1. APP开发期间的数据库
在上一篇文章中封装了GreenDaoManager
中有个构造方法如下:
private GreenDaoManager(){
if (mInstance == null) {
// DaoMaster.DevOpenHelper devOpenHelper = new
// DaoMaster.DevOpenHelper(MyApplication.getContext(), "database_name", null);//此处openhelper为自动生成开发所使用,发布版本需自定义
MySQLiteOpenHelper devOpenHelper = new
MySQLiteOpenHelper(new GreenDaoContext(), "database_name.db", null);//GreenDaoContext为创建数据库路径使用
mDaoMaster = new DaoMaster(devOpenHelper.getWritableDatabase());
mDaoSession = mDaoMaster.newSession();
}
}
其中注释掉的两行代码中:
DaoMaster.DevOpenHelper devOpenHelper = new
DaoMaster.DevOpenHelper(MyApplication.getContext(), "database_name", null);//此处DevOpenHelper 为自动生成开发所使用,发布版本需自定义
其中的MyApplication.getContext()
上下文表示了数据库存储路径为手机内存。这里的DevOpenHelper
即为DaoMaster
中自动生成代码,完整代码如下:
/** * WARNING: Drops all table on Upgrade! Use only during development. */
public static class DevOpenHelper extends OpenHelper {
public DevOpenHelper(Context context, String name, CursorFactory factory) {
super(context, name, factory);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Log.i("greenDAO", "Upgrading schema from version " + oldVersion + " to " + newVersion + " by dropping all tables");
dropAllTables(db, true);
onCreate(db);
}
}
注意看第一行注释:WARNING: Drops all table on Upgrade! Use only during development.
数据库升级的话,会删除所有表,然后重新创建。这种方式在开发期间,APP还没有上线之前是可以的。
当APP上线后,我们不能使用这种方式,因为这样会导致已经存在的数据会被删除。
2. APP上线后,数据库升级
我们需要重写一个类MySQLiteOpenHelper
实现OpenHelper
.
1. 需要自己实现了onUpgrade
方法来自定义升级过程。
2. 当然升级过程中也要修改DaoMaster.SCHEMA_VERSION
3. 当DaoMaster.SCHEMA_VERSION
跟你当前数据库的版本比较后,会根据你当前数据库的版本,然后进行升级。
4. 关键代码onUpgrade
方法,会比较新数据库和旧数据库的版本,然后执行相应的sql升级:
public class MySQLiteOpenHelper extends DaoMaster.OpenHelper {
public MySQLiteOpenHelper(Context context, String name) {
super(context, name);
}
public MySQLiteOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory) {
super(context, name, factory);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
//数据迁移模块
MigrationHelper.migrate(db,
UserDao.class,
ProfessionDao.class,
LTestDao.class);
}
}
数据库升级不外乎两种情况:
1.修改表结构。
2.添加新表。
针对onUpgrade
中的实现方法可以采用两种不同策略:(稍后都会提供两种策略的代码实现,下面主要讲述第二种数据迁移实现方式)
1.逐级版本迭代升级,比如当前版本为1,最新版本为3,此方案就是先从1–>2–>3.
2.把数据库中的数据备份,然后全删数据库,再重新创建新的数据库,把备份数据导入。此方案直接从1–>3。
3. 数据迁移(数据库备份)的具体实现
- android上面对的数据库基本上就是轻量级数据库
sqlite
,首先我们需要了解一些后面需要用到的数据库操作语句:
- 判断
sqlite
表是否存在
SELECT * FROM sqlite_master WHERE type='table' AND name='tempTableName';
sqlite
判断临时表是否存在
SELECT * FROM sqlite_temp_master WHERE type='table' AND name='tempTableName';
sqlite
创建表tableName
的临时表
create temporary table tempTableName as select * from tableName;
- 删除临时表
drop table tempTableName;
- 判断
- sqlite的系统表
sqlite_master
、临时表sqlite_temp_master
SQLite数据库中一个特殊的名叫SQLITE_MASTER
上执行一个SELECT查询以获得所有表的索引。每一个 SQLite 数据库都有一个叫SQLITE_MASTER
的表, 它定义数据库的模式。SQLITE_MASTER
表看起来如下:
CREATE TABLE sqlite_master (
type TEXT,
name TEXT,
tbl_name TEXT,
rootpage INTEGER,
sql TEXT
);
type 字段永远是 ‘table’,name 字段永远是对应表的名字。所以,要获得数据库中所有表的列表, 使用下列SELECT语句:
SELECT name FROM sqlite_master
WHERE type=’table’
ORDER BY name;
对于索引,type 等于 ‘index’, name 则是索引的名字,tbl_name 是该索引所属的表的名字。 不管是表还是索引,sql 字段是原先用 CREATE TABLE 或 CREATE INDEX 语句创建它们时的命令文本。对于自动创建的索引(用来实现 PRIMARY KEY 或 UNIQUE 约束),sql字段为NULL。
SQLITE_MASTER 表是只读的。不能对它使用 UPDATE、INSERT 或 DELETE。 它会被 CREATE TABLE、CREATE INDEX、DROP TABLE 和 DROP INDEX 命令自动更新。
临时表及其索引和触发器存放在另外一个叫 SQLITE_TEMP_MASTER 的表中。SQLITE_TEMP_MASTER 跟 SQLITE_MASTER 差不多, 但它只是对于创建那些临时表的应用可见。如果要获得所有表的列表, 不管是永久的还是临时的,可以使用类似下面的命令:
SELECT name FROM
(SELECT * FROM sqlite_master UNION ALL
SELECT * FROM sqlite_temp_master)
WHERE type=’table’
ORDER BY name
数据迁移的工具类
MigrationHelper
。
public final class MigrationHelper {
public static boolean DEBUG = true;
private static String TAG = “MigrationHelper”;
private static final String SQLITE_MASTER = “sqlite_master”;
private static final String SQLITE_TEMP_MASTER = “sqlite_temp_master”;
public static void migrate(SQLiteDatabase db, Class
4. 设置数据库路径
在第一模块中有句代码:
MySQLiteOpenHelper devOpenHelper = new MySQLiteOpenHelper(new GreenDaoContext(), "database_name.db", null);//GreenDaoContext为创建数据库路径使用
里面有个上下文GreenDaoContext
继承了ContextWrapper
,里面设置了数据库路径,代码如下:
public class GreenDaoContext extends ContextWrapper {
private String currentUserId = "greendao";//一般用来针对一个用户一个数据库,以免数据混乱问题
private Context mContext;
public GreenDaoContext() {
super(MyApplication.getContext());
this.mContext = MyApplication.getContext();
// this.currentUserId = "greendao";//初始化
}
/**
* 获得数据库路径,如果不存在,则创建对象
*
* @param dbName
*/
@Override
public File getDatabasePath(String dbName) {
String dbDir = CommonUtils.getDBPath();
if (TextUtils.isEmpty(dbDir)){
Log.e("SD卡管理:", "SD卡不存在,请加载SD卡");
return null;
}
File baseFile = new File(dbDir);
// 目录不存在则自动创建目录
if (!baseFile.exists()){
baseFile.mkdirs();
}
StringBuffer buffer = new StringBuffer();
buffer.append(baseFile.getPath());
buffer.append(File.separator);
buffer.append(currentUserId);
dbDir = buffer.toString();// 数据库所在目录
buffer.append(File.separator);
// buffer.append(dbName+"_"+currentUserId);//也可以采用此种方式,将用户id与表名联系到一块命名
buffer.append(dbName);
String dbPath = buffer.toString();// 数据库路径
// 判断目录是否存在,不存在则创建该目录
File dirFile = new File(dbDir);
if (!dirFile.exists()){
dirFile.mkdirs();
}
// 数据库文件是否创建成功
boolean isFileCreateSuccess = false;
// 判断文件是否存在,不存在则创建该文件
File dbFile = new File(dbPath);
if (!dbFile.exists()) {
try {
isFileCreateSuccess = dbFile.createNewFile();// 创建文件
} catch (IOException e) {
e.printStackTrace();
}
} else
isFileCreateSuccess = true;
// 返回数据库文件对象
if (isFileCreateSuccess)
return dbFile;
else
return super.getDatabasePath(dbName);
}
/**
* 重载这个方法,是用来打开SD卡上的数据库的,android 2.3及以下会调用这个方法。
*
* @param name
* @param mode
* @param factory
*/
@Override
public SQLiteDatabase openOrCreateDatabase(String name, int mode,
SQLiteDatabase.CursorFactory factory) {
SQLiteDatabase result = SQLiteDatabase.openOrCreateDatabase(getDatabasePath(name), factory);
return result;
}
/**
* Android 4.0会调用此方法获取数据库。
*
* @param name
* @param mode
* @param factory
* @param errorHandler
* @see android.content.ContextWrapper#openOrCreateDatabase(java.lang.String, int,
* android.database.sqlite.SQLiteDatabase.CursorFactory,
* android.database.DatabaseErrorHandler)
*/
@Override
public SQLiteDatabase openOrCreateDatabase(String name, int mode, SQLiteDatabase.CursorFactory factory,
DatabaseErrorHandler errorHandler) {
SQLiteDatabase result = SQLiteDatabase.openOrCreateDatabase(getDatabasePath(name), factory);
return result;
}
}
OK,先到这了。。。