SQLiteOpenHelper Verständnisfrage / Online Update

  • Antworten:6
Bluna Teddy
  • Forum-Beiträge: 4

21.06.2012, 16:49:35 via Website

Hi,

ich bin noch neu in der Android Entwicklung (3 Monate?). Und ich habe schon viel gelesen zu dem SQLiteOpenHelper aber ich habe scheinbar noch ein verständnis Problem.

- Wann genau wird die onUpgrade aufgerufen?
- brauche ich transactions, oder achtet da die Datenbank bei onUpgrade selbst drauf?

Ich hab mit db.setversion(2) die Version auf 2 erhöht, aber es passierte weiter nichts. Beim restart der App kommt dann der Fehler, dass er nicht downgraden kann von Version 2 auf 1.
Anbei mein Code:

1public class DatabaseHelper extends SQLiteOpenHelper
2{
3 private Context context;
4 public DatabaseHelper(Context context)
5 {
6 super(context, context.getResources().getString(R.string.DBName), null,
7 Integer.parseInt(context.getResources().getString(
8 R.string.DBVersion)));
9 this.context = context;
10 }
11 @Override
12 public void onCreate(SQLiteDatabase db)
13 {
14 try
15 {
16 fillDatabse(db, "db.sql");
17 }
18 catch (Exception e)
19 {
20 // TODO Auto-generated catch block
21 e.printStackTrace();
22 }
23 }
24 @Override
25 public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
26 {
27 // context.deleteDatabase(context.getResources().getString(R.string.DBName));
28 Log.i("DatabaseHelper", "onUpgrade aufgerufen");
29 try
30 {
31 db.beginTransaction();
32 db.execSQL("DROP TABLE IF EXISTS produkt_has_kriterium, kriterium_has_wertemoeglichkeit, wertemoeglichkeit, kriterium, typKriterium, produkt");
33 fillDatabse(db, "dpProd.sql");
34 db.setTransactionSuccessful();
35 }
36 catch (Exception e)
37 {
38 db.endTransaction();
39 }
40 finally
41 {
42 db.endTransaction();
43 }
44 }
45
46 private void fillDatabse(SQLiteDatabase db, String file) throws Exception
47 {
48 for (String sql : context.getResources().getStringArray(
49 R.array.DBCreate))
50 {
51 db.execSQL(sql);
52 }
53 FileReader fReader = new FileReader(file);
54 BufferedReader bReader = new BufferedReader(fReader);
55 String row;
56 while ((row = bReader.readLine()) != null)
57 {
58 db.execSQL(row);
59 }
60 }
61}

Antworten
Bluna Teddy
  • Forum-Beiträge: 4

21.06.2012, 17:43:39 via Website

Also bis auf die frage, ob ich transactions brauche ist alles gelöst.

Es klappt nun, keine Ahnung warum er nun in den Code reinspringt. Aber ein Fehler noch im Code, die DROP Statements müssen einzeln sein.
Kommata mag SQLite scheinbar nicht. ;)

Antworten
San Blarnoi
  • Forum-Beiträge: 2.545

21.06.2012, 19:40:45 via Website

Zwingend erforderlich sind die nicht, aber zumindest am PC ist das Einschließen vieler Statements in eine Transaction um Welten schneller als die direkte Ausführung.

Antworten
Gelöschter Account
  • Forum-Beiträge: 694

21.06.2012, 20:20:00 via Website

Transactions haben mehrere ganz wichtige Funktionen. Eine davon ist zum Beispiel die Konsistenz der Daten zu gewährleisten. Als alter DB2 Admin kann ich nur jedem dringend empfehlen sich mal damit zu beschäftigen - auch unter Android.

Was die angesprochene Performance angeht. Transaktionen können, müssen aber nicht unbedingt, Einfluss auf die Performance nehmen. Das hängt von vielen Faktoren ab (zum Beispiel Anzahl, Art und Belegung der Indexe).

Was aber auf jeden Fall Auswirkung auf die Performance hat sind Transaktionen im Zusammenspiel mit Prepared Statements.

Als meine App GaCoMo vor ein paar Jahren rauskam hatte ich - warum auch immer - an genau einer kritischen Stelle weder Prepared Statements noch Transaktionen verwendet. In der kritischen Stelle werden Dateien im TCX Format geparsed und in die Datenbank eingetragen. Diese Dateien enthalten zum Beispiel die Koordinaten eines Sportlers bei einem 180km Fahrradrennen oder eines 42km Marathonlaufes. Da kommen ein paar tausend Rows in einer Datei zusammen. Zwischen der ersten Version und der kurz darauf erschienenen 1.0.1 der App lag eine Performancesteigerung von 1000% - kein Witz.

Meine Empfehlung: Wenn Ihr in Euren Apps mehrfach und immer wieder während eines App Laufes die selben Statements feuert - nehmt Prepared Statements in Eure Apps auf.


Im Übrigen kann ich die immer wieder verbreitete Methode des onUpgrade() nicht verstehen. Was soll der DROP? Sorry, das ist Müll. Man kann auch eine Datenbank um Felder erweitern. Wenn eine App mal draußen ist geht es sowieso nicht anders.

1@Override
2 public void onUpgrade(SQLiteDatabase sqliteDatabase, int oldVersion, int newVersion) {
3 this.sqliteDatabase = sqliteDatabase;
4
5 switch (newVersion) {
6 case DATENBANK_VERSION:
7 if (oldVersion == 1) {
8 upgradeFrom1To2();
9 }
10
11 if (oldVersion <= 2) {
12 upgradeFrom2To3();
13 }
14
15 if (oldVersion <= 3) {
16 upgradeFrom3To4();
17 }
18...

Das geht sicher geschickter - habe mir aber noch nicht die Zeit genommen das mal zu optimieren.

1private void upgradeFrom17To18() {
2 sqliteDatabase.execSQL("alter table aufwendung add column kilometerstand integer");
3 }

Antworten
Bluna Teddy
  • Forum-Beiträge: 4

21.06.2012, 22:24:56 via Website

Wow. Danke für die ausführliche Antwort! :-) Ich denke für den Fall den du schilderst, ist deine Variante sicher besser. Aber es gibt sicher auch use cases, bei denen ein löschen der Tabellen die bessere Vorgehensweise ist. Bspw. wenn die DB öfter aktualisiert wird als die App selbst. :-)

Antworten
Rafael K.
  • Forum-Beiträge: 2.359

22.06.2012, 08:53:31 via Website

Der Gag an der onUpgrade Methode ist doch grade, dass man die Datenstruktur erweitern kann und die Daten erhalten bleiben.
Warum sollte man diesen Vorteil durch einen DROP unterminieren?
Ist doch auch für den User angenehm, wenn nach einem Update MIT Änderung der Datenstruktur seine Daten noch da sind.

Wenn ich mir vorstelle ich würde in meiner Kleinanzeigen App dem User alle seine mühsam angelegten Vorlagen löschen, nur weil ich ein weiteres Feld in der DB brauche...was da los wär :cold:

Antworten