GreenDao3.2.2集成使用以及数据库的升级
一概念
是一个将对象映射到 SQLite 数据库中的轻量且快速的 ORM 解决方案。
二优点:
一个精简的库;性能最大化;内存开销最小化;易于使用的 APIs;对 Android 进行高度优化。
三集成
1在app的build.gradle 红色的是要添加的
apply plugin: 'com.android.application'
apply plugin: 'org.greenrobot.greendao' // apply plugin
android {
//初始化greendao基本信息
greendao{
schemaVersion 1
daoPackage 'com.admom.mygreendaotest.gen'
targetGenDir 'src/main/java'
}
//schemaVersion: 数据库schema版本,也可以理解为数据库版本号
//daoPackage:设置DaoMaster、DaoSession、Dao包名
//targetGenDir:设置DaoMaster、DaoSession、Dao目录
//targetGenDirTest:设置生成单元测试目录
//generateTests:设置自动生成单元测试用例
}
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'com.android.support:appcompat-v7:25.3.1'
compile 'com.android.support.constraint:constraint-layout:1.0.2'
testCompile 'junit:junit:4.12'
compile 'org.greenrobot:greendao:3.2.2'
}
2在工程的build.gradle里添加如下代码
buildscript {
repositories {
jcenter()
mavenCentral() // add repository
}
dependencies {
classpath 'com.android.tools.build:gradle:2.3.2'
classpath 'org.greenrobot:greendao-gradle-plugin:3.2.2' // add plugin
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
3根据
greendao{
schemaVersion 1
daoPackage 'com.example.wbxu.gen'
targetGenDir 'src/main/java'
}
的配置 在src/java/ com.example.wbxu 这个包的下边创建gen用于存放DaoMaster DaoSession Dao【操作表的根据bean生成的】,
4创建实体类bean
@Entity
public class Fruit {
@Id(autoincrement = true) //设置主键自增长
private Long id; //自增id必须为long类型的
private String Name; //名字
@NotNull
private int Count; //个数
}
然后点击Build Make Project 就会在gen文件夹里生成DaoMaster DaoSession 对应实体【对应表的Dao】
5编写DaoManager创建数据库、创建数据库表、包含增删改查的操作
public class DaoManager {
private static final String TAG = DaoManager.class.getSimpleName();
//创建数据库的名字
private static final String DB_NAME = "MyGreenDb.db";
//初始化上下文
private Context context;
//多线程中要被共享的使用volatile关键字修饰 GreenDao管理类
private volatile static DaoManager mInstance;
//它里边实际上是保存数据库的对象
private static DaoMaster mDaoMaster;
//创建数据库的工具
private static DaoMaster.DevOpenHelper mHelper;
//管理gen里生成的所有的Dao对象里边带有基本的增删改查的方法
private static DaoSession mDaoSession;
/**
* 单例模式获得操作数据库对象
* @return
*/
public static DaoManager getInstance(){
if(mInstance==null){
synchronized (DaoManager.class){
if(mInstance==null){
mInstance=new DaoManager();
}
}
}
return mInstance;
}
/**
* 初始化上下文创建数据库的时候使用
*/
public void init(Context context){
this.context = context;
}
/**
* 判断是否有存在数据库,如果没有则创建
* @return
*/
public DaoMaster getDaoMaster(){
if(mDaoMaster == null) {
mHelper = new DaoMaster.DevOpenHelper(context, DB_NAME, null);
mDaoMaster = new DaoMaster(mHelper.getWritableDatabase());
}
return mDaoMaster;
}
/**
* 完成对数据库的添加、删除、修改、查询操作,
* @return
*/
public DaoSession getDaoSession(){
if(mDaoSession == null){
if(mDaoMaster == null){
mDaoMaster = getDaoMaster();
}
mDaoSession = mDaoMaster.newSession();
}
return mDaoSession;
}
/**
* 关闭所有的操作,数据库开启后,使用完毕要关闭
*/
public void closeConnection(){
closeHelper();
closeDaoSession();
}
public void closeHelper(){
if(mHelper != null){
mHelper.close();
mHelper = null;
}
}
public void closeDaoSession(){
if(mDaoSession != null){
mDaoSession.clear();
mDaoSession = null;
}
}
}
6编写对应表的工具类 实现操作该表的方法
public class FruitDaoUtil {
private DaoManager mManager;
private String TAG="flag";
//操作Fruit的构造函数
public FruitDaoUtil(Context context) {
mManager = DaoManager.getInstance();
mManager.init(context);
}
/**
* 完成fruit记录的插入,如果表未创建,先创建fruit表
*
* @param fruit
* @return 返回long值 -1为失败
*/
public boolean insertFruit(Fruit fruit) {
boolean flag = false;
flag = mManager.getDaoSession().getFruitDao().insertOrReplace(fruit) == -1 ? false : true;
Log.i(TAG, "-------插入一条的结果为"+flag);
return flag;
}
/**
* 插入多条数据,在子线程操作
* @return
*/
public boolean insertListFruit(final List mList) {
boolean flag = false;
try {
mManager.getDaoSession().runInTx(new Runnable() {
@Override
public void run() {
for (Fruit fruit : mList) {
mManager.getDaoSession().insertOrReplace(fruit);
}
}
});
flag = true;
} catch (Exception e) {
e.printStackTrace();
}
return flag;
}
/**
* 刷新指定数据
*/
public boolean reFreshFruit(Fruit fruit){
boolean flag = false;
mManager.getDaoSession().refresh(fruit);
return flag;
}
/**
* 修改一条数据
* @return
*/
public boolean updateFruit(Fruit fruit){
boolean flag = false;
try {
mManager.getDaoSession().update(fruit);
flag = true;
}catch (Exception e){
e.printStackTrace();
}
return flag;
}
/**
* 删除单条记录
* @return
*/
public boolean deleteFruit(Fruit fruit){
boolean flag = false;
try {
mManager.getDaoSession().delete(fruit);
flag = true;
}catch (Exception e){
e.printStackTrace();
}
return flag;
}
/**
* 删除所有记录
* @return
*/
public boolean deleteAll(){
boolean flag = false;
try {
mManager.getDaoSession().deleteAll(Fruit.class);
flag = true;
}catch (Exception e){
e.printStackTrace();
}
return flag;
}
/**
* 查询所有记录
* @return
*/
public List queryAllFruit(){
return mManager.getDaoSession().loadAll(Fruit.class);
}
/**
* 根据主键id查询记录
* @param key
* @return
*/
public Fruit queryFruitById(long key){
return mManager.getDaoSession().load(Fruit.class, key);
}
/**
* 使用 sql语句进行查询操作
* 参数一sql语句 参数二查询条件限定
*/
public List queryFruitBySql(String sql, String[] conditions){
return mManager.getDaoSession().queryRaw(Fruit.class, sql, conditions);
}
/**
* 使用queryBuilder进行查询
* @return
*/
public List queryFruitByQueryBuilder(long id){
QueryBuilder queryBuilder = mManager.getDaoSession().queryBuilder(Fruit.class);
return queryBuilder.where(FruitDao.Properties.Id.eq(id)).list();
}
}
7测试MainActivity的测试按钮点击事件如下
public void onClick(View view) {
switch (view.getId()) {
case R.id.insertsingle: //插入单个的
mFruitDaoUtil.insertFruit(new Fruit(1L,"苹果1",1));
break;
case R.id.multinsert: //插入多个的
List list=new ArrayList();
for (int i = 0; i < 10; i++) {
list.add(new Fruit(Long.parseLong(i+""),"桃子"+i,i));
}
mFruitDaoUtil.insertListFruit(list);
break;
case R.id.refresh: //刷新单个的
mFruitDaoUtil.reFreshFruit(new Fruit(1L,"苹果1",10));
break;
case R.id.update: //更新单个的
mFruitDaoUtil.reFreshFruit(new Fruit(1L,"苹果1",20));
break;
case R.id.deletesingle: //删除单个的
mFruitDaoUtil.deleteFruit(new Fruit(4L,"苹果1",20));
break;
case R.id.deleteMult: //删除全部
mFruitDaoUtil.deleteAll();
break;
case R.id.checksingle: //按主键查询一个
Fruit f= mFruitDaoUtil.queryFruitById(1L);
Log.d("flag","---------按条件查询的结果为"+f.getName()+"-----"+f.getId());
break;
case R.id.checkmult: //按条件查询
List l= mFruitDaoUtil.queryFruitBySql("Name,Count",new String[]{"苹果1","1"});
for (int i = 0; i List =mFruitDaoUtil.queryFruitByQueryBuilder(1L);
for (int i = 0; i
四常用的注解解释:
@Entity 实体注解
@NotNull 设置表中的当前列的值不为空
@Convert 制定自定义类型
@Generated GreenDao运行所产生的构造函数或者方法,被此标注的代码可以更新或者下次运行时清除
@Id 主键Long型,可以通过@Id(autoincrement = true)设置自增长,通过这个注解标记的字段必 须是long,数据库中表示它就是主键,并且默认为自增长
@Index 使用@Index作为一个属性累创建一个索引,定义多列索引(@Iink Entity#indexes())
@JoinEntity 定义表连接关系
@JoinProperty 定义名称和引用名称属性关系
@Keep 注解的代码在GreenDao下运行时保持不变
1.注解实体类:默认禁止修改此类
2.注解其他代码,默认禁止修改注解的代码段
@Order 制定排序
@Property 设置一个非默认关系映射所对应的列名,默认使用的字段名。
例:@Property(nameInDb="name")
@ToMany 定义多个实体对应的关系
@ToOne 定义与另一个实体(一个实体对象)的关系
@Transient 添加该标记之后不会生成数据库表的列
@Unique 向数据库列添加一个唯一的约束
五关于数据库的更新
原理:首先创建临时表(数据格式和原表一模一样)。
把当前表的数据插入到临时表中去。
删除掉原表,创建新表。
把临时表数据插入到新表中去,然后删除临时表。
下边贴上国外大神的写的更新数据库的操作类
public class MigrationHelper2 {
public static boolean DEBUG = false;
private static String TAG = "MigrationHelper2";
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 extends AbstractDao, ?>>... daoClasses) {
printLog("【The Old Database Version】" + db.getVersion());
Database database = new StandardDatabase(db);
migrate(database, daoClasses);
}
public static void migrate(Database database, Class extends AbstractDao, ?>>... daoClasses) {
printLog("【Generate temp table】start");
generateTempTables(database, daoClasses);
printLog("【Generate temp table】complete");
dropAllTables(database, true, daoClasses);
createAllTables(database, false, daoClasses);
printLog("【Restore data】start");
restoreData(database, daoClasses);
printLog("【Restore data】complete");
}
private static void generateTempTables(Database db, Class extends AbstractDao, ?>>... daoClasses) {
for (int i = 0; i < daoClasses.length; i++) {
String tempTableName = null;
DaoConfig daoConfig = new DaoConfig(db, daoClasses[i]);
String tableName = daoConfig.tablename;
if (!isTableExists(db, false, tableName)) {
printLog("【New Table】" + tableName);
continue;
}
try {
tempTableName = daoConfig.tablename.concat("_TEMP");
StringBuilder dropTableStringBuilder = new StringBuilder();
dropTableStringBuilder.append("DROP TABLE IF EXISTS ").append(tempTableName).append(";");
db.execSQL(dropTableStringBuilder.toString());
StringBuilder insertTableStringBuilder = new StringBuilder();
insertTableStringBuilder.append("CREATE TEMPORARY TABLE ").append(tempTableName);
insertTableStringBuilder.append(" AS SELECT * FROM ").append(tableName).append(";");
db.execSQL(insertTableStringBuilder.toString());
printLog("【Table】" + tableName +"\n ---Columns-->"+getColumnsStr(daoConfig));
printLog("【Generate temp table】" + tempTableName);
} catch (SQLException e) {
Log.e(TAG, "【Failed to generate temp table】" + tempTableName, e);
}
}
}
private static boolean isTableExists(Database db, boolean isTemp, String tableName) {
if (db == null || TextUtils.isEmpty(tableName)) {
return false;
}
String dbName = isTemp ? SQLITE_TEMP_MASTER : SQLITE_MASTER;
String sql = "SELECT COUNT(*) FROM " + dbName + " WHERE type = ? AND name = ?";
Cursor cursor=null;
int count = 0;
try {
cursor = db.rawQuery(sql, new String[]{"table", tableName});
if (cursor == null || !cursor.moveToFirst()) {
return false;
}
count = cursor.getInt(0);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (cursor != null)
cursor.close();
}
return count > 0;
}
private static String getColumnsStr(DaoConfig daoConfig) {
if (daoConfig == null) {
return "no columns";
}
StringBuilder builder = new StringBuilder();
for (int i = 0; i < daoConfig.allColumns.length; i++) {
builder.append(daoConfig.allColumns[i]);
builder.append(",");
}
if (builder.length() > 0) {
builder.deleteCharAt(builder.length() - 1);
}
return builder.toString();
}
private static void dropAllTables(Database db, boolean ifExists, @NonNull Class extends AbstractDao, ?>>... daoClasses) {
reflectMethod(db, "dropTable", ifExists, daoClasses);
printLog("【Drop all table】");
}
private static void createAllTables(Database db, boolean ifNotExists, @NonNull Class extends AbstractDao, ?>>... daoClasses) {
reflectMethod(db, "createTable", ifNotExists, daoClasses);
printLog("【Create all table】");
}
/**
* dao class already define the sql exec method, so just invoke it
*/
private static void reflectMethod(Database db, String methodName, boolean isExists, @NonNull Class extends AbstractDao, ?>>... daoClasses) {
if (daoClasses.length < 1) {
return;
}
try {
for (Class cls : daoClasses) {
Method method = cls.getDeclaredMethod(methodName, Database.class, boolean.class);
method.invoke(null, db, isExists);
}
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
private static void restoreData(Database 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");
if (!isTableExists(db, true, tempTableName)) {
continue;
}
try {
// get all columns from tempTable, take careful to use the columns list
List columns = getColumns(db, tempTableName);
ArrayList properties = new ArrayList<>(columns.size());
for (int j = 0; j < daoConfig.properties.length; j++) {
String columnName = daoConfig.properties[j].columnName;
if (columns.contains(columnName)) {
properties.add(columnName);
}
}
if (properties.size() > 0) {
final String columnSQL = TextUtils.join(",", properties);
StringBuilder insertTableStringBuilder = new StringBuilder();
insertTableStringBuilder.append("INSERT INTO ").append(tableName).append(" (");
insertTableStringBuilder.append(columnSQL);
insertTableStringBuilder.append(") SELECT ");
insertTableStringBuilder.append(columnSQL);
insertTableStringBuilder.append(" FROM ").append(tempTableName).append(";");
db.execSQL(insertTableStringBuilder.toString());
printLog("【Restore data】 to " + tableName);
}
StringBuilder dropTableStringBuilder = new StringBuilder();
dropTableStringBuilder.append("DROP TABLE ").append(tempTableName);
db.execSQL(dropTableStringBuilder.toString());
printLog("【Drop temp table】" + tempTableName);
} catch (SQLException e) {
Log.e(TAG, "【Failed to restore data from temp table 】" + tempTableName, e);
}
}
}
private static List getColumns(Database db, String tableName) {
List columns = null;
Cursor cursor = null;
try {
cursor = db.rawQuery("SELECT * FROM " + tableName + " limit 0", null);
if (null != cursor && cursor.getColumnCount() > 0) {
columns = Arrays.asList(cursor.getColumnNames());
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (cursor != null)
cursor.close();
if (null == columns)
columns = new ArrayList<>();
}
return columns;
}
private static void printLog(String info){
if(DEBUG){
Log.d(TAG, info);
}
}
}
然后创建自定义的更新数据库类继承DaoMaster.OpenHelper
**
* Created by wbxu on 2017/6/19.
* 自定义 MySQLiteOpenHelper集成 DaoMaster.OpenHelper 重写更新数据库的方法
* 当app下的build.gradle 的schemaVersion数据库的版本号改变时,,创建数据库会调用onUpgrade更细数据库的方法
*/
public class MySQLiteOpenHelper extends DaoMaster.OpenHelper{
/**
*
* @param context 上下文
* @param name 原来定义的数据库的名字 新旧数据库一致
* @param factory 可以null
*/
public MySQLiteOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory) {
super(context, name, factory);
}
/**
*
* @param db
* @param oldVersion
* @param newVersion
* 更新数据库的时候自己调用
*/
@Override
public void onUpgrade(Database db, int oldVersion, int newVersion) {
Log.d("flag","-----调用了");
//具体的数据转移在MigrationHelper2类中
/**
* 将db传入 将gen目录下的所有的Dao.类传入
*/
MigrationHelper2.migrate(db,FruitDao.class, AnimalsDao.class, PeoreDao.class);
}
}
使用方法:
1当新建一个表就是新建一个bean 然后build makeProject 会在gen生成对应的dao文件 将类名传入MigrationHelper2.migrate(db,FruitDao.class, AnimalsDao.class, PeoreDao.class);这个更新的方法里
2更改app下build.gradle的数据库的版本号
//初始化greendao基本信息
greendao{
schemaVersion 4
daoPackage 'com.example.wbxu.mygreendaodemo.gen'
targetGenDir 'src/main/java'
}
3调用让其更新
在想要更新的地方如mainActivity 或 Application 更新数据库
//传入参数二是新旧的数据库名字需要一致
MySQLiteOpenHelper o=new MySQLiteOpenHelper(this,"MyGreenDb.db",null);
DaoMaster daoMaster = new DaoMaster(o.getWritableDatabase());
源码下载:http://download.csdn.net/detail/bskfnvjtlyzmv867/9835023