Android studio,使用greenDao第三方数据库框架操作数据库(二)(升级管理,自定义数据库路径,数据库升级操作)

在网上找了很多资料,终于找到了Greendao数据库自定义路径,以及GreenDao数据库升级操作,避免开发阶段老是删除数据库,增删改查数据库都极其不方便,大部分是借鉴了网上的资料,然后自己做总结。

1,.修改DBUtil工具类,如下:

/**
 * 数据库工具类
 * Created by pc on 2016/11/8.
 */

public class DBUtil {


    public static DaoSession getDaoSession(Context context) {
       /* if (daoSession == null) {
            DaoMaster.OpenHelper openHelper = new DaoMaster.OpenHelper(context, "e6b") {
                @Override
                public void onUpgrade(Database db, int oldVersion, int newVersion) {
                    switch (oldVersion) {
                        case 1:
                            db.beginTransaction();
                            db.execSQL("...");
                            db.setTransactionSuccessful();
                            db.endTransaction();
                            break;
                    }
                }
            };
            SQLiteDatabase db = openHelper.getWritableDatabase();
            DaoMaster daoMaster = new DaoMaster(db);
            daoSession = daoMaster.newSession();*/

        return GreenDaoManager.getInstance().getSession();//换成自定义数据库操作类
    }

}
2.添加几个工具类,GreenDaoManager.java(数据库模式管理类),MySQLiteOpenHelper.java(数据库模式选择类),MigrationHelper.java (数据备份升级类), GreenDaoContext.java (自定义数据库路径操作类)    分别如下:

public class GreenDaoManager {

     private DaoMaster mDaoMaster;
     private DaoSession mDaoSession;
     private static GreenDaoManager mInstance;//单例
     private GreenDaoManager(){
         if(mInstance==null) {
//            DaoMaster.DevOpenHelper devOpenHelper = new
//                    DaoMaster.DevOpenHelper(MyApplication.getContext(), "database_name", null);//此处openhelper为自动生成开发所使用,发布版本需自定义
             MySQLiteOpenHelper devOpenHelper =new MySQLiteOpenHelper(new GreenDaoContext(),"textGreendao.db", null);//GreenDaoContext为创建数据库路径使用

//数据库升级:数据库没有改变,默认1,1     数据库增加字段,删除字段,数据库有改变的,写1,2,表示数据库版本升级,数据库版本升级之后,原本数据库的数据不变
		devOpenHelper.onUpgrade(devOpenHelper.getWritableDatabase(),1,2);//数据库有改动后,不会再崩
mDaoMaster= new DaoMaster(devOpenHelper.getWritableDatabase()); mDaoSession= mDaoMaster.newSession(); } } public static GreenDaoManager getInstance() { if( mInstance== null) { synchronized(GreenDaoManager. class) { //保证异步处理安全操作 if( mInstance== null) { mInstance= new GreenDaoManager(); } } } return mInstance; } public DaoMaster getMaster() { return mDaoMaster; } public DaoSession getSession() { return mDaoSession; } public DaoSession getNewSession() { mDaoSession= mDaoMaster.newSession(); return mDaoSession; }}

public class MySQLiteOpenHelper extends DaoMaster.OpenHelper  {
    public MySQLiteOpenHelper(Context context, String name) {
        super(context, name);
    }

    public MySQLiteOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory) {
        super(context, name, factory);
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
 
  
 
  
	if(oldVersion==newVersion){
    		return;
	}
//数据迁移模块 MigrationHelper. migrate(db, TestInfoDao. class); }}

public class MigrationHelper {
    public static boolean DEBUG = true;
    private static String TAG = "MigrationHelper";
    private static final String SQLITE_MASTER = "sqlite_master";
    private static final String SQLITE_TEMP_MASTER = "sqlite_temp_master";

    public static void migrate(SQLiteDatabase db, Classextends AbstractDao>... daoClasses) {
        Database database = new StandardDatabase(db);

        Log.e("MigrationHelper-->", "【The Old Database Version】" + db.getVersion());
        Log.e("MigrationHelper-->", "【Generate temp table】start");
        generateTempTables(database, daoClasses);
        Log.e("MigrationHelper-->", "【Generate temp table】complete");

        dropAllTables(database, true, daoClasses);
        createAllTables(database, false, daoClasses);

        Log.e("MigrationHelper-->", "【Restore data】start");
        restoreData(database, daoClasses);
        Log.e("MigrationHelper-->", "【Restore data】complete");
    }

    private static void generateTempTables(Database db, Classextends 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)) {//不存在系统表中,表明是新增表,不需要创建临时表
                Log.e("MigrationHelper-->", "【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());
                Log.e("MigrationHelper-->", "【Table】" + tableName + "\n ---Columns-->" + getColumnsStr(daoConfig));
                Log.e("MigrationHelper-->", "【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 Classextends AbstractDao>... daoClasses) {
        reflectMethod(db, "dropTable", ifExists, daoClasses);
        printLog("【Drop all table】");
    }

    private static void createAllTables(Database db, boolean ifNotExists, @NonNull Classextends 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 Classextends 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, Classextends 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);
        }
    }


}

public class GreenDaoContext extends ContextWrapper {

    private String currentUserId = "greendao";//一般用来针对一个用户一个数据库,以免数据混乱问题
    private Context mContext;

    public GreenDaoContext() {
        super(Myapplication.getContext());
        this.mContext = Myapplication.getContext();
//        this.currentUserId = "greendao";//初始化
    }

    /**
     * 获得数据库路径,如果不存在,则创建对象
     *
     * @param dbName
     */
    @Override
    public File getDatabasePath(String dbName) {


        String dbDir = FilePathUtil.getDBDir();//外置sd卡路径
        if (TextUtils.isEmpty(dbDir)){
            dbDir = FilePathUtil.getInnerSDCardPath();//没外置,存内置
        }

        Log.e("SD卡管理:", "dbDir="+dbDir);
            File baseFile = new File(dbDir);
            // 目录不存在则自动创建目录
            if (!baseFile.exists()) {
                baseFile.mkdirs();
                Log.e("SD卡管理:", "dbDir="+dbDir);
            }
            StringBuffer buffer = new StringBuffer();
            buffer.append(baseFile.getPath());
            buffer.append(File.separator);
            //buffer.append(currentUserId);
            dbDir = buffer.toString();// 数据库所在目录
            buffer.append(File.separator);
//        buffer.append(dbName+"_"+currentUserId);//也可以采用此种方式,将用户id与表名联系到一块命名
            buffer.append(dbName);
            String dbPath = buffer.toString();// 数据库路径
            // 判断目录是否存在,不存在则创建该目录
            File dirFile = new File(dbDir);
            if (!dirFile.exists()) {
                dirFile.mkdirs();
                Log.e("SD卡管理:", "dbDir="+dbDir);
            }
            // 数据库文件是否创建成功
            boolean isFileCreateSuccess = false;
            // 判断文件是否存在,不存在则创建该文件
            File dbFile = new File(dbPath);
            if (!dbFile.exists()) {
                try {
                    isFileCreateSuccess = dbFile.createNewFile();// 创建文件
                    Log.e("SD卡管理:", "dbPath="+dbPath);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            } else
                isFileCreateSuccess = true;
            // 返回数据库文件对象
            if (isFileCreateSuccess)
                return dbFile;
            else
                return super.getDatabasePath(dbName);

    }

    /**
     * 重载这个方法,是用来打开SD卡上的数据库的,android 2.3及以下会调用这个方法。
     *
     * @param name
     * @param mode
     * @param factory
     */
    @Override
    public SQLiteDatabase openOrCreateDatabase(String name, int mode,
                                               SQLiteDatabase.CursorFactory factory) {
        SQLiteDatabase result = SQLiteDatabase.openOrCreateDatabase(getDatabasePath(name), factory);
        return result;
    }

    /**
     * Android 4.0会调用此方法获取数据库。
     *
     * @param name
     * @param mode
     * @param factory
     * @param errorHandler
     * @see android.content.ContextWrapper#openOrCreateDatabase(java.lang.String, int,
     * android.database.sqlite.SQLiteDatabase.CursorFactory,
     * android.database.DatabaseErrorHandler)
     */
    @Override
    public SQLiteDatabase openOrCreateDatabase(String name, int mode, SQLiteDatabase.CursorFactory factory,
                                               DatabaseErrorHandler errorHandler) {
        SQLiteDatabase result = SQLiteDatabase.openOrCreateDatabase(getDatabasePath(name), factory);

        return result;
    }

}

最后还是一样的调用DBUtil,获取相应的Dao

TestInfoDao mDao=DBUtil.getDaoSession(context).getTestInfoDao();

不明白的可以看我之前的博客   Android studio,使用greenDao第三方数据库框架操作数据库

联系起来就可以了


我的demo已上传


这样就O啦





我不是个呆若木鸡的小小英

你可能感兴趣的:(数据库)