如何使用SQLiteOpenHelper

都知道在Android中SQLiteOpenHelper是用来创建和升级数据库,参考
$ANDROID_SDK_HOME/docs/reference/android/database/sqlite/SQLiteOpenHelper.html

软件发布出去了,用户已经安装使用了,但是随着软件的升级,数据库结构做了些改动,我们不希望用户把应用卸载了再装(这样会丢失应用所有的数据),我们希望在数据库总体结构和已有数据不变的情况下做些小的改动,比如新增一个字段或索引,新增加一个表等等,那么这个时候我们就要用到这个类了

常用的也就是onCreate和onUpgrade这两个方法,在使用的时候这两个方法都需要重写,里面实现自己的逻辑

我们先列出一个场景:
假设第一版程序发布出去,First Public Version,代码如下

1 @Override
2 public void onCreate(SQLiteDatabase db) {
3     bootstrapDB(db);
4 }
5  
6 @Override
7 public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
8 }

onUpgrade里面没有代码,第一版出去没有需要更新的,bootstrapDB方法就是些DDL和数据初始化操作等等

之后过了一段时间,新的程序发布(其中数据库结构做了些变化),这个时候已经开始使用第一版程序的用户就需要升级,我们不希望他已经存在的数据被破坏,那么我们发布出去的新的版本中代码该怎么写呢?
直接看代码,这些代码都是从Android自带的应用中抽取出来的,做了些具体业务上的简化,主要是阐述清楚用法

1 @Override
2 public void onCreate(SQLiteDatabase db) {
3     bootstrapDB(db); // 这个方法里面都是最新版的初始化方法
4 }
5  
6 @Override
7 public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
8     Log.i(TAG, "Upgrading DB from version " + oldVersion + " to "
9             + newVersion);
10     if (oldVersion == 1) {
11         upgradeToVersion2(db);
12         oldVersion += 1;
13     }
14     Log.v("do upgrade", "我更新了。。。");
15 }

这样如果后来又有新的程序发布,那么这两个方法会变成类似这个样子

1 @Override
2 public void onCreate(SQLiteDatabase db) {
3     bootstrapDB(db); // 这个方法里面始终都是最新版的初始化方法
4 }
5  
6 @Override
7 public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
8     Log.i(TAG, "Upgrading DB from version " + oldVersion + " to "
9             + newVersion);
10     if (oldVersion == 1) {
11         upgradeToVersion2(db);
12         oldVersion += 1;
13     }
14     if (oldVersion == 2) {
15         upgradeToVersion3(db);
16         oldVersion += 1;
17     }
18     // 这是一种逐级更新的方式
19             // 对于目前使用的还是第一版的用户而言,会先执行完upgradeToVersion2再执行upgradeToVersion3
20             // 对于目前使用的还是第二版的用户而言,会执行upgradeToVersion3
21     Log.v("do upgrade", "我更新了。。。");
22 }

这样也许就能看的很清楚这个类的意图和用法了,后面版本一直增加的话,我们就一直这样写就好,保证全新的用户和升级的用户都能正常使用,那么我们如何来调用呢
一般我们会有个构造方法,有个参数就是数据库的版本,比如下面这两个构造方法

1 public MyDatabaseHelper(Context context, String name, CursorFactory factory,
2         int version) {
3     super(context, name, factory, version);
4 }
5  
6 public MyDatabaseHelper(Context context, int version) {
7     super(context, NAME, null, version);
8 }

采用如下方式调用

1 helper = new MyDatabaseHelper(context, 10); // 这个数据库版本号会随着程序的每次发布而变化,是表示每次需要更新到的版本号,也就是最新的版本号
2 sqlite = helper.getWritableDatabase();

其实更好理解这个用法就是读SQLiteOpenHelper.getWritableDatabase这个方法,里面有段代码

1 int version = db.getVersion();
2 if (version != mNewVersion) {
3     db.beginTransaction();
4     try {
5         if (version == 0) {
6             onCreate(db);
7         } else {
8             onUpgrade(db, version, mNewVersion);
9         }
10         db.setVersion(mNewVersion);
11         db.setTransactionSuccessful();
12     } finally {
13         db.endTransaction();
14     }
15 }

另外,看看set/get Version就知道数据库版本标记是通过PRAGMA user_version;这个命令来完成的,你也可以用sqlite3之类的工具把数据库文件打开,然后执行PRAGMA user_version查看或者设置版本值

如下是完整的两个代码,是目前在使用的

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
package org . xkit . android . demo ;
 
import java.util.ArrayList ;
import java.util.HashMap ;
import java.util.List ;
import java.util.Map ;
 
import android.content.Context ;
import android.database.Cursor ;
import android.database.sqlite.SQLiteDatabase ;
import android.util.Log ;
 
public class DBAdapter {
private Context context ;
private SQLiteDatabase sqlite ;
 
private MyDatabaseHelper helper ;
 
public DBAdapter ( Context c ) {
this . context = c ;
}
 
public void open () {
helper = new MyDatabaseHelper ( context , 10 );
sqlite = helper . getWritableDatabase ();
}
 
public void execSQL ( String sql ) {
Log . i ( "sql execute" , sql );
sqlite . execSQL ( sql );
}
 
public Cursor getResultSet ( String tableName , String condition ,
Object [] fields ) {
StringBuffer sb = new StringBuffer ();
String allFields = new String ();
if ( fields == null ) {
allFields = "*" ;
} else {
for ( int i = 0 ; i < fields . length ; i ++) {
allFields += fields [ i ]. toString () + "," ;
}
allFields = allFields . substring ( 0 , allFields . length () - 1 );
}
sb . append ( "select " ). append ( allFields ). append ( " from " ). append (
tableName ). append ( " where " ). append ( condition );
Log . i ( "sqlquery" , sb . toString ());
return sqlite . rawQuery ( sb . toString (), null );
}
 
public Cursor getResultSet ( String sql ) {
Log . i ( "sql query" , sql );
return sqlite . rawQuery ( sql , null );
}
 
public List < Map < String , String >> getResultSet ( String sql , int pageSize ) {
Log . i ( "sql query" , sql );
Cursor cursor = sqlite . rawQuery ( sql , null );
int count = cursor . getCount ();
int columnCount = cursor . getColumnCount ();
Log . d ( "Column Count" , "" + columnCount );
List < Map < String , String >> list = new ArrayList < Map < String , String >>(
count );
Map < String , String > entity = new HashMap < String , String >( columnCount );
for ( cursor . moveToFirst (); ! cursor . isAfterLast (); cursor . moveToNext ()) {
// 找出一共有多少列
for ( int i = 0 ; i < columnCount ; i ++) {
Log . d ( "Column Found" , cursor . getColumnName ( i ) + " : "
+ cursor . getString ( i ));
entity . put ( cursor . getColumnName ( i ), cursor . getString ( i ));
}
list . add ( entity );
}
cursor . close ();
entity = null ;
return list ;
}
 
public void close () {
// 关闭我们打开的数据库
throw new RuntimeException ( "Only for Stub!" );
}
}
view raw DBAdapter.java This Gist brought to you by  GitHub.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
package org . xkit . android . demo ;
 
import android.content.Context ;
import android.database.sqlite.SQLiteDatabase ;
import android.database.sqlite.SQLiteOpenHelper ;
import android.database.sqlite.SQLiteDatabase.CursorFactory ;
import android.util.Log ;
 
public class MyDatabaseHelper extends SQLiteOpenHelper {
 
private static final String TAG = "MyDatabaseHelper" ;
 
public static final String NAME = "lucane.db" ;
 
public MyDatabaseHelper ( Context context , String name , CursorFactory factory ,
int version ) {
super ( context , name , factory , version );
}
 
public MyDatabaseHelper ( Context context , int version ) {
super ( context , NAME , null , version );
}
 
@Override
public void onCreate ( SQLiteDatabase db ) {
bootstrapDB ( db );
}
 
@Override
public void onUpgrade ( SQLiteDatabase db , int oldVersion , int newVersion ) {
Log . i ( TAG , "Upgrading DB from version " + oldVersion + " to "
+ newVersion );
if ( oldVersion < 8 ) {
// 如果版本太小,就直接删除,然后创建
// 所以bootstrapDB应该是最新的SQL初始化语句
dropTables ( db );
onCreate ( db );
return ;
}
 
if ( oldVersion == 8 ) {
upgradeToVersion9 ( db );
oldVersion += 1 ;
}
 
if ( oldVersion == 9 ) {
upgradeToVersion10 ( db );
oldVersion += 1 ;
}
 
// 这是一种逐级更新的方式
Log . v ( "do upgrade" , "我更新了。。。" );
}
 
private void bootstrapDB ( SQLiteDatabase db ) {
Log . i ( TAG , "Bootstrapping database" );
db
. execSQL ( "CREATE TABLE person (personid integer primary key autoincrement,name varchar(20),age integer )" );
}
 
private void dropTables ( SQLiteDatabase db ) {
db . execSQL ( "DROP TABLE IF EXISTS person;" );
}
 
// PATCH方法开始
 
static void upgradeToVersion10 ( SQLiteDatabase db ) {
db . execSQL ( "CREATE INDEX idx_person_name_gender ON person (" + "name"
+ ", " + "gender" + ");" );
}
 
static void upgradeToVersion9 ( SQLiteDatabase db ) {
db . execSQL ( "ALTER TABLE "
+ "person ADD COLUMN gender INTEGER NOT NULL DEFAULT 1;" );
}
 
// PATCH方法结束
}

猜你喜欢

转载自liushilang.iteye.com/blog/1902681