Das Speichern von Daten in einer Datenbank
ist ideal für sich wiederholende oder strukturierte Daten,
wie Kontaktinformationen. Auf dieser Seite wird davon ausgegangen, dass Sie
SQL-Datenbanken im Allgemeinen
SQLite-Datenbanken unter Android Die APIs, die Sie zum Verwenden einer Datenbank benötigen
für Android sind im Paket android.database.sqlite
verfügbar.
Achtung:Diese APIs sind zwar leistungsstark, entsprechen aber relativ wenig und erfordern viel Zeit und Aufwand:
- Es gibt keine Prüfung der Kompilierungszeit von SQL-Rohabfragen. Da Ihre Daten Diagrammänderungen müssen Sie die betroffenen SQL-Abfragen manuell aktualisieren. Dieses kann zeitaufwendig und fehleranfällig sein.
- Sie müssen viel Boilerplate-Code verwenden, um zwischen SQL-Abfragen zu konvertieren. und Datenobjekte.
Aus diesen Gründen empfehlen wir dringend die Verwendung des Raumpersistenzbibliothek als Abstraktionsebene für den Zugriff auf Informationen in der SQLite Ihrer App Datenbanken.
Schema definieren und Vertrag
Eines der Hauptprinzipien von SQL-Datenbanken ist das Schema: ein Deklaration der Datenbankstruktur. Das Schema wird in der SQL- Anweisungen, mit denen Sie Ihre Datenbank erstellen. Vielleicht finden Sie es hilfreich, eine Companion-Klasse erstellen, auch als Contract-Klasse bezeichnet, die explizit angibt, das Layout Ihres Schemas systematisch und selbstdokumentierend darzustellen.
Eine Vertragsklasse ist ein Container für Konstanten, die Namen für URIs definieren, Tabellen und Spalten. Mit der Kontraktionsklasse können Sie dieselben Konstanten für alle anderen Klassen im selben Paket. So können Sie eine Spalte und im gesamten Code verwenden.
Eine gute Methode zur Organisation einer Vertragsklasse besteht darin, für die gesamte Datenbank auf der Stammebene der Klasse. Erstellen Sie dann eine innere Klasse für jede Tabelle. Jede innere Klasse listet die Spalten der entsprechenden Tabelle auf.
Hinweis: Wenn Sie BaseColumns
implementieren,
kann Ihre innere Klasse eine primäre
Schlüsselfeld namens _ID
, das von einigen Android-Klassen wie CursorAdapter
erwartet wird. Sie ist nicht erforderlich, kann aber Ihrer Datenbank helfen.
mit dem Android-Framework harmonieren.
Im folgenden Vertrag werden beispielsweise die Tabellennamen und Spaltennamen für eine einzelne Tabelle, die einen RSS-Feed darstellt:
Kotlin
object FeedReaderContract { // Table contents are grouped together in an anonymous object. object FeedEntry : BaseColumns { const val TABLE_NAME = "entry" const val COLUMN_NAME_TITLE = "title" const val COLUMN_NAME_SUBTITLE = "subtitle" } }
Java
public final class FeedReaderContract { // To prevent someone from accidentally instantiating the contract class, // make the constructor private. private FeedReaderContract() {} /* Inner class that defines the table contents */ public static class FeedEntry implements BaseColumns { public static final String TABLE_NAME = "entry"; public static final String COLUMN_NAME_TITLE = "title"; public static final String COLUMN_NAME_SUBTITLE = "subtitle"; } }
Datenbank mit einem SQL-Hilfsprogramm erstellen
Nachdem Sie das Aussehen Ihrer Datenbank definiert haben, sollten Sie Methoden implementieren. die die Datenbank und die Tabellen erstellen und verwalten. Hier sind einige typische Anweisungen zum Erstellen und Löschen einer Tabelle:
Kotlin
private const val SQL_CREATE_ENTRIES = "CREATE TABLE ${FeedEntry.TABLE_NAME} (" + "${BaseColumns._ID} INTEGER PRIMARY KEY," + "${FeedEntry.COLUMN_NAME_TITLE} TEXT," + "${FeedEntry.COLUMN_NAME_SUBTITLE} TEXT)" private const val SQL_DELETE_ENTRIES = "DROP TABLE IF EXISTS ${FeedEntry.TABLE_NAME}"
Java
private static final String SQL_CREATE_ENTRIES = "CREATE TABLE " + FeedEntry.TABLE_NAME + " (" + FeedEntry._ID + " INTEGER PRIMARY KEY," + FeedEntry.COLUMN_NAME_TITLE + " TEXT," + FeedEntry.COLUMN_NAME_SUBTITLE + " TEXT)"; private static final String SQL_DELETE_ENTRIES = "DROP TABLE IF EXISTS " + FeedEntry.TABLE_NAME;
Genau wie Dateien, die Sie auf dem internen Speicher Ihres Geräts Speicher speichern, speichert Android die Datenbank im privaten Ordner Ihrer App. Ihre Daten da sich dieser Bereich standardmäßig für andere Apps oder den Nutzer zugänglich sind.
Die Klasse SQLiteOpenHelper
enthält eine nützliche
eine Reihe von APIs zum Verwalten Ihrer Datenbank.
Wenn Sie diese Klasse verwenden, um Verweise auf Ihre Datenbank zu erhalten,
führt die potenziell
lang andauernde Vorgänge zum Erstellen und Aktualisieren der Datenbank
und nicht beim Start der App. Sie müssen lediglich
getWritableDatabase()
oder
getReadableDatabase()
.
Hinweis:Da sie lange andauern können,
sollten Sie getWritableDatabase()
oder getReadableDatabase()
in einem Hintergrundthread aufrufen.
Weitere Informationen finden Sie unter Threading unter Android.
Erstellen Sie zur Verwendung von SQLiteOpenHelper
eine abgeleitete Klasse, die
überschreibt onCreate()
und
onUpgrade()
. Sie können
auch die Funktion
onDowngrade()
oder
onOpen()
-Methoden,
aber sie sind nicht erforderlich.
Hier sehen Sie z. B. eine Implementierung von SQLiteOpenHelper
, die
verwendet einige der oben aufgeführten Befehle:
Kotlin
class FeedReaderDbHelper(context: Context) : SQLiteOpenHelper(context, DATABASE_NAME, null, DATABASE_VERSION) { override fun onCreate(db: SQLiteDatabase) { db.execSQL(SQL_CREATE_ENTRIES) } override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) { // This database is only a cache for online data, so its upgrade policy is // to simply to discard the data and start over db.execSQL(SQL_DELETE_ENTRIES) onCreate(db) } override fun onDowngrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) { onUpgrade(db, oldVersion, newVersion) } companion object { // If you change the database schema, you must increment the database version. const val DATABASE_VERSION = 1 const val DATABASE_NAME = "FeedReader.db" } }
Java
public class FeedReaderDbHelper extends SQLiteOpenHelper { // If you change the database schema, you must increment the database version. public static final int DATABASE_VERSION = 1; public static final String DATABASE_NAME = "FeedReader.db"; public FeedReaderDbHelper(Context context) { super(context, DATABASE_NAME, null, DATABASE_VERSION); } public void onCreate(SQLiteDatabase db) { db.execSQL(SQL_CREATE_ENTRIES); } public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { // This database is only a cache for online data, so its upgrade policy is // to simply to discard the data and start over db.execSQL(SQL_DELETE_ENTRIES); onCreate(db); } public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) { onUpgrade(db, oldVersion, newVersion); } }
Instanziieren Sie die abgeleitete Klasse von, um auf Ihre Datenbank zuzugreifen
SQLiteOpenHelper
:
Kotlin
val dbHelper = FeedReaderDbHelper(context)
Java
FeedReaderDbHelper dbHelper = new FeedReaderDbHelper(getContext());
Informationen in einer Datenbank speichern
Fügen Sie Daten in die Datenbank ein, indem Sie ein ContentValues
-Objekt übergeben.
an die Methode insert()
übergeben:
Kotlin
// Gets the data repository in write mode val db = dbHelper.writableDatabase // Create a new map of values, where column names are the keys val values = ContentValues().apply { put(FeedEntry.COLUMN_NAME_TITLE, title) put(FeedEntry.COLUMN_NAME_SUBTITLE, subtitle) } // Insert the new row, returning the primary key value of the new row val newRowId = db?.insert(FeedEntry.TABLE_NAME, null, values)
Java
// Gets the data repository in write mode SQLiteDatabase db = dbHelper.getWritableDatabase(); // Create a new map of values, where column names are the keys ContentValues values = new ContentValues(); values.put(FeedEntry.COLUMN_NAME_TITLE, title); values.put(FeedEntry.COLUMN_NAME_SUBTITLE, subtitle); // Insert the new row, returning the primary key value of the new row long newRowId = db.insert(FeedEntry.TABLE_NAME, null, values);
Das erste Argument für insert()
ist einfach der Tabellenname.
Das zweite Argument teilt dem Framework mit, was zu tun ist, wenn das Framework
ContentValues
ist leer. Sie haben also
put
beliebige Werte).
Wenn Sie den Namen einer Spalte angeben, fügt das Framework eine Zeile ein und legt die
dieser Spalte auf null setzen. Wenn Sie null
angeben, wie in diesem
Codebeispiel enthält, fügt das Framework keine Zeile ein, wenn keine Werte vorhanden sind.
Die Methode insert()
gibt die ID für die
neu erstellte Zeile. Andernfalls wird -1 zurückgegeben, wenn beim Einfügen der Daten ein Fehler aufgetreten ist. Das kann passieren,
wenn es einen Konflikt mit bereits vorhandenen Daten in der Datenbank gibt.
Informationen aus einer Datenbank lesen
Verwenden Sie zum Lesen aus einer Datenbank die Methode query()
und übergeben Sie Ihre Auswahlkriterien und die gewünschten Spalten.
Die Methode kombiniert Elemente von insert()
.
und update()
, mit Ausnahme der Spaltenliste
definiert die Daten, die Sie abrufen möchten (die "Projektion"), nicht die einzufügenden Daten. Die Ergebnisse
der Abfrage werden in einem Cursor
-Objekt zurückgegeben.
Kotlin
val db = dbHelper.readableDatabase // Define a projection that specifies which columns from the database // you will actually use after this query. val projection = arrayOf(BaseColumns._ID, FeedEntry.COLUMN_NAME_TITLE, FeedEntry.COLUMN_NAME_SUBTITLE) // Filter results WHERE "title" = 'My Title' val selection = "${FeedEntry.COLUMN_NAME_TITLE} = ?" val selectionArgs = arrayOf("My Title") // How you want the results sorted in the resulting Cursor val sortOrder = "${FeedEntry.COLUMN_NAME_SUBTITLE} DESC" val cursor = db.query( FeedEntry.TABLE_NAME, // The table to query projection, // The array of columns to return (pass null to get all) selection, // The columns for the WHERE clause selectionArgs, // The values for the WHERE clause null, // don't group the rows null, // don't filter by row groups sortOrder // The sort order )
Java
SQLiteDatabase db = dbHelper.getReadableDatabase(); // Define a projection that specifies which columns from the database // you will actually use after this query. String[] projection = { BaseColumns._ID, FeedEntry.COLUMN_NAME_TITLE, FeedEntry.COLUMN_NAME_SUBTITLE }; // Filter results WHERE "title" = 'My Title' String selection = FeedEntry.COLUMN_NAME_TITLE + " = ?"; String[] selectionArgs = { "My Title" }; // How you want the results sorted in the resulting Cursor String sortOrder = FeedEntry.COLUMN_NAME_SUBTITLE + " DESC"; Cursor cursor = db.query( FeedEntry.TABLE_NAME, // The table to query projection, // The array of columns to return (pass null to get all) selection, // The columns for the WHERE clause selectionArgs, // The values for the WHERE clause null, // don't group the rows null, // don't filter by row groups sortOrder // The sort order );
Das dritte und vierte Argument (selection
und selectionArgs
) sind
kombiniert, um eine WHERE-Klausel zu erstellen. Weil die Argumente getrennt von der Auswahl bereitgestellt werden
werden sie vor der Zusammenführung mit Escapezeichen versehen. Dadurch werden Ihre Auswahlanweisungen gegen SQL immun
Injektion. Weitere Informationen zu allen Argumenten finden Sie in der
Referenz zu query()
.
Wenn du dir eine Zeile im Cursor ansehen möchtest, verwende eine der Cursor
-Bewegungen
, die Sie immer aufrufen müssen, bevor Sie mit dem Lesen von Werten beginnen. Da der Cursor bei
Position -1 wird durch das Aufrufen von moveToNext()
die „Leseposition“ festgelegt. am
ersten Eintrag in den Ergebnissen und gibt zurück, ob der Cursor bereits nach dem letzten Eintrag in
in der Ergebnismenge. Für jede Zeile können Sie den Wert einer Spalte lesen, indem Sie einen der
Cursor
Get-Methoden wie getString()
oder getLong()
. Für jede der get-Methoden,
müssen Sie die Indexposition der gewünschten Spalte übergeben. Diese erhalten Sie durch Aufrufen
getColumnIndex()
oder
getColumnIndexOrThrow()
. Nach Abschluss
Ergebnisse iterieren, rufen Sie close()
am Cursor auf
um seine Ressourcen freizugeben.
Das folgende Beispiel zeigt, wie alle Element-IDs abgerufen werden, die in einem Cursor gespeichert sind
und fügen sie einer Liste hinzu:
Kotlin
val itemIds = mutableListOf<Long>() with(cursor) { while (moveToNext()) { val itemId = getLong(getColumnIndexOrThrow(BaseColumns._ID)) itemIds.add(itemId) } } cursor.close()
Java
List itemIds = new ArrayList<>(); while(cursor.moveToNext()) { long itemId = cursor.getLong( cursor.getColumnIndexOrThrow(FeedEntry._ID)); itemIds.add(itemId); } cursor.close();
Informationen aus einer Datenbank löschen
Um Zeilen aus einer Tabelle zu löschen, müssen Sie Auswahlkriterien angeben,
Identifizieren Sie die Zeilen für die Methode delete()
. Die
funktioniert genauso wie die Auswahlargumente
query()
-Methode. Sie teilt die
Auswahlspezifikation in eine Auswahlklausel und Auswahlargumente. Die
definiert die zu betrachtenden Spalten und ermöglicht Ihnen, Spalten zu kombinieren,
Tests durchführen. Die Argumente sind Werte, gegen die geprüft werden soll und die an die Klausel gebunden sind.
Da das Ergebnis nicht wie bei einer regulären SQL-Anweisung gehandhabt wird,
immun gegen SQL-Injection.
Kotlin
// Define 'where' part of query. val selection = "${FeedEntry.COLUMN_NAME_TITLE} LIKE ?" // Specify arguments in placeholder order. val selectionArgs = arrayOf("MyTitle") // Issue SQL statement. val deletedRows = db.delete(FeedEntry.TABLE_NAME, selection, selectionArgs)
Java
// Define 'where' part of query. String selection = FeedEntry.COLUMN_NAME_TITLE + " LIKE ?"; // Specify arguments in placeholder order. String[] selectionArgs = { "MyTitle" }; // Issue SQL statement. int deletedRows = db.delete(FeedEntry.TABLE_NAME, selection, selectionArgs);
Der Rückgabewert für die Methode delete()
gibt die Anzahl der Zeilen an, die aus der Datenbank gelöscht wurden.
Datenbank aktualisieren
Wenn Sie eine Teilmenge der Datenbankwerte ändern müssen, verwenden Sie die Methode
update()
-Methode.
Beim Aktualisieren der Tabelle wird die ContentValues
-Syntax von
insert()
mit der Syntax WHERE
von delete()
.
Kotlin
val db = dbHelper.writableDatabase // New value for one column val title = "MyNewTitle" val values = ContentValues().apply { put(FeedEntry.COLUMN_NAME_TITLE, title) } // Which row to update, based on the title val selection = "${FeedEntry.COLUMN_NAME_TITLE} LIKE ?" val selectionArgs = arrayOf("MyOldTitle") val count = db.update( FeedEntry.TABLE_NAME, values, selection, selectionArgs)
Java
SQLiteDatabase db = dbHelper.getWritableDatabase(); // New value for one column String title = "MyNewTitle"; ContentValues values = new ContentValues(); values.put(FeedEntry.COLUMN_NAME_TITLE, title); // Which row to update, based on the title String selection = FeedEntry.COLUMN_NAME_TITLE + " LIKE ?"; String[] selectionArgs = { "MyOldTitle" }; int count = db.update( FeedReaderDbHelper.FeedEntry.TABLE_NAME, values, selection, selectionArgs);
Der Rückgabewert der Methode update()
ist
Anzahl der betroffenen Zeilen in der Datenbank.
Datenbankverbindung wird bestehen bleiben
Seit getWritableDatabase()
und getReadableDatabase()
sind
wenn die Datenbank geschlossen ist, sollten Sie Ihre Datenbankverbindung
solange Sie darauf zugreifen müssen. In der Regel ist es optimal, die Datenbank zu schließen
in der onDestroy()
der aufrufenden Aktivität.
Kotlin
override fun onDestroy() { dbHelper.close() super.onDestroy() }
Java
@Override protected void onDestroy() { dbHelper.close(); super.onDestroy(); }
Datenbankfehler beheben
Das Android SDK enthält ein sqlite3
-Shell-Tool, mit dem du
Inhaltsverzeichnis, SQL-Befehle und weitere nützliche Funktionen auf SQLite ausführen.
Datenbanken. Weitere Informationen finden Sie unter Shell-Befehle ausführen.