以前开发用到数据库时,基本上都是用android原生的sql语句,写那些语句时稍有不慎,就给你抛出一个exception。现在网上有很多的数据库ORM框架,今天写篇文章来记录一下比较好用的框架:greendao的使用。关于greendao的介绍,网上已经有很多了,可以自行查阅。
准备工作
- 1、新建一个android工程,在main目录下新建一个文件夹java-gen,如下图:
- 2、在同一个project下,再新建一个java module,并新创建一个类,如下图:
-
3、在android module中的build.gradle文件中加上以下代码:
sourceSets { main { java.srcDirs = ['src/main/java', 'src/main/java-gen'] } } compile 'de.greenrobot:greendao:2.1.0'
在java module中的build.grade文件中添加以下代码:
compile 'de.greenrobot:greendao-generator:2.1.0'
自动生成数据库Bean和Dao类
以下是java module中类的实现
public class GreenDaoGeneratorTest {
//自动生成类的包名
public static String PACKAGE_NAME = "com.blainpeng.greendao";
//这里的OUT_DIR就是我们新建的java-gem的路径
public static String OUT_DIR = "/Users/Desktop/AndroidProject/GreenDaoDemo/app/src/main/java-gen";
public static void main(String[] args) throws Exception {
// 1、创建一个用于添加实体(entity)的模式(Schema)对象
Schema schema = new Schema(1, PACKAGE_NAME); //第一个参数为数据库的版本号
// Schema schema = new Schema(2, PACKAGE_NAME);版本号升级
// 2、获得了Schema对象后就可以添加实体了,也就是添加数据库表了。
addCustomer(schema);
// 3、利用DaoGenerator类生成代码,并将自动生成的代码放到指定的目录
new DaoGenerator().generateAll(schema, OUT_DIR);
}
private static void addCustomer(Schema schema) {
// 4、一个实体类就关联到数据库中的一张表,此处表名为:Customer
Entity entity = schema.addEntity("Customer");
// 5、设置数据库表中的字段(greenDao会自动根据实体类的属性来创建表字段,并赋予默认值)
entity.addIdProperty().autoincrement();
entity.addStringProperty("name").notNull();
entity.addStringProperty("age").notNull();
entity.addStringProperty("phone").notNull();
entity.addStringProperty("marriage").notNull();
//entity.addStringProperty("address"); 升级时添加的新列名
}
}
写好这个类以后,点击它,右击run ,出现下图说明运行成功:
此时,java-gen文件夹里面就有4个类了。
如何调用?
-
创建一个类继承自Application,上代码:
public class BaseApplication extends Application { public static DaoMaster daoMaster; public static DaoSession daoSession; public static SQLiteDatabase db; public static DaoMaster.DevOpenHelper helper; @Override public void onCreate() { super.onCreate(); /* * 通过 DaoMaster 的内部类 DevOpenHelper,你可以得到一个便利的 SQLiteOpenHelper 对象 */ helper = new DaoMaster.DevOpenHelper(this, "dbname.db", null); db = helper.getWritableDatabase(); daoMaster = new DaoMaster(db); daoSession = daoMaster.newSession(); } public static DaoSession getDaoSession() { return daoSession; } public static SQLiteDatabase getSqLiteDatabase() { return db; } }
-
在activity中调用
//先获得dao的实例 customerDao = BaseApplication.getDaoSession().getCustomerDao(); //创建对象,并将对象添加到数据库 Customer customer = new Customer(null, name, age, phone,marriage); customerDao.insert(customer); //查询方法 list = customerDao.loadAll();
使用greendao,对于数据库的CRUD,我们只需要往里面添加一个对象就可以了,再也不需要去记那些spl语句子,是不是非常爽啊。
如何安全地升级数据库?
-
数据库升级的原理
先创建一个新表,将原表中的数据进行复制,再把原数据库表删掉// 删除表时,使用事务处理,使得修改能立即更新到数据库文件中 db.beginTransaction(); try { // 重命名数据库表 String tempTableName = TABLE_NAME + "_temp"; String sql = "ALTER TABLE " + TABLE_NAME + " RENAME TO " + tempTableName; db.execSQL(sql); // 创建一个新的数据库表 db.execSQL(sql_create_table2); // 将数据从tempTableName中插入到TABLE_NAME表中 sql = "INSERT INTO " + TABLE_NAME + " SELECT *," + " ''FROM " + tempTableName; db.execSQL(sql); // 删除临时表 sql = "DROP TABLE " + tempTableName; db.execSQL(sql); db.setTransactionSuccessful(); } finally { db.endTransaction(); }
-
使用greendao时进行数据库升级
以下是一位国外大神的封装:public class MigrationHelper{ private static final String CONVERSION_CLASS_NOT_FOUND_EXCEPTION = "MIGRATION HELPER - CLASS DOESN'T MATCH WITH THE CURRENT PARAMETERS"; private static MigrationHelper instance; public static MigrationHelper getInstance() { if (instance == null) { instance = new MigrationHelper(); } return instance; } /** * 数据迁移 * * @param db * @param daoClasses */ public void migrate(SQLiteDatabase db, Class<? extends AbstractDao<?, ?>>... daoClasses){ generateTempTables(db, daoClasses);// 删除旧的数据库表 DaoMaster.dropAllTables(db, true);// 重新创建新的数据库表 DaoMaster.createAllTables(db, false);restoreData(db, daoClasses); } /** * 生成临时数据库表 * * @param db * @param 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){ exception.printStackTrace(); } createTableStringBuilder.append(divider).append(columnName).append(" ").append(type); if (daoConfig.properties[j].primaryKey){ createTableStringBuilder.append(" PRIMARY KEY"); } divider = ","; } } createTableStringBuilder.append(");"); db.execSQL(createTableStringBuilder.toString()); 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(";"); db.execSQL(insertTableStringBuilder.toString()); } } /** * 保存数据 * * @param db * @param daoClasses */ 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<String>(); 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 ").append(tempTableName); db.execSQL(insertTableStringBuilder.toString()); db.execSQL(dropTableStringBuilder.toString()); } } /** * 获得数据库表字段类型 * * @param type * @return * @throws Exception */ 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)) { return "INTEGER"; } if (type.equals(Boolean.class)) { return "BOOLEAN"; } Exception exception = new Exception(CONVERSION_CLASS_NOT_FOUND_EXCEPTION.concat(" - Class: ").concat(type.toString())); exception.printStackTrace(); throw exception; } /** * 获得数据库所有列 * * @param db * @param tableName * @return */ 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; } }
最后在DaoMaster的onUpgrade内调用这个帮助类中的方法
MigrationHelper.getInstance().migrate(db, CustomerDao.class);
好了,greendao的使用就这么多了。