用习惯了三方数据库,原生的 SQLite 数据库是不是有一些陌生了?而且什么时候 create,什么时候需要 upgrade 是不是也有些记不清了?是不是有时还会不小心用出了 no such table 的异常?那就一起来看一看吧!
- 数据库的使用
1.extends SQLiteOpenHelper;
2.构造方法传入数据库的库名和版本号;
3.实现方法 onCreate(SQLiteDatabase db)以及 onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion);
public class DataBaseHelper extends SQLiteOpenHelper {
/**
* 数据库名称
*/
static final String DATABASE_NAME = "DBName.db";
/**
* 数据库版本号
*/
static final int VERSION = 1;
/**
* 构造方法
*/
private DataBaseHelper(Context context) {
super(context, DATABASE_NAME, null, VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
- 跟着源码看流程
数据库的流程(建库,onCreate,onUpgrade,建表时机)
通过构造方法设置初始值,比较重要的参数是: 1.库名,2.版本号
//最终会调用此方法
private SQLiteOpenHelper(@Nullable Context context, @Nullable String name, int version,
int minimumSupportedVersion,
@NonNull SQLiteDatabase.OpenParams.Builder openParamsBuilder) {
Preconditions.checkNotNull(openParamsBuilder);
//判断版本号,数据库的版本号必须大于1
if (version < 1) throw new IllegalArgumentException("Version must be >= 1, was " + version);
//进行初始赋值
mContext = context;
mName = name;
mNewVersion = version;
mMinimumSupportedVersion = Math.max(0, minimumSupportedVersion);
setOpenParamsBuilder(openParamsBuilder);
}
首次调用 getWritableDatabase()或 getReadableDatabase()时,通过 getDatabaseLocked(boolean writable)建立数据库,在这里进行完毕的时候,我们完成了建库
而我们一般会选择在 onCreate(db);当中进行建表
public SQLiteDatabase getWritableDatabase() {
synchronized (this) {
return getDatabaseLocked(true);
}
}
public SQLiteDatabase getReadableDatabase() {
synchronized (this) {
return getDatabaseLocked(false);
}
}
private SQLiteDatabase getDatabaseLocked(boolean writable) {
...
//version首次进入的时候,version = 0;
final int version = db.getVersion();
//mNewVersion是在构造函数中赋值,且不可小于1,则在首次进入时,是一定会满足条件的
if (version != mNewVersion) {
if (db.isReadOnly()) {
throw new SQLiteException("Can't upgrade read-only database from version " +
db.getVersion() + " to " + mNewVersion + ": " + mName);
}
if (version > 0 && version < mMinimumSupportedVersion) {
...
} else {
//我们并没有设置mMinimumSupportedVersion,因此会进入这里
//开启一个事务,只有建库的过程全部完成,才算成功,否则,都不算做成功
db.beginTransaction();
try {
//这里又看到了version,当手机当中没有建立数据库时(以我们在构造方法中指定的库名为准),version是为0的,当已经建立过
//数据库的时候,这个值就不再是0了
if (version == 0) {
//则会进行创建,也就是我们需要实现的方法,这也就是常说的,为什么只有在没有库的时候才会走onCreate
//,而其余的情况都不会走了
onCreate(db);
} else {
//可以看到,是两种情况,version和构造方法当中传入的mNewVersion相比较
//如果mNewVersion比较小,则证明你的版本比之前记录的版本低了,因此会进行降级,我们一般使用的比较少
if (version > mNewVersion) {
onDowngrade(db, version, mNewVersion);
} else {
//如果mNewVersion比较大,则找到了onUpgrade,这个我们可以实现用来进行自己操作的方法
onUpgrade(db, version, mNewVersion);
}
//看到这里,是不是有一些好奇,相等的情况哪里去了,哈哈,看一下最上面if (version != mNewVersion),如果
version == mNewVersion,则这些都根本都不会进入
}
db.setVersion(mNewVersion);
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
}
}
...
} finally {
...
}
}
- 建表
1.一般情况下,我们是在 onCreate(db);中进行数据表的创建的,跟随数据库一起创建
2.当数据库已经存在,而我们希望再新建一张新表的时候,从上面的分析已经知道,不会再重走 onCreate(db);了,这个时候,需要更改数据库的版本号,通过 onUpgrade(db, version, mNewVersion);处进行建表
3.这个时候,数据库的名字已经知道了,想要建立一张表,就需要 (1.数据表的名称;2.每一列的列名,3.指定列名的同时,需要指定列的类型)
id | 列 0 | 列 1 | 列 2 |
---|---|---|---|
1 | 列 0 数据 | 列 1 数据 | 列 2 数据 |
2 | 列 0 数据 | 列 1 数据 | 列 2 数据 |
3 | 列 0 数据 | 列 1 数据 | 列 2 数据 |
4 | 列 0 数据 | 列 1 数据 | 列 2 数据 |
示例
/**
* 表名
*/
static final String DATABASE_NAME = "TABLE_NAME.db";
/**
* 列名
*/
private final static String USER_NAME = "USER_NAME";
private final static String USER_PSW = "USER_PSW";
在这里,我们可能需要一点小小的帮助:
public static final String create = "CREATE TABLE IF NOT EXISTS ";
public static final String id = BaseColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, ";
//UserDataDao
public static final String CREATE_TABLE_SQL = provideCreateTableSql();
private static String provideCreateTableSql() {
return DBSQL.create + TABLE_NAME + " (" +
DBSQL.id +
USER_NAME + " TEXT," +
USER_PSW + " TEXT);";
}
//完整的sql语句 TEXT指明的是列当中的数据类型均为String
//当然,如果有多个列,那就照样子添加就可以了
CREATE TABLE IF NOT EXISTS USER_TABLE (_id INTEGER PRIMARY KEY AUTOINCREMENT, USER_NAME TEXT,USER_PSW TEXT);
//这个时候,我们来修改一下onCreate(db);当中的代码
@Override
public void onCreate(SQLiteDatabase db) {
createTable(db, UserDataDao.CREATE_TABLE_SQL);
}
//因为我们可能创建多张表,用一个方法表示一下,每多一张表,就多添加一遍就可以,参数就是上面所介绍的SQL语句
private synchronized void createTable(SQLiteDatabase db, String createTableSQL) {
try {
db.execSQL(createTableSQL);
} catch (Exception ignored) {
}
}
- 增删改查
//增 put键值对就可以了
public synchronized void insert(UserBean userBean) {
try {
ContentValues contentValues = new ContentValues();
contentValues.put(USER_NAME, userBean.mUserName);
contentValues.put(USER_PSW, userBean.mUserPsw);
mDbHelper.getWritableDatabase().insert(TABLE_NAME, null, contentValues);
} catch (Exception ignored) {
}
}
//删
//根据列中的值删除
//参数 1.表名;2.列名 + "=?";3.所根据的列的值
public synchronized void delete(UserBean userBean) {
try {
mDbHelper.getWritableDatabase().delete(TABLE_NAME
, USER_NAME + "=?"
, new String[]{userBean.mUserName});
} catch (Exception ignored) {
}
}
//改
//根据列中的值更改
//columnsToUpdata列中原来的值
//和insert一样,先制作一个需要插入的数据
//参数 1.表名;2,制作的需要插入的数据,3.列名 + "=?";4.列中原来的值
public synchronized void upData(UserBean userBean,String columnsToUpdata) {
try {
ContentValues contentValues = new ContentValues();
contentValues.put(USER_NAME, userBean.mUserName);
contentValues.put(USER_PSW, userBean.mUserPsw);
mDbHelper.getWritableDatabase().update(TABLE_NAME,contentValues
, USER_NAME + "=?"
, new String[]{columnsToUpdata});
} catch (Exception ignored) {
}
}
//查 查询表中全部数据
public static final String queryAll = "SELECT * FROM ";
private static final String SQL_QUERY_ALL = DBSQL.queryAll + TABLE_NAME;
public synchronized List queryAll() {
List list = new ArrayList<>();
try {
Cursor cursor = mDbHelper.getWritableDatabase().rawQuery(SQL_QUERY_ALL, new String[]{});
while (cursor.moveToNext()) {
String name = cursor.getString(cursor.getColumnIndex(USER_NAME));
String psw = cursor.getString(cursor.getColumnIndex(USER_PSW));
UserBean userBean = new UserBean();
userBean.mUserName = name;
userBean.mUserPsw = psw;
list.add(userBean);
}
cursor.close();
} catch (Exception ignored) {
}
return list;
}
//查 根据指定列的值查询
private static final String SQL_QUERY_BY_COLUMS_VALUE = "SELECT * FROM " + TABLE_NAME + " WHERE " + USER_NAME + " = ?";
public synchronized List getByColumnsValue(String value) {
List list = new ArrayList<>();
try {
Cursor cursor = mDbHelper.getWritableDatabase().rawQuery(SQL_QUERY_BY_COLUMS_VALUE , new String[]{value});
while (cursor.moveToNext()) {
String name = cursor.getString(cursor.getColumnIndex(USER_NAME));
String psw = cursor.getString(cursor.getColumnIndex(USER_PSW));
UserBean userBean = new UserBean();
userBean.mUserName = name;
userBean.mUserPsw = psw;
list.add(userBean);
}
cursor.close();
} catch (Exception ignored) {
}
return list;
}
//删除表
public static final String drop = "DROP TABLE IF EXISTS ";
private static final String DELETE_TABLE = DBSQL.drop + TABLE_NAME;
public synchronized void deleteTable() {
try {
mDbHelper.getWritableDatabase().execSQL(DELETE_TABLE);
} catch (Exception ignored) {
}
}