很久没写博客了,最近一直很忙,没时间整理,一些内容都保存到草稿箱了,但是比较乱,需要整理后才能发,今天抽时间挑出来一篇,全是源码,描述的内容很少(基本没有,除了代码中的一些注解),相信能用到的朋友一看就能明白的;同时也给自己做个记录,方便以后用到直接拿过去就行了。

这篇的内容主要是Android本地存储之GreenDao。因为在开发中难免会有APP版本的升级,增加或者修改内容,这时候本地有保存用到GreenDao数据库的一般升级会把之前保存的数据清空。这篇文章要解决的问题就是在APP版本升级,本地数据库表或者字段有改动的情况下,不清空之前已经保存的数据。废话不多说,下面就直接上代码了:

【注意】:还要注意一点,尽量避免数据库表名有用到数据库的关键字的,如果有用到的就比较麻烦了,需要单独处理。我这里就用到了group关键字,代码里有单独处理的方法,如果你用了其它关键字就仿照我这个来写吧,嘿嘿!你如果有更好的方法顺便告诉我一声哈!

1、新建类

package com.example.test1.db;import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.text.TextUtils;import androidx.annotation.NonNull;import com.example.test1.utils.LoggUtils;import org.greenrobot.greendao.AbstractDao;
import org.greenrobot.greendao.database.Database;
import org.greenrobot.greendao.database.StandardDatabase;
import org.greenrobot.greendao.internal.DaoConfig;import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;/*** Created by WJY.* Date: 2020/8/4* Time: 13:55* Description:兼容旧表性质的 greenDao 数据库升级,不会造成旧表的数据丢失*/
public class GreenDaoCompatibleUpdateHelper {public interface GreenDaoCompatibleUpdateCallBack {void onFinalSuccess();void onFailedLog(String errorMsg);}private static GreenDaoCompatibleUpdateCallBack callBack;@SuppressWarnings("all")public void compatibleUpdate(SQLiteDatabase sqliteDatabase, Class<? extends AbstractDao<?, ?>>... daoClasses) {StandardDatabase db = new StandardDatabase(sqliteDatabase);if (!generateNewTablesIfNotExists_withNoExchangeData(db, daoClasses))    /** 创建之前旧表中不存在的新表 */return;if (!generateTempTables_withExchangeDataFromOldTable(db, daoClasses))    /** 创建中间表 & 把旧表的数据迁移到中间表 */return;if (!dropAllTables(db, true, daoClasses))                         /** 把旧表全部删除 */return;if (!createAllTables_withNoExchangeData(db, false, daoClasses)) /** 创建所有新表 */return;restoreData_fromTempTableToNewTable(db, daoClasses);                     /** 把中间表的数据迁移到新表 & 删除中间表 */if (callBack != null)callBack.onFinalSuccess();callBack = null;}@SuppressWarnings("all")public void compatibleUpdate(StandardDatabase db, Class<? extends AbstractDao<?, ?>>... daoClasses) {if (!generateNewTablesIfNotExists_withNoExchangeData(db, daoClasses))return;if (!generateTempTables_withExchangeDataFromOldTable(db, daoClasses))return;if (!dropAllTables(db, true, daoClasses))return;if (!createAllTables_withNoExchangeData(db, false, daoClasses))return;restoreData_fromTempTableToNewTable(db, daoClasses);if (callBack != null)callBack.onFinalSuccess();callBack = null;}public GreenDaoCompatibleUpdateHelper setCallBack(GreenDaoCompatibleUpdateCallBack callBack1) {callBack = callBack1;return this;}@SafeVarargsprivate static boolean generateNewTablesIfNotExists_withNoExchangeData(StandardDatabase db, Class<? extends AbstractDao<?, ?>>... daoClasses) {return reflectMethod(db, "createTable", true, daoClasses);}@SafeVarargsprivate static boolean generateTempTables_withExchangeDataFromOldTable(StandardDatabase db, Class<? extends AbstractDao<?, ?>>... daoClasses) {try {for (int i = 0; i < daoClasses.length; i++) {DaoConfig daoConfig = new DaoConfig(db, daoClasses[i]);String tableName = daoConfig.tablename;if (tableName.equals("GROUP")){//group是关键字   最好不要用作表名,但是如果吴用了,用中括号[]括起来就好了,括起来后该字段就被转化为了普通的字符串//如果吴用了其他关键字   则在此处处理其他字段tableName = "[GROUP]";}String tempTableName = daoConfig.tablename.concat("_TEMP");StringBuilder insertTableStringBuilder = new StringBuilder();insertTableStringBuilder.append("CREATE TEMP TABLE ").append(tempTableName);insertTableStringBuilder.append(" AS SELECT * FROM ").append(tableName).append(";");LoggUtils.e("cacacaca", "daoConfig="+daoConfig.toString());LoggUtils.e("cacacaca", "tableName="+tableName);LoggUtils.e("cacacaca", "insertTableStringBuilder.toString()="+insertTableStringBuilder.toString());db.execSQL(insertTableStringBuilder.toString());}return true;} catch (Exception e) {if (callBack != null)callBack.onFailedLog("generateTempTables_withExchangeDataFromOldTable ===> " + e.toString());}return false;}@SafeVarargsprivate static boolean dropAllTables(StandardDatabase db, boolean ifExists, @NonNull Class<? extends AbstractDao<?, ?>>... daoClasses) {return reflectMethod(db, "dropTable", ifExists, daoClasses);}@SafeVarargsprivate static boolean createAllTables_withNoExchangeData(StandardDatabase db, boolean ifNotExists, @NonNull Class<? extends AbstractDao<?, ?>>... daoClasses) {return reflectMethod(db, "createTable", ifNotExists, daoClasses);}/*** dao class already define the sql exec method, so just invoke it*/@SafeVarargsprivate static boolean reflectMethod(StandardDatabase db, String methodName, boolean isExists, @NonNull Class<? extends AbstractDao<?, ?>>... daoClasses) {if (daoClasses.length < 1) {if (callBack != null)callBack.onFailedLog("reflectMethod ===> daoClasses.length < 1");return false;}try {for (Class cls : daoClasses) {Method method = cls.getDeclaredMethod(methodName, Database.class, boolean.class);method.invoke(null, db, isExists);}// restoreData_fromTempTableToNewTable// ===>// android.database.sqlite.SQLiteConstraintException: NOT NULL constraint failed: MATTER_USER_BEAN.STATUS (code 1299)return true;} catch (Exception e) {e.printStackTrace();if (callBack != null)callBack.onFailedLog("reflectMethod ===> " + e.toString());}return false;}/*** 把旧表的数据复制到新表,不存在的字段默认值** @param db* @param daoClasses*/@SafeVarargsprivate static void restoreData_fromTempTableToNewTable(StandardDatabase db, Class<? extends AbstractDao<?, ?>>... daoClasses) {try {for (int i = 0; i < daoClasses.length; i++) {DaoConfig daoConfig = new DaoConfig(db, daoClasses[i]);String tableName = daoConfig.tablename;if (tableName.equals("GROUP")){//group是关键字   最好不要用作表名,但是如果吴用了,用中括号[]括起来就好了,括起来后该字段就被转化为了普通的字符串//如果吴用了其他关键字   则在此处处理其他字段tableName = "[GROUP]";}String tempTableName = daoConfig.tablename.concat("_TEMP");// get all columns from tempTable, take careful to use the columns listList<String> columns = getColumns(db, tempTableName);ArrayList<String> 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());}StringBuilder dropTableStringBuilder = new StringBuilder();dropTableStringBuilder.append("DROP TABLE ").append(tempTableName);db.execSQL(dropTableStringBuilder.toString());}} catch (Exception e) {if (callBack != null)callBack.onFailedLog("restoreData_fromTempTableToNewTable ===> " + e.toString());}}private static List<String> getColumns(StandardDatabase db, String tableName) {List<String> 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) {if (callBack != null)callBack.onFailedLog("getColumns ===> " + e.toString());} finally {if (cursor != null)cursor.close();if (null == columns)columns = new ArrayList<>();}return columns;}
}

2、新建MyGreenDaoDbHelper

package com.example.test1.db;import android.content.Context;
import android.database.sqlite.SQLiteDatabase;import com.example.test1.db.gen.DaoMaster;
import com.example.test1.db.gen.GroupDao;
import com.example.test1.db.gen.StudentDao;
import com.example.test1.utils.LoggUtils;import org.greenrobot.greendao.database.Database;/*** Created by WJY.* Date: 2020/8/4* Time: 14:00* Description:*/
public class MyGreenDaoDbHelper extends DaoMaster.DevOpenHelper {public MyGreenDaoDbHelper(Context context, String name) {super(context, name);}public MyGreenDaoDbHelper(Context context, String name, SQLiteDatabase.CursorFactory factory) {super(context, name, factory);}@Override@SuppressWarnings("all")public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {super.onUpgrade(db, oldVersion, newVersion);LoggUtils.e("MyGreenDaoDbHelper", "----" + oldVersion + "---先前和更新之后的版本---" + newVersion + "----");if (oldVersion < newVersion) {LoggUtils.e("MyGreenDaoDbHelper", "进行数据库升级");new GreenDaoCompatibleUpdateHelper().setCallBack(new GreenDaoCompatibleUpdateHelper.GreenDaoCompatibleUpdateCallBack() {@Overridepublic void onFinalSuccess() {LoggUtils.e("MyGreenDaoDbHelper", "进行数据库升级 ===> 成功");}@Overridepublic void onFailedLog(String errorMsg) {LoggUtils.e("MyGreenDaoDbHelper", "升级失败日志 ===> " + errorMsg);}}).compatibleUpdate(db,StudentDao.class, GroupDao.class);LoggUtils.e("MyGreenDaoDbHelper", "进行数据库升级--完成");}}@Overridepublic void onUpgrade(Database db, int oldVersion, int newVersion) {// 不要调用父类的,它默认是先删除全部表再创建// super.onUpgrade(db, oldVersion, newVersion);}
}

3、在MyApplication里初始化

package com.example.test1;import android.app.Application;
import android.content.Context;import com.example.test1.db.MyGreenDaoDbHelper;
import com.example.test1.db.gen.DaoMaster;
import com.example.test1.db.gen.DaoSession;import org.greenrobot.greendao.identityscope.IdentityScopeType;/*** Created by WJY.* Date: 2020/8/4* Time: 19:34* Description:*/
public class MyApplication extends Application {private static MyApplication instance;private static Context context;private static DaoSession mDaoSession;//单例模式中获取唯一的MyApplication实例public static MyApplication getInstance() {if (null == instance) {instance = new MyApplication();}return instance;}@Overridepublic void onCreate() {super.onCreate();context = getApplicationContext();setupDatabase();}/*** 配置数据库*/private void setupDatabase() {//创建数据库shop.dbMyGreenDaoDbHelper helper = new MyGreenDaoDbHelper(this, "checkterminal.db", null);
//        //获取可写数据库
//        SQLiteDatabase db = helper.getWritableDatabase();//获取数据库对象DaoMaster daoMaster = new DaoMaster(helper.getWritableDatabase());//获取dao对象管理者mDaoSession = daoMaster.newSession(IdentityScopeType.None);}public static DaoSession getDaoInstant() {return mDaoSession;}
}

别忘了在app的build.gradle里升级数据库版本,每次数据库有改动这里都要加1。

greendao{schemaVersion 2 // 版本号+1
}

GreenDao 数据库 升级 保留之前数据相关推荐

  1. Android ORM 框架:GreenDao 数据库升级

    本文作者:Speedy CSDN 专栏:blog.csdn.net/speedystone 掘金专栏:juejin.im/user/57e082- 前言 在 Android ORM 框架:GreenD ...

  2. DButils数据库升级不丢失数据

    如果版本升级,表中新增了某个字段,如何在不删除表的情况下顺利过渡,如果不做处理,数据库就会报错,没有新添加的列.修改数据库的创建方式,实现升级接口. 1 db = DbUtils.create(con ...

  3. Android版本升级同时Sqlite数据库的升级及之前数据的保留-转

    http://www.cnblogs.com/wang340/archive/2013/05/06/3063135.html http://www.eoeandroid.com/forum.php?m ...

  4. 如何在升级数据表的同时保留原数据

    一.问题 项目做到后期,或者项目版本升级时,有时不得不更新原来的数据库设计.比如有一张表,可能需要增加字段.修改字段等.在某些情况下,ALTER TABLE命令不能完成这个任务,比如更换主键.这时只能 ...

  5. 数据库篇之[bsp_advertpositions]数据表-BrnShop1.9升级至2.1升级说明(非官方版本)...

    数据库篇之[bsp_advertpositions]数据表 主要描述在数据库方面进行升级(使用前请参照网上商城BrnShop1.9升级至2.1升级说明(非官方版本仅提供技术交流)的使用协议) 主要看下 ...

  6. mysql数据库删除重复的数据只保留一条

    问题引入 假设一个场景,一张用户表,包含 3 个字段:id,identity_id,name. 现在身份证号 identity_id 和姓名 name 有很多重复的数据,需要删除多余数据只保留一条有效 ...

  7. mysql版本升级对数据的影响_MySQL数据库升级的一些坑

    对于商业数据库而言,数据库升级是一个优先级很高的事情,有版本升级路线图,有相应的补丁,而且对于方案还有一系列的演练,陷入是一场硬仗.而在MySQL方向上,升级这件事情就被淡化了许多,好像只能证明它的存 ...

  8. SqlServer清空一个数据库中所有表数据保留表结构

    SqlServer将多行查询结果通过逗号拼接成一个字符串 select stuff((select ','+title from tb for xml path('')),1,1,'') --其中tb ...

  9. oracle 数据库修改数据类型,保留原来数据

    遇到项目,原来是数据类型不能满足当前需求,要保留旧数据的前提下修改(或扩大)某一列的数据类型 在oracle数据库中,有数据的列是不能被修改的,思路是这样的 (1)在原数据表中增加新列,新列的列名只要 ...

最新文章

  1. nicstat命令安装与分析
  2. Python——基础篇
  3. 在php中如何便利字符串,php字符串可以遍历嘛
  4. 你还可以续命几次?回顾DockPanel Suite项目的发展史
  5. 基于External-DNS的多集群Ingress DNS实践
  6. cts(7)---android 8.1 vts环境和测试
  7. 科技部部长:院士头衔不是学术不端挡箭牌!已有多位院士、校长等被“拿下”...
  8. 《操作系统真象还原》——0.17 先有的语言,还是先有的编译器,第1个编译器是怎么产生的...
  9. C语言打印结构体的值,怎么才能把结构体里面的二维数组打印出来?
  10. opencv车牌照识别
  11. Ubuntu安装jdk8
  12. excel求方差和标准差的函数_excel标准差函数是什么?怎么计算?
  13. Java实现数字大写
  14. 15个网站失效死链接检查工具
  15. Windows10 如何清理注册表,教大家清理注册表方法
  16. Jsp之一 WEB应用程序概述
  17. 【golang】处理jpeg图片压缩后方向发生变化问题
  18. 75寸的电视长宽各是多少厘米
  19. Thinkbook14G2ITL笔记本重装系统遇到的问题?
  20. oracle修复工具下载,Oracle数据库恢复工具DataNumen Oracle Recovery

热门文章

  1. python module docs是什么意思_Python Module和Package辨析
  2. 思岚科技发布业内首款激光建图传感器Slamtec Mapper
  3. 张宇考研数学闭关修炼【解析分册】
  4. 致:视频监控、车载导航的用户,听说你想买张流量卡?
  5. (转)爱剪辑学习记录_快速剪辑视频
  6. HEVC-环路滤波 之去块效应滤波
  7. 基于树莓派的语音识别和语音合成
  8. Android中ExpandableListView中嵌套ListView
  9. 微信看看对方是不是把你删除了
  10. 12.03-内存管理_Tagged Pointer