介绍
GreenDAO是一个对象关系映射(ORM)的框架,能够提供相关接口,通过操作对象的方式去操作关系型数据库。GreenDao官网介绍: greenDAO is a light & fast ORM solution for Android that maps objects to SQLite databases.
GreenDao的优势
- 轻量级
- 增删改查操作快速
- 内存开销小,性能好
- Api接口完善,方便初学者使用
GreenDao2.0配置
在gradle中引入:
compile 'de.greenrobot:greendao:2.0.0'
GreenDao2.0使用
创建本地数据库及表
新建一java工程,导入greendao-generator-1.3.1.jar到libs中,main文件中写:
public class ExampleDaoGenerator {
public static void main(String[] args) throws Exception {
//第一个参数是数据库版本号,第二个参数是包名
Schema schema = new Schema(version, "你的包名路径");
//给数据库新增一张表
addMessage(schema);
//第二个参数是文件生成路径
new DaoGenerator().generateAll(schema, LocalConstants.CODE_PATH);
}
private static void addMessage(Schema schema) {
//表实体,会对应生成一张表
Entity note = schema.addEntity("MessageEntity");
//给表添加一个主键
note.addStringProperty("msgId").primaryKey().notNull();
//boolean类型字段,对应列名
note.addBooleanProperty("isRead");
//字符类型字段,对应列名
note.addStringProperty("createTime");
}
}
执行Main()方法,数据库映射文件将会在LocalConstants.CODE_PATH路径下生成。-
数据库的使用(表的增删改查)
public class DbHelper {
private final static String DB_NAME = "xxx.db";
private static volatile DbHelper dbHelper;
private DaoSession daoSession;
private DaoMaster daoMaster;
private MessageEntityDao messageEntityDao;
public static DbHelper getInstance() {
if (null == dbHelper) {
synchronized (DbHelper.class) {
if (null == dbHelper) {
dbHelper = new DbHelper();
dbHelper.daoSession = dbHelper.getDaoSession(XxxApplication.getInstance());
dbHelper.messageEntityDao = dbHelper.daoSession.getMessageEntityDao();
}
}
}
return dbHelper;
}
private DbHelper() {} private DaoSession getDaoSession(Context context) { if (daoSession == null) { if (daoMaster == null) { daoMaster = getDaoMaster(context); } daoSession = daoMaster.newSession(); } return daoSession; } private DaoMaster getDaoMaster(Context context) { if (daoMaster == null) { DaoMaster.OpenHelper helper = new DaoMaster.DevOpenHelper(context, DB_NAME, null); daoMaster = new DaoMaster(helper.getWritableDatabase()); } return daoMaster; } //保存一条消息 public long saveMessageEntity(MessageEntity messageEntity) { if (null == messageEntity) { return -1; } long result = -1; try { result = messageEntityDao.insertOrReplace(messageEntity); } catch (ClassCastException ex) { MLog.e("ClassCastException", "ClassCastException"); } catch (Exception ex) { ex.printStackTrace(); } return result; } //查询未读消息数 public int getNoReadMsg() { try { return messageEntityDao.queryBuilder().where(MessageEntityDao.Properties.IsRead.eq(false)).build().list().size(); } catch (Exception e) { e.printStackTrace(); return 0; } } //查消息类型对应的未读消息条数 public int getNoReadMsgCountByMsgType(String msgType) { try { return messageEntityDao.queryBuilder().where( MessageEntityDao.Properties.MsgType.eq(msgType), MessageEntityDao.Properties.IsRead.eq(false)).build().list().size(); } catch (Exception e) { e.printStackTrace(); return 0; } } //查询消息 public MessageEntity getMsgByMsgId(String msgId) { try { return messageEntityDao.queryBuilder().where(MessageEntityDao.Properties.MsgId.eq(msgId)).build().unique(); } catch (Exception e) { e.printStackTrace(); return null; } } }
说明:
使用DevOpenHelper打开数据库
DaoMaster.DevOpenHelper helper = new DevOpenHelper(context,"xxx.db",null);
我们查看下DevOpenHelper内容
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);
}
}
可以发现,当数据库版本更新时,会执行onUpgrade方法,先删除原有的数据表,再新建表。
数据库升级
当我们的app版本升级时,当对本地数据库表结构修改时,就有必要对本地数据库升级。我们只需要修改下DaoMaster文件中的SCHEMA_VERSION常量(增1),它就会执行onUpgrade()。
public class DaoMaster extends AbstractDaoMaster {
public static final int SCHEMA_VERSION = 128;
public static void createAllTables(SQLiteDatabase db, boolean ifNotExists) {
MessageEntityDao.createTable(db, ifNotExists);
}
......
}
有时我们并不想把原有的表数据也删除,那要怎么做呢?
其核心思路是
- 把旧表改为临时表
- 建立新表
- 临时表数据写入新表,删除临时表
代码实现:
/**
*表字段有改变的时候需要用到合并数据
*Created by wangfengkai on 17/3/11.
*Github:https://github.com/github/jxwangfengkai
*/
public class DbOpenHelper extends DaoMaster.OpenHelper {
public DbOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory) {
super(context, name, factory);
}
@Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
//操作数据库的更新
MigrationHelper.getInstance().migrate(sqLiteDatabase, MessageEntityDao.class);
}
}
/**
* MigrationHelper类
*/
public class MigrationHelper {
private static final String CONVERSION_CLASS_NOT_FOUND_EXCEPTION = "MIGRATION HELPER - CLASS DOESN'T MATCH WITH THE CURRENT PARAMETERS";
private static final String TAG = "MigrationHelper";
private static volatile MigrationHelper instance;
public static MigrationHelper getInstance() {
if (instance == null) {
instance = new MigrationHelper();
}
return instance;
}
public void migrate(SQLiteDatabase db, Class extends AbstractDao, ?>>... daoClasses) {
generateTempTables(db, daoClasses);
DaoMaster.dropAllTables(db, true);
DaoMaster.createAllTables(db, false);
restoreData(db, daoClasses);
}
private void generateTempTables(SQLiteDatabase db, Class extends AbstractDao, ?>>... daoClasses) {
for (int i = 0; i < daoClasses.length; i++) {
DaoConfig daoConfig = new DaoConfig(db, daoClasses[i]);
String divider = "";
String tableName = daoConfig.tablename;
String tempTableName = daoConfig.tablename.concat("_TEMP");
ArrayList properties = new ArrayList<>();
StringBuilder createTableStringBuilder = new StringBuilder();
createTableStringBuilder.append("CREATE TABLE ").append(tempTableName).append(" (");
for (int j = 0; j < daoConfig.properties.length; j++) {
String columnName = daoConfig.properties[j].columnName;
if (getColumns(db, tableName).contains(columnName)) {
properties.add(columnName);
String type = null;
try {
type = getTypeByClass(daoConfig.properties[j].type);
} catch (Exception exception) {
Log.e(TAG, "CrashType:" + daoConfig.properties[j].type);
exception.printStackTrace();
}
createTableStringBuilder.append(divider).append(columnName).append(" ").append(type);
if (daoConfig.properties[j].primaryKey) {
createTableStringBuilder.append(" PRIMARY KEY");
}
divider = ",";
}
}
createTableStringBuilder.append(");");
String createSql = createTableStringBuilder.toString();
if (!createSql.contains("();")) {
//说明没有表
db.execSQL(createSql);
StringBuilder insertTableStringBuilder = new StringBuilder();
insertTableStringBuilder.append("INSERT INTO ").append(tempTableName).append(" (");
insertTableStringBuilder.append(TextUtils.join(",", properties));
insertTableStringBuilder.append(") SELECT ");
insertTableStringBuilder.append(TextUtils.join(",", properties));
insertTableStringBuilder.append(" FROM ").append(tableName).append(";");
String insertTableSql = insertTableStringBuilder.toString();
Log.e(TAG, daoConfig.tablename + "__insertTableSql:" + insertTableSql);
db.execSQL(insertTableSql);
}
}
}
private void restoreData(SQLiteDatabase db, Class extends AbstractDao, ?>>... daoClasses) {
for (int i = 0; i < daoClasses.length; i++) {
DaoConfig daoConfig = new DaoConfig(db, daoClasses[i]);
String tableName = daoConfig.tablename;
String tempTableName = daoConfig.tablename.concat("_TEMP");
ArrayList properties = new ArrayList();
for (int j = 0; j < daoConfig.properties.length; j++) {
String columnName = daoConfig.properties[j].columnName;
if (getColumns(db, tempTableName).contains(columnName)) {
properties.add(columnName);
}
}
StringBuilder insertTableStringBuilder = new StringBuilder();
insertTableStringBuilder.append("INSERT INTO ").append(tableName).append(" (");
insertTableStringBuilder.append(TextUtils.join(",", properties));
insertTableStringBuilder.append(") SELECT ");
insertTableStringBuilder.append(TextUtils.join(",", properties));
insertTableStringBuilder.append(" FROM ").append(tempTableName).append(";");
StringBuilder dropTableStringBuilder = new StringBuilder();
dropTableStringBuilder.append("DROP TABLE IF EXISTS ").append(tempTableName);
String insertSQL = insertTableStringBuilder.toString();
if (properties.size() > 0) {
Log.e(TAG, daoConfig.tablename + "__restoreData__insertSQL:" + insertSQL);
db.execSQL(insertSQL);
}
String dropTableSql = dropTableStringBuilder.toString();
Log.e(TAG, daoConfig.tablename + "__restoreData__dropTableSql:" + dropTableSql);
db.execSQL(dropTableSql);
}
}
private String getTypeByClass(Class> type) throws Exception {
if (type.equals(String.class)) {
return "TEXT";
}
if (type.equals(Long.class) || type.equals(Integer.class) || type.equals(long.class) || type.equals(int.class) || type.equals(Boolean.class) || type.equals(boolean.class)) {
return "INTEGER";
}
Exception exception = new Exception(CONVERSION_CLASS_NOT_FOUND_EXCEPTION.concat(" - Class: ").concat(type.toString()));
exception.printStackTrace();
throw exception;
}
private static List getColumns(SQLiteDatabase db, String tableName) {
List columns = new ArrayList<>();
Cursor cursor = null;
try {
cursor = db.rawQuery("SELECT * FROM " + tableName + " limit 1", null);
if (cursor != null) {
columns = new ArrayList<>(Arrays.asList(cursor.getColumnNames()));
}
} catch (Exception e) {
Log.v(tableName, e.getMessage(), e);
e.printStackTrace();
} finally {
if (cursor != null)
cursor.close();
}
return columns;
}
}
所以,当需要数据库升级时,我们使用
DbOpenHelper helper = new DbOpenHelper(context,"xxx.db",null);
来打开数据库。
讲到这里,GreenDao2.0的使用基本已经完了,下一篇,我将为大家讲解GreenDao3.0的优化及使用。
喜欢就点个赞哦。