介紹
GreenDAO是一個對象關系映射(ORM)的框架,能夠提供相關接口娘锁,通過操作對象的方式去操作關系型數(shù)據(jù)庫。GreenDao官網(wǎng)介紹: greenDAO is a light & fast ORM solution for Android that maps objects to SQLite databases.
GreenDao的優(yōu)勢
- 輕量級
- 增刪改查操作快速
- 內存開銷小外莲,性能好
- Api接口完善,方便初學者使用
GreenDao2.0配置
在gradle中引入:
compile 'de.greenrobot:greendao:2.0.0'
GreenDao2.0使用
創(chuàng)建本地數(shù)據(jù)庫及表
新建一java工程降铸,導入greendao-generator-1.3.1.jar到libs中在旱,main文件中寫:
public class ExampleDaoGenerator {
public static void main(String[] args) throws Exception {
//第一個參數(shù)是數(shù)據(jù)庫版本號,第二個參數(shù)是包名
Schema schema = new Schema(version, "你的包名路徑");
//給數(shù)據(jù)庫新增一張表
addMessage(schema);
//第二個參數(shù)是文件生成路徑
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");
}
}
執(zhí)行Main()方法谅畅,數(shù)據(jù)庫映射文件將會在LocalConstants.CODE_PATH路徑下生成登渣。-
數(shù)據(jù)庫的使用(表的增刪改查)
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; } //查詢未讀消息數(shù) public int getNoReadMsg() { try { return messageEntityDao.queryBuilder().where(MessageEntityDao.Properties.IsRead.eq(false)).build().list().size(); } catch (Exception e) { e.printStackTrace(); return 0; } } //查消息類型對應的未讀消息條數(shù) 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打開數(shù)據(jù)庫
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);
}
}
可以發(fā)現(xiàn),當數(shù)據(jù)庫版本更新時毡泻,會執(zhí)行onUpgrade方法胜茧,先刪除原有的數(shù)據(jù)表,再新建表仇味。
數(shù)據(jù)庫升級
當我們的app版本升級時竹揍,當對本地數(shù)據(jù)庫表結構修改時,就有必要對本地數(shù)據(jù)庫升級邪铲。我們只需要修改下DaoMaster文件中的SCHEMA_VERSION常量(增1),它就會執(zhí)行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);
}
......
}
有時我們并不想把原有的表數(shù)據(jù)也刪除,那要怎么做呢英染?
其核心思路是
- 把舊表改為臨時表
- 建立新表
- 臨時表數(shù)據(jù)寫入新表揽惹,刪除臨時表
代碼實現(xiàn):
/**
*表字段有改變的時候需要用到合并數(shù)據(jù)
*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) {
//操作數(shù)據(jù)庫的更新
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<String> 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<String> 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<String> getColumns(SQLiteDatabase db, String tableName) {
List<String> 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;
}
}
所以,當需要數(shù)據(jù)庫升級時四康,我們使用
DbOpenHelper helper = new DbOpenHelper(context,"xxx.db",null);
來打開數(shù)據(jù)庫搪搏。
講到這里,GreenDao2.0的使用基本已經(jīng)完了闪金,下一篇疯溺,我將為大家講解GreenDao3.0的優(yōu)化及使用论颅。
喜歡就點個贊哦。