基本用法
继承 SQLiteOpenHelper 类, 并实现重写构造方法:
public SQLiteOpenHelper(Context context, String name, CursorFactory factory, int version)
参数依次是: 上下文, 数据库名称呢个, 游标工厂, 数据库版本号.
使用该构造方法创建 helper 对象, 用于创建, 打开, 管理数据库. 创建或打开数据库需要调用下面两个方法中的一个.
SQLiteDatabase getWritableDatabase()
SQLiteDatabase getReadableDatabase()
重写 onCreate() 方法
void onCreate(SQLiteDatabase db);
这个方法会在数据库第一次被创建出来的时候调用. 一般在这里进行数据库表的初始化.
重写 onUpgrade() 方法
void onUpgrade(SQLiteDatabase db,int oldVersion,int newVersion);
这个方法会在数据库需要升级的时候调用. 可以在这个方法中添加或删除数据库表, 或者重命名表, 添加或删除数据列. 这个方法执行在事务内, 如果执行过程中出现了异常, 所有的改动都会自动回滚.
获取数据库对象
通过前面所列的两个方法 getWritableDatabase() 或 getReadableDatabase() 获取数据库对象SQLiteDatabase. 关于这两个方法的区别, 网上有一段描述:
getWritableDatabase() 方法以读写方式打开数据库,一旦数据库的磁盘空间满了,数据库就只能读而不能写,此时getWritableDatabase() 方法就会出错。 getReadableDatabase()方法则是先以读写方式打开数据库,如果数据库的磁盘空间满了,就会打开失败,当打开失败后会继续尝试以只读方式打开数据库。如果该问题成功解决,则只读数据库对象就会关闭
操作数据库中的数据
得到数据库对象(设对应变量名为 db)后就可以进行常规的数据库操作了, 有两种方式可以选择:
- 调用 db 的 execSQL()[增删改] 或 rawQuery()[查] 方法, 传入对应的 sql 语句来执行相关操作.
- 调用 db 中封装好的方法(insert, delete, update, query), 传入相应的参数来执行相关操作.
方法一使用sql语句, 比较灵活, 资源占用小, 可以实现表的级联查询. 方法二使用了现成的API, 比较方便, 可以避免sql语句拼写错误等, 不过看源码可以知道, 其内部还是将传入的参数拼装成sql语句后执行, 因此资源开销比较大. 不过方法二有返回值, 可以方便地知道是否执行成功.
具体实现方式如下:
sql语句( info 是表名 ):
- 添加 insert into info (name,phone) values (‘zhangsan’,’110’)
- 删除 delete from info where name=’zhangsan’
- 修改 update info set phone =’999’ where name =’zhangsan’
- 查询 select * from info where name=’zhangsan’
使用现有API
- 添加:
ContentValues values = new ContentValues();
values.put ("name",name);
values.put("phone",phone);
long result = db.insert("info", null, values);//成功返回新行行号,失败返回-1
- 删除:
int db.delete(String table, String whereClause, String[] whereArgs)
- 修改:
int update (table, values, whereClause, whereArgs)
- 查询:
public Cursor query (String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy)
if(cursor.moveToNext()) phone = cursor.getString(0);
部分源码
SQLiteOpenHelper
public SQLiteDatabase getWritableDatabase() {
synchronized (this) {
return getDatabaseLocked(true);
}
}
public SQLiteDatabase getReadableDatabase() {
synchronized (this) {
return getDatabaseLocked(false);
}
}
可见两种获取数据库对象的方法都调用了同一个方法, 不过传递了不同的参数. 下面看看调用的这个方法:
private SQLiteDatabase getDatabaseLocked(boolean writable) {
if (mDatabase != null) {
if (!mDatabase.isOpen()) {
// 用户调用了mDatabase.close().
mDatabase = null;
} else if (!writable || !mDatabase.isReadOnly()) {
// 数据库已被打开.
return mDatabase;
}
}
if (mIsInitializing) {
throw new IllegalStateException("getDatabase called recursively");
}
SQLiteDatabase db = mDatabase;
try {
mIsInitializing = true;
if (db != null) {
if (writable && db.isReadOnly()) {
db.reopenReadWrite();
}
} else if (mName == null) {
//mName是构造方法中传入的数据库的名称, 值为null时表示创建内存数据库,即应用关闭时数据库也会被清理
db = SQLiteDatabase.create(null);
} else {
try {
if (DEBUG_STRICT_READONLY && !writable) {
final String path = mContext.getDatabasePath(mName).getPath();
db = SQLiteDatabase.openDatabase(path, mFactory,
SQLiteDatabase.OPEN_READONLY, mErrorHandler);
} else {
db = mContext.openOrCreateDatabase(mName, mEnableWriteAheadLogging ?
Context.MODE_ENABLE_WRITE_AHEAD_LOGGING : 0,
mFactory, mErrorHandler);
}
} catch (SQLiteException ex) {
if (writable) {
throw ex;
}
Log.e(TAG, "Couldn't open " + mName
+ " for writing (will try read-only):", ex);
final String path = mContext.getDatabasePath(mName).getPath();
db = SQLiteDatabase.openDatabase(path, mFactory,
SQLiteDatabase.OPEN_READONLY, mErrorHandler);
}
}
onConfigure(db);
//获取当前数据库的版本号
final int version = db.getVersion();
if (version != mNewVersion) {
if (db.isReadOnly()) {
throw new SQLiteException("Can't upgrade read-only database from version " +
db.getVersion() + " to " + mNewVersion + ": " + mName);
}
db.beginTransaction();
try {
if (version == 0) {
//说明数据库是第一次被创建, 调用onCreate()方法
onCreate(db);
} else {
if (version > mNewVersion) {
//当前版本比较高的话, 调用降级方法
onDowngrade(db, version, mNewVersion);
} else {
//当前版本较低的话, 调用升级方法
onUpgrade(db, version, mNewVersion);
}
}
//更新当前数据库的版本号
db.setVersion(mNewVersion);
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
}
onOpen(db);
if (db.isReadOnly()) {
Log.w(TAG, "Opened " + mName + " in read-only mode");
}
mDatabase = db;
return db;
} finally {
mIsInitializing = false;
if (db != null && db != mDatabase) {
db.close();
}
}
}