美文网首页
数据库操作能力 -- GreenDao -- 2

数据库操作能力 -- GreenDao -- 2

作者: TomyZhang | 来源:发表于2020-01-09 10:43 被阅读0次

    七、数据库的升级

    GreenDao的OpenHelper下有个onUpgrade(Database db, int oldVersion, int newVersion)方法,当设置的数据库版本改变时,在数据库初始化的时候就会回调到这个方法,我们可以通过继承OpenHelper重写onUpgrade方法来实现数据库更新操作。

    数据库的升级思路:

    • 创建临时表TMP_,复制原来的数据库到临时表中。
    • 删除之前的原表。
    • 创建新表。
    • 将临时表中的数据复制到新表中,最后将TMP_表删除掉。
    //build.gradle(module)
    apply plugin: 'com.android.application'
    apply plugin: 'org.greenrobot.greendao' // apply plugin
    
    android {
        compileSdkVersion 29
        buildToolsVersion "29.0.0"
        defaultConfig {
            applicationId "com.example.sourcecodetest"
            minSdkVersion 19
            targetSdkVersion 29
            versionCode 1
            versionName "1.0"
            testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
        }
        buildTypes {
            release {
                minifyEnabled false
                proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
            }
        }
    }
    
    dependencies {
        implementation fileTree(dir: 'libs', include: ['*.jar'])
        implementation 'androidx.appcompat:appcompat:1.1.0'
        implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
        testImplementation 'junit:junit:4.12'
        androidTestImplementation 'androidx.test.ext:junit:1.1.1'
        androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
    
        implementation 'org.greenrobot:greendao:3.2.2' // add library
    }
    
    greendao {
        schemaVersion 5 //数据库版本号,原本为3改为5,用于测试数据库升级
        daoPackage 'com.example.sourcecodetest.database'
        //设置DaoMaster、DaoSession、Dao包名
        targetGenDir 'src/main/java' //设置DaoMaster、DaoSession、Dao目录,请注意,这里路径用 / 不要用 .
        generateTests false //设置为true以自动生成单元测试
        targetGenDirTests 'src/main/java' //应存储生成的单元测试的基本目录。默认为src/androidTest/java
    }
    
    //MyApplication
    public class MyApplication extends Application {
        private static final String TAG = "MyApplication";
        private DaoSession daoSession;
    
        @Override
        public void onCreate() {
            super.onCreate();
            Log.d(TAG, "zwm, onCreate");
            initGreenDao();
        }
    
        /**
         * 初始化GreenDao,直接在Application中进行初始化操作
         */
        private void initGreenDao() {
            Log.d(TAG, "zwm, initGreenDao");
            //DaoMaster.DevOpenHelper helper = new DaoMaster.DevOpenHelper(this, "tomorrow.db");
            MyDaoMaster helper = new MyDaoMaster(this, "tomorrow.db"); //自定义DaoMaster.OpenHelper,用于处理数据库升级
            SQLiteDatabase db = helper.getWritableDatabase();
            DaoMaster daoMaster = new DaoMaster(db);
            daoSession = daoMaster.newSession();
        }
    
        public DaoSession getDaoSession() {
            return daoSession;
        }
    }
    
    //MyDaoMaster
    public class MyDaoMaster extends DaoMaster.OpenHelper {
        private static final String TAG = "MyDaoMaster";
    
        public MyDaoMaster(Context context, String name) {
            super(context, name);
        }
    
        public MyDaoMaster(Context context, String name, SQLiteDatabase.CursorFactory factory) {
            super(context, name, factory);
        }
    
        @Override
        public void onUpgrade(Database db, int oldVersion, int newVersion) {
            super.onUpgrade(db, oldVersion, newVersion);
            Log.d(TAG, "zwm, onUpgrade oldVersion: " + oldVersion + " newVersion: " + newVersion);
            MigrationHelper.migrate(db, new MigrationHelper.ReCreateAllTableListener() {
                @Override
                public void onCreateAllTables(Database db, boolean ifNotExists) {
                    Log.d(TAG, "zwm, onCreateAllTables, ifNotExists: " + ifNotExists);
                    DaoMaster.createAllTables(db, ifNotExists);
                }
                @Override
                public void onDropAllTables(Database db, boolean ifExists) {
                    Log.d(TAG, "zwm, onDropAllTables, ifExists: " + ifExists);
                    DaoMaster.dropAllTables(db, ifExists);
                }
            }, StudentDao.class, TeacherDao.class, StudentAndTeacherBeanDao.class);
        }
    }
    
    //MigrationHelper
    public final 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";
    
        private static WeakReference<ReCreateAllTableListener> weakListener;
    
        public interface ReCreateAllTableListener{
            void onCreateAllTables(Database db, boolean ifNotExists);
            void onDropAllTables(Database db, boolean ifExists);
        }
    
        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(SQLiteDatabase db, ReCreateAllTableListener listener, Class<? extends AbstractDao<?, ?>>... daoClasses) {
            weakListener = new WeakReference<>(listener);
            migrate(db, daoClasses);
        }
    
        public static void migrate(Database database, ReCreateAllTableListener listener, Class<? extends AbstractDao<?, ?>>... daoClasses) {
            weakListener = new WeakReference<>(listener);
            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");
    
            ReCreateAllTableListener listener = null;
            if (weakListener != null) {
                listener = weakListener.get();
            }
    
            if (listener != null) {
                listener.onDropAllTables(database, true);
                printLog("【Drop all table by listener】");
                listener.onCreateAllTables(database, false);
                printLog("【Create all table by listener】");
            } else {
                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 by reflect】");
        }
    
        private static void createAllTables(Database db, boolean ifNotExists, @NonNull Class<? extends AbstractDao<?, ?>>... daoClasses) {
            reflectMethod(db, "createTable", ifNotExists, daoClasses);
            printLog("【Create all table by reflect】");
        }
    
        /**
         * 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<TableInfo> newTableInfos = TableInfo.getTableInfo(db, tableName);
                    List<TableInfo> tempTableInfos = TableInfo.getTableInfo(db, tempTableName);
                    ArrayList<String> selectColumns = new ArrayList<>(newTableInfos.size());
                    ArrayList<String> intoColumns = new ArrayList<>(newTableInfos.size());
                    for (TableInfo tableInfo : tempTableInfos) {
                        if (newTableInfos.contains(tableInfo)) {
                            String column = '`' + tableInfo.name + '`';
                            intoColumns.add(column);
                            selectColumns.add(column);
                        }
                    }
                    // NOT NULL columns list
                    for (TableInfo tableInfo : newTableInfos) {
                        if (tableInfo.notnull && !tempTableInfos.contains(tableInfo)) {
                            String column = '`' + tableInfo.name + '`';
                            intoColumns.add(column);
    
                            String value;
                            if (tableInfo.dfltValue != null) {
                                value = "'" + tableInfo.dfltValue + "' AS ";
                            } else {
                                value = "'' AS ";
                            }
                            selectColumns.add(value + column);
                        }
                    }
    
                    if (intoColumns.size() != 0) {
                        StringBuilder insertTableStringBuilder = new StringBuilder();
                        insertTableStringBuilder.append("REPLACE INTO ").append(tableName).append(" (");
                        insertTableStringBuilder.append(TextUtils.join(",", intoColumns));
                        insertTableStringBuilder.append(") SELECT ");
                        insertTableStringBuilder.append(TextUtils.join(",", selectColumns));
                        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<String> getColumns(Database 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) {
                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, "zwm, " + info);
            }
        }
    
        private static class TableInfo {
            int cid;
            String name;
            String type;
            boolean notnull;
            String dfltValue;
            boolean pk;
    
            @Override
            public boolean equals(Object o) {
                return this == o
                        || o != null
                        && getClass() == o.getClass()
                        && name.equals(((TableInfo) o).name);
            }
    
            @Override
            public String toString() {
                return "TableInfo{" +
                        "cid=" + cid +
                        ", name='" + name + '\'' +
                        ", type='" + type + '\'' +
                        ", notnull=" + notnull +
                        ", dfltValue='" + dfltValue + '\'' +
                        ", pk=" + pk +
                        '}';
            }
    
            private static List<TableInfo> getTableInfo(Database db, String tableName) {
                String sql = "PRAGMA table_info(" + tableName + ")";
                printLog(sql);
                Cursor cursor = db.rawQuery(sql, null);
                if (cursor == null)
                    return new ArrayList<>();
                TableInfo tableInfo;
                List<TableInfo> tableInfos = new ArrayList<>();
                while (cursor.moveToNext()) {
                    tableInfo = new TableInfo();
                    tableInfo.cid = cursor.getInt(0);
                    tableInfo.name = cursor.getString(1);
                    tableInfo.type = cursor.getString(2);
                    tableInfo.notnull = cursor.getInt(3) == 1;
                    tableInfo.dfltValue = cursor.getString(4);
                    tableInfo.pk = cursor.getInt(5) == 1;
                    tableInfos.add(tableInfo);
                    // printLog(tableName + ":" + tableInfo);
                }
                cursor.close();
                return tableInfos;
            }
        }
    }
    
    //Student
    @Entity
    public class Student {
        @Id(autoincrement = true)
        private Long id;
    
        @Unique
        private long studentNo; //学号
    
        private int age; //年龄
    
        private String telPhone; //手机号
    
        private String sex; //性别
    
        private String name; //姓名
    
        private  String address; //家庭住址
    
        private String schoolName; //学校名字
    
        private String grade; //几年级
    
        private boolean addNewField; //增加的新列,用于测试数据库升级
    
        @ToMany
        @JoinEntity(entity = StudentAndTeacherBean.class,sourceProperty = "studentId",targetProperty = "teacherId")
        List<Teacher> teacherList;
    }
    
    //MainActivity
    public class MainActivity extends AppCompatActivity {
        private static final String TAG = "MainActivity";
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            Log.d(TAG, "zwm, onCreate");
    
            //insert(); //插入数据后注释掉,用于测试数据库升级
            List<Student> list = loadStudents();
            for(Student student : list) {
                Log.d(TAG, "zwm, student NO." + student.getStudentNo() + ", _id: " + student.getId() + ", age: " + student.getAge() + ", name: " + student.getName());
                Log.d(TAG, "zwm, student newField: " + student.getAddNewField());
                List<Teacher> teacherList = student.getTeacherList();
                Log.d(TAG, "zwm, teacherList.size: " + teacherList.size());
                if(teacherList != null && teacherList.size() > 0) {
                    for(Teacher teacher : teacherList) {
                        Log.d(TAG, "zwm, teacher NO." + teacher.getTeacherNo() + ", _id: " + teacher.getId() + ", age: " + teacher.getAge() + ", name: " + teacher.getName());
                    }
                }
            }
    
            List<Teacher> list2 = loadTeachers();
            for(Teacher teacher : list2) {
                Log.d(TAG, "zwm, teacher NO." + teacher.getTeacherNo() + ", _id: " + teacher.getId() + ", age: " + teacher.getAge() + ", name: " + teacher.getName());
                List<Student> studentList = teacher.getStudentList();
                Log.d(TAG, "zwm, studentList.size: " + studentList.size());
                if(studentList != null && studentList.size() > 0) {
                    for(Student student : studentList) {
                        Log.d(TAG, "zwm, student NO." + student.getStudentNo() + ", _id: " + student.getId() + ", age: " + student.getAge() + ", name: " + student.getName());
                    }
                }
            }
        }
    
        public void insert() {
            Log.d(TAG, "zwm, insert");
            DaoSession daoSession = ((MyApplication) getApplication()).getDaoSession();
            Student student = new Student();
            student.setStudentNo(5551);
            student.setAge(18);
            student.setTelPhone("5524307");
            student.setName("学生1");
            student.setSex("男");
            student.setAddress("广州");
            student.setGrade("一");
            student.setSchoolName("大学");
            daoSession.insert(student);
    
            Student student2 = new Student();
            student2.setStudentNo(5552);
            student2.setAge(19);
            student2.setTelPhone("5524308");
            student2.setName("学生2");
            student2.setSex("男");
            student2.setAddress("深圳");
            student2.setGrade("二");
            student2.setSchoolName("大学");
            daoSession.insert(student2);
    
            Student student3 = new Student();
            student3.setStudentNo(5553);
            student3.setAge(20);
            student3.setTelPhone("5524309");
            student3.setName("学生3");
            student3.setSex("男");
            student3.setAddress("北京");
            student3.setGrade("三");
            student3.setSchoolName("大学");
            daoSession.insert(student3);
    
            Teacher teacher1 = new Teacher();
            teacher1.setTeacherNo(9991);
            teacher1.setAge(28);
            teacher1.setTelPhone("9924307");
            teacher1.setName("教师1");
            teacher1.setSex("男");
            teacher1.setSubject("语文");
            teacher1.setSchoolName("大学");
            daoSession.insert(teacher1);
    
            Teacher teacher2 = new Teacher();
            teacher2.setTeacherNo(9992);
            teacher2.setAge(29);
            teacher2.setTelPhone("9924308");
            teacher2.setName("教师2");
            teacher2.setSex("男");
            teacher2.setSubject("数学");
            teacher2.setSchoolName("大学");
            daoSession.insert(teacher2);
    
            Teacher teacher3 = new Teacher();
            teacher3.setTeacherNo(9993);
            teacher3.setAge(30);
            teacher3.setTelPhone("9924309");
            teacher3.setName("教师3");
            teacher3.setSex("男");
            teacher3.setSubject("英语");
            teacher3.setSchoolName("大学");
            daoSession.insert(teacher3);
    
            StudentAndTeacherBean studentAndTeacher = new StudentAndTeacherBean();
            studentAndTeacher.setStudentId(Long.valueOf(1));
            studentAndTeacher.setTeacherId(Long.valueOf(1));
            daoSession.insert(studentAndTeacher);
    
            StudentAndTeacherBean studentAndTeacher2 = new StudentAndTeacherBean();
            studentAndTeacher2.setStudentId(Long.valueOf(1));
            studentAndTeacher2.setTeacherId(Long.valueOf(2));
            daoSession.insert(studentAndTeacher2);
    
            StudentAndTeacherBean studentAndTeacher3 = new StudentAndTeacherBean();
            studentAndTeacher3.setStudentId(Long.valueOf(2));
            studentAndTeacher3.setTeacherId(Long.valueOf(1));
            daoSession.insert(studentAndTeacher3);
    
            StudentAndTeacherBean studentAndTeacher4 = new StudentAndTeacherBean();
            studentAndTeacher4.setStudentId(Long.valueOf(2));
            studentAndTeacher4.setTeacherId(Long.valueOf(3));
            daoSession.insert(studentAndTeacher4);
    
            StudentAndTeacherBean studentAndTeacher5 = new StudentAndTeacherBean();
            studentAndTeacher5.setStudentId(Long.valueOf(3));
            studentAndTeacher5.setTeacherId(Long.valueOf(1));
            daoSession.insert(studentAndTeacher5);
    
            StudentAndTeacherBean studentAndTeacher6 = new StudentAndTeacherBean();
            studentAndTeacher6.setStudentId(Long.valueOf(3));
            studentAndTeacher6.setTeacherId(Long.valueOf(2));
            daoSession.insert(studentAndTeacher6);
    
            StudentAndTeacherBean studentAndTeacher7 = new StudentAndTeacherBean();
            studentAndTeacher7.setStudentId(Long.valueOf(3));
            studentAndTeacher7.setTeacherId(Long.valueOf(3));
            daoSession.insert(studentAndTeacher7);
        }
    
        public List<Student> loadStudents(){
            Log.d(TAG, "zwm, loadStudents");
            DaoSession daoSession = ((MyApplication) getApplication()).getDaoSession();
            List<Student> students = daoSession.loadAll(Student.class);
            return students;
        }
    
        public List<Teacher> loadTeachers(){
            Log.d(TAG, "zwm, loadTeachers");
            DaoSession daoSession = ((MyApplication) getApplication()).getDaoSession();
            List<Teacher> teachers = daoSession.loadAll(Teacher.class);
            return teachers;
        }
    }
    
    //输出log
    2020-01-08 19:45:42.461 29277-29277/com.example.sourcecodetest D/MyApplication: zwm, onCreate
    2020-01-08 19:45:42.461 29277-29277/com.example.sourcecodetest D/MyApplication: zwm, initGreenDao
    2020-01-08 19:45:42.889 29277-29277/com.example.sourcecodetest D/MainActivity: zwm, onCreate
    2020-01-08 19:45:42.889 29277-29277/com.example.sourcecodetest D/MainActivity: zwm, insert
    2020-01-08 19:45:43.046 29277-29277/com.example.sourcecodetest D/MainActivity: zwm, loadStudents
    2020-01-08 19:45:43.051 29277-29277/com.example.sourcecodetest D/MainActivity: zwm, student NO.5551, _id: 1, age: 18, name: 学生1
    2020-01-08 19:45:43.051 29277-29277/com.example.sourcecodetest D/MainActivity: zwm, student newField: false
    2020-01-08 19:45:43.061 29277-29277/com.example.sourcecodetest D/MainActivity: zwm, teacherList.size: 2
    2020-01-08 19:45:43.061 29277-29277/com.example.sourcecodetest D/MainActivity: zwm, teacher NO.9991, _id: 1, age: 28, name: 教师1
    2020-01-08 19:45:43.062 29277-29277/com.example.sourcecodetest D/MainActivity: zwm, teacher NO.9992, _id: 2, age: 29, name: 教师2
    2020-01-08 19:45:43.062 29277-29277/com.example.sourcecodetest D/MainActivity: zwm, student NO.5552, _id: 2, age: 19, name: 学生2
    2020-01-08 19:45:43.062 29277-29277/com.example.sourcecodetest D/MainActivity: zwm, student newField: false
    2020-01-08 19:45:43.067 29277-29277/com.example.sourcecodetest D/MainActivity: zwm, teacherList.size: 2
    2020-01-08 19:45:43.068 29277-29277/com.example.sourcecodetest D/MainActivity: zwm, teacher NO.9991, _id: 1, age: 28, name: 教师1
    2020-01-08 19:45:43.068 29277-29277/com.example.sourcecodetest D/MainActivity: zwm, teacher NO.9993, _id: 3, age: 30, name: 教师3
    2020-01-08 19:45:43.068 29277-29277/com.example.sourcecodetest D/MainActivity: zwm, student NO.5553, _id: 3, age: 20, name: 学生3
    2020-01-08 19:45:43.069 29277-29277/com.example.sourcecodetest D/MainActivity: zwm, student newField: false
    2020-01-08 19:45:43.072 29277-29277/com.example.sourcecodetest D/MainActivity: zwm, teacherList.size: 3
    2020-01-08 19:45:43.072 29277-29277/com.example.sourcecodetest D/MainActivity: zwm, teacher NO.9991, _id: 1, age: 28, name: 教师1
    2020-01-08 19:45:43.072 29277-29277/com.example.sourcecodetest D/MainActivity: zwm, teacher NO.9992, _id: 2, age: 29, name: 教师2
    2020-01-08 19:45:43.072 29277-29277/com.example.sourcecodetest D/MainActivity: zwm, teacher NO.9993, _id: 3, age: 30, name: 教师3
    2020-01-08 19:45:43.072 29277-29277/com.example.sourcecodetest D/MainActivity: zwm, loadTeachers
    2020-01-08 19:45:43.076 29277-29277/com.example.sourcecodetest D/MainActivity: zwm, teacher NO.9991, _id: 1, age: 28, name: 教师1
    2020-01-08 19:45:43.080 29277-29277/com.example.sourcecodetest D/MainActivity: zwm, studentList.size: 3
    2020-01-08 19:45:43.080 29277-29277/com.example.sourcecodetest D/MainActivity: zwm, student NO.5551, _id: 1, age: 18, name: 学生1
    2020-01-08 19:45:43.080 29277-29277/com.example.sourcecodetest D/MainActivity: zwm, student NO.5552, _id: 2, age: 19, name: 学生2
    2020-01-08 19:45:43.080 29277-29277/com.example.sourcecodetest D/MainActivity: zwm, student NO.5553, _id: 3, age: 20, name: 学生3
    2020-01-08 19:45:43.080 29277-29277/com.example.sourcecodetest D/MainActivity: zwm, teacher NO.9992, _id: 2, age: 29, name: 教师2
    2020-01-08 19:45:43.084 29277-29277/com.example.sourcecodetest D/MainActivity: zwm, studentList.size: 2
    2020-01-08 19:45:43.085 29277-29277/com.example.sourcecodetest D/MainActivity: zwm, student NO.5551, _id: 1, age: 18, name: 学生1
    2020-01-08 19:45:43.085 29277-29277/com.example.sourcecodetest D/MainActivity: zwm, student NO.5553, _id: 3, age: 20, name: 学生3
    2020-01-08 19:45:43.085 29277-29277/com.example.sourcecodetest D/MainActivity: zwm, teacher NO.9993, _id: 3, age: 30, name: 教师3
    2020-01-08 19:45:43.088 29277-29277/com.example.sourcecodetest D/MainActivity: zwm, studentList.size: 2
    2020-01-08 19:45:43.088 29277-29277/com.example.sourcecodetest D/MainActivity: zwm, student NO.5552, _id: 2, age: 19, name: 学生2
    2020-01-08 19:45:43.088 29277-29277/com.example.sourcecodetest D/MainActivity: zwm, student NO.5553, _id: 3, age: 20, name: 学生3
    2020-01-08 19:49:37.030 30214-30214/com.example.sourcecodetest D/MyApplication: zwm, onCreate
    2020-01-08 19:49:37.030 30214-30214/com.example.sourcecodetest D/MyApplication: zwm, initGreenDao
    2020-01-08 19:49:37.153 30214-30214/com.example.sourcecodetest D/MyDaoMaster: zwm, onUpgrade oldVersion: 3 newVersion: 5
    2020-01-08 19:49:37.154 30214-30214/com.example.sourcecodetest D/MigrationHelper: zwm, 【Generate temp table】start
    2020-01-08 19:49:37.167 30214-30214/com.example.sourcecodetest D/MigrationHelper: zwm, 【Table】STUDENT
         ---Columns-->_id,STUDENT_NO,AGE,TEL_PHONE,SEX,NAME,ADDRESS,SCHOOL_NAME,GRADE,ADD_NEW_FIELD
    2020-01-08 19:49:37.167 30214-30214/com.example.sourcecodetest D/MigrationHelper: zwm, 【Generate temp table】STUDENT_TEMP
    2020-01-08 19:49:37.173 30214-30214/com.example.sourcecodetest D/MigrationHelper: zwm, 【Table】TEACHER
         ---Columns-->_id,TEACHER_NO,AGE,SEX,TEL_PHONE,NAME,SCHOOL_NAME,SUBJECT
    2020-01-08 19:49:37.174 30214-30214/com.example.sourcecodetest D/MigrationHelper: zwm, 【Generate temp table】TEACHER_TEMP
    2020-01-08 19:49:37.186 30214-30214/com.example.sourcecodetest D/MigrationHelper: zwm, 【Table】STUDENT_AND_TEACHER_BEAN
         ---Columns-->_id,STUDENT_ID,TEACHER_ID
    2020-01-08 19:49:37.186 30214-30214/com.example.sourcecodetest D/MigrationHelper: zwm, 【Generate temp table】STUDENT_AND_TEACHER_BEAN_TEMP
    2020-01-08 19:49:37.186 30214-30214/com.example.sourcecodetest D/MigrationHelper: zwm, 【Generate temp table】complete
    2020-01-08 19:49:37.186 30214-30214/com.example.sourcecodetest D/MyDaoMaster: zwm, onDropAllTables, ifExists: true
    2020-01-08 19:49:37.195 30214-30214/com.example.sourcecodetest D/MigrationHelper: zwm, 【Drop all table by listener】
    2020-01-08 19:49:37.196 30214-30214/com.example.sourcecodetest D/MyDaoMaster: zwm, onCreateAllTables, ifNotExists: false
    2020-01-08 19:49:37.202 30214-30214/com.example.sourcecodetest D/MigrationHelper: zwm, 【Create all table by listener】
    2020-01-08 19:49:37.202 30214-30214/com.example.sourcecodetest D/MigrationHelper: zwm, 【Restore data】start
    2020-01-08 19:49:37.205 30214-30214/com.example.sourcecodetest D/MigrationHelper: zwm, PRAGMA table_info(STUDENT)
    2020-01-08 19:49:37.208 30214-30214/com.example.sourcecodetest D/MigrationHelper: zwm, PRAGMA table_info(STUDENT_TEMP)
    2020-01-08 19:49:37.212 30214-30214/com.example.sourcecodetest D/MigrationHelper: zwm, 【Restore data】 to STUDENT
    2020-01-08 19:49:37.213 30214-30214/com.example.sourcecodetest D/MigrationHelper: zwm, 【Drop temp table】STUDENT_TEMP
    2020-01-08 19:49:37.216 30214-30214/com.example.sourcecodetest D/MigrationHelper: zwm, PRAGMA table_info(TEACHER)
    2020-01-08 19:49:37.220 30214-30214/com.example.sourcecodetest D/MigrationHelper: zwm, PRAGMA table_info(TEACHER_TEMP)
    2020-01-08 19:49:37.228 30214-30214/com.example.sourcecodetest D/MigrationHelper: zwm, 【Restore data】 to TEACHER
    2020-01-08 19:49:37.230 30214-30214/com.example.sourcecodetest D/MigrationHelper: zwm, 【Drop temp table】TEACHER_TEMP
    2020-01-08 19:49:37.233 30214-30214/com.example.sourcecodetest D/MigrationHelper: zwm, PRAGMA table_info(STUDENT_AND_TEACHER_BEAN)
    2020-01-08 19:49:37.237 30214-30214/com.example.sourcecodetest D/MigrationHelper: zwm, PRAGMA table_info(STUDENT_AND_TEACHER_BEAN_TEMP)
    2020-01-08 19:49:37.241 30214-30214/com.example.sourcecodetest D/MigrationHelper: zwm, 【Restore data】 to STUDENT_AND_TEACHER_BEAN
    2020-01-08 19:49:37.242 30214-30214/com.example.sourcecodetest D/MigrationHelper: zwm, 【Drop temp table】STUDENT_AND_TEACHER_BEAN_TEMP
    2020-01-08 19:49:37.242 30214-30214/com.example.sourcecodetest D/MigrationHelper: zwm, 【Restore data】complete
    2020-01-08 19:49:37.591 30214-30214/com.example.sourcecodetest D/MainActivity: zwm, onCreate
    2020-01-08 19:49:37.592 30214-30214/com.example.sourcecodetest D/MainActivity: zwm, loadStudents
    2020-01-08 19:49:37.598 30214-30214/com.example.sourcecodetest D/MainActivity: zwm, student NO.5551, _id: 1, age: 18, name: 学生1
    2020-01-08 19:49:37.598 30214-30214/com.example.sourcecodetest D/MainActivity: zwm, student newField: false
    2020-01-08 19:49:37.608 30214-30214/com.example.sourcecodetest D/MainActivity: zwm, teacherList.size: 2
    2020-01-08 19:49:37.608 30214-30214/com.example.sourcecodetest D/MainActivity: zwm, teacher NO.9991, _id: 1, age: 28, name: 教师1
    2020-01-08 19:49:37.608 30214-30214/com.example.sourcecodetest D/MainActivity: zwm, teacher NO.9992, _id: 2, age: 29, name: 教师2
    2020-01-08 19:49:37.608 30214-30214/com.example.sourcecodetest D/MainActivity: zwm, student NO.5552, _id: 2, age: 19, name: 学生2
    2020-01-08 19:49:37.608 30214-30214/com.example.sourcecodetest D/MainActivity: zwm, student newField: false
    2020-01-08 19:49:37.612 30214-30214/com.example.sourcecodetest D/MainActivity: zwm, teacherList.size: 2
    2020-01-08 19:49:37.612 30214-30214/com.example.sourcecodetest D/MainActivity: zwm, teacher NO.9991, _id: 1, age: 28, name: 教师1
    2020-01-08 19:49:37.612 30214-30214/com.example.sourcecodetest D/MainActivity: zwm, teacher NO.9993, _id: 3, age: 30, name: 教师3
    2020-01-08 19:49:37.612 30214-30214/com.example.sourcecodetest D/MainActivity: zwm, student NO.5553, _id: 3, age: 20, name: 学生3
    2020-01-08 19:49:37.612 30214-30214/com.example.sourcecodetest D/MainActivity: zwm, student newField: false
    2020-01-08 19:49:37.616 30214-30214/com.example.sourcecodetest D/MainActivity: zwm, teacherList.size: 3
    2020-01-08 19:49:37.617 30214-30214/com.example.sourcecodetest D/MainActivity: zwm, teacher NO.9991, _id: 1, age: 28, name: 教师1
    2020-01-08 19:49:37.617 30214-30214/com.example.sourcecodetest D/MainActivity: zwm, teacher NO.9992, _id: 2, age: 29, name: 教师2
    2020-01-08 19:49:37.617 30214-30214/com.example.sourcecodetest D/MainActivity: zwm, teacher NO.9993, _id: 3, age: 30, name: 教师3
    2020-01-08 19:49:37.618 30214-30214/com.example.sourcecodetest D/MainActivity: zwm, loadTeachers
    2020-01-08 19:49:37.623 30214-30214/com.example.sourcecodetest D/MainActivity: zwm, teacher NO.9991, _id: 1, age: 28, name: 教师1
    2020-01-08 19:49:37.628 30214-30214/com.example.sourcecodetest D/MainActivity: zwm, studentList.size: 3
    2020-01-08 19:49:37.632 30214-30214/com.example.sourcecodetest D/MainActivity: zwm, student NO.5551, _id: 1, age: 18, name: 学生1
    2020-01-08 19:49:37.632 30214-30214/com.example.sourcecodetest D/MainActivity: zwm, student NO.5552, _id: 2, age: 19, name: 学生2
    2020-01-08 19:49:37.633 30214-30214/com.example.sourcecodetest D/MainActivity: zwm, student NO.5553, _id: 3, age: 20, name: 学生3
    2020-01-08 19:49:37.633 30214-30214/com.example.sourcecodetest D/MainActivity: zwm, teacher NO.9992, _id: 2, age: 29, name: 教师2
    2020-01-08 19:49:37.637 30214-30214/com.example.sourcecodetest D/MainActivity: zwm, studentList.size: 2
    2020-01-08 19:49:37.637 30214-30214/com.example.sourcecodetest D/MainActivity: zwm, student NO.5551, _id: 1, age: 18, name: 学生1
    2020-01-08 19:49:37.637 30214-30214/com.example.sourcecodetest D/MainActivity: zwm, student NO.5553, _id: 3, age: 20, name: 学生3
    2020-01-08 19:49:37.637 30214-30214/com.example.sourcecodetest D/MainActivity: zwm, teacher NO.9993, _id: 3, age: 30, name: 教师3
    2020-01-08 19:49:37.641 30214-30214/com.example.sourcecodetest D/MainActivity: zwm, studentList.size: 2
    2020-01-08 19:49:37.641 30214-30214/com.example.sourcecodetest D/MainActivity: zwm, student NO.5552, _id: 2, age: 19, name: 学生2
    2020-01-08 19:49:37.641 30214-30214/com.example.sourcecodetest D/MainActivity: zwm, student NO.5553, _id: 3, age: 20, name: 学生3
    

    自定义SQLiteOpenHelper处理数据库升级(用于参考)

    //MusicDBHelper
    final class MusicDBHelper extends SQLiteOpenHelper {
    
        private static final String TAG = MusicProvider.class.getSimpleName();
    
        final Context mContext;
    
        /*
         * naming style 50 001 OS version local version.
         */
        public static final int DATABASE_VERSION = 20091;
    
        private static volatile MusicDBHelper sInstance;
    
        public static synchronized MusicDBHelper getInstance(Context context) {
            if (sInstance == null) {
                synchronized (MusicDBHelper.class) {
                    if (sInstance == null) {
                        sInstance = new MusicDBHelper(context);
                    }
                }
            }
            return sInstance;
        }
    
        private MusicDBHelper(Context context) {
            super(context, MusicDBInfo.PRIMARY_DATABASE_NAME, null, DATABASE_VERSION);
            mContext = context;
            iLog.d("MusicDBHelper", "()");
        }
    
        @Override
        public void onCreate(final SQLiteDatabase db) {
            iLog.d("MusicDBHelper", "onCreate");
            updateDatabase(mContext, db, 0, DATABASE_VERSION);
        }
    
        @Override
        public void onUpgrade(final SQLiteDatabase db, final int oldVersion, final int newVersion) {
            iLog.d("MusicDBHelper",
                    "onUpgrade : oldVersion = " + oldVersion + ", newVersion = " + newVersion);
            updateDatabase(mContext, db, oldVersion, newVersion);
        }
    
        /**
         * This method takes care of updating all the tables in the database to the
         * current version, creating them if necessary.
         *
         * @param db Database
         */
        private static void updateDatabase(Context context, SQLiteDatabase db, int fromVersion,
                int toVersion) {
    
            iLog.d(TAG, String.format(Locale.US, "updateDatabase fromVersion[%d],  toVersion[%d])",
                    fromVersion, toVersion));
    
            if (fromVersion > toVersion) {
                iLog.e(TAG, "Illegal update request: can't downgrade from " + fromVersion + " to " +
                        toVersion + ". Did you forget to wipe data?");
                throw new IllegalArgumentException();
            }
    
            if (fromVersion < 1) {
                // create audio_meta table
                // createAudioTable(db);
                createDLNATable(db);
            }
    
            if (fromVersion < 10001) {
                // Drop audio View for Store. From this verion, only use audio_meta
                // table.
                db.execSQL("DROP VIEW IF EXISTS audio");
                db.execSQL("DROP TABLE IF EXISTS album_art");
                db.execSQL("DROP VIEW IF EXISTS audio_with_albumart");
                db.execSQL("DROP VIEW IF EXISTS album_info");
                db.execSQL("DROP VIEW IF EXISTS artist_info");
                db.execSQL("DROP VIEW IF EXISTS music_folders_view");
                db.execSQL("DROP VIEW IF EXISTS searchhelpertitle");
                db.execSQL("DROP TABLE IF EXISTS audio_playlists");
                db.execSQL("DROP TABLE IF EXISTS audio_playlists_map");
                db.execSQL("DROP TABLE IF EXISTS audio_playlists_map_cache");
                db.execSQL("DROP TABLE IF EXISTS download_queue");
                db.execSQL("DROP TABLE IF EXISTS dlna_dms_contents_table");
                db.execSQL("DROP TABLE IF EXISTS inventory");
                db.execSQL("DROP TABLE IF EXISTS remote_songs");
                db.execSQL("DROP VIEW IF EXISTS remote_songs_view");
    
                // for removing useless column
                // db.execSQL("CREATE TABLE IF NOT EXISTS audio_meta2 ("
                // + MusicDBInfo.AUDIO_TABLE_COLUMNS_DEFINITION_V1 + ");");
                // // copy data from old table
                // db.execSQL("INSERT OR REPLACE INTO audio_meta2 ("
                // + MusicDBInfo.AUDIO_TABLE_COLUMNS + ") SELECT "
                // + MusicDBInfo.AUDIO_TABLE_COLUMNS + " FROM audio_meta;");
                db.execSQL("DROP TABLE IF EXISTS audio_meta");
                // db.execSQL("ALTER TABLE audio_meta2 RENAME TO audio_meta;");
            }
    
            // 1st release's db version is 20061
            if (fromVersion < 20061) {
                // For base table
                createAudioTable(db);
                createPlaylistTable(db);
    
                createMusicDBInfoTable(db);
    
                // For Online
                createOnlineTable(db);
    
                // For CardView
                createMusicCacheMapTable(db);
            }
    
            if (fromVersion < 20062) {
                db.execSQL("AlTER TABLE " + MusicDBInfo.AUDIO_PLAYLIST_TABLE_NAME +
                        " ADD COLUMN server_id INTEGER;");
                db.execSQL("AlTER TABLE " + MusicDBInfo.AUDIO_PLAYLIST_TABLE_NAME +
                        " ADD COLUMN sync_state INTEGER;");
                db.execSQL("AlTER TABLE " + MusicDBInfo.AUDIO_PLAYLIST_TABLE_NAME +
                        " ADD COLUMN track_sync_state INTEGER;");
            }
    
            if (fromVersion < 20064) {
                // create audio_meta_helper table to sync local contents.
                db.execSQL("DROP TABLE IF EXISTS audio_meta_helper");
                db.execSQL("CREATE TABLE audio_meta_helper AS SELECT * FROM audio_meta WHERE _id < 1");
            }
    
            if (fromVersion < 20065) {
                db.execSQL("DROP TABLE IF EXISTS audio_meta_helper");
            }
    
            if (fromVersion < 20066) {
                db.execSQL("DROP TABLE IF EXISTS " + OnlineTracks.MAP_TABLE_NAME);
                db.execSQL("CREATE TABLE IF NOT EXISTS " + OnlineTracks.MAP_TABLE_NAME + " (" +
                        OnlineTracks.SCHEMA_COLUMNS_DEFINITION + ");");
            }
    
            if (fromVersion < 20067) {
                db.execSQL("DROP TABLE IF EXISTS " + OnlineBanner.TABLE_NAME);
                db.execSQL("CREATE TABLE IF NOT EXISTS " + OnlineBanner.TABLE_NAME + " (" +
                        OnlineBanner.SCHEMA_COLUMNS_DEFINITION + ");");
            }
    
            if (fromVersion < 20068) {
                createMusicDBInfoTable(db);
            }
    
            if (fromVersion < 20069) {
                // recreate online topic
                db.execSQL("DROP TABLE IF EXISTS " + OnlineTopics.TABLE_NAME);
                db.execSQL("CREATE TABLE IF NOT EXISTS " + OnlineTopics.TABLE_NAME + " (" +
                        OnlineTopics.SCHEMA_COLUMNS_DEFINITION + ");");
            }
    
            if (fromVersion < 20070) {
                db.execSQL("DROP TABLE IF EXISTS " + OnlineBanner.TABLE_NAME);
                db.execSQL("CREATE TABLE IF NOT EXISTS " + OnlineBanner.TABLE_NAME + " (" +
                        OnlineBanner.SCHEMA_COLUMNS_DEFINITION + ");");
            }
    
            if (fromVersion < 20071) {
                createMusicDBInfoTable(db);
                db.execSQL("INSERT INTO " + MusicDBInfo.DBSyncInfo.TABLE_NAME + " values('" +
                        MusicDBInfo.DBSyncInfo.CP_MEDIA_PROVIDER + "', '" +
                        String.valueOf(System.currentTimeMillis()) + "', '" +
                        new SimpleDateFormat("MM-dd hh:mm:ss.SSS").format(new Date()).toString() +
                        "', '0', '', '" + Locale.getDefault().toString() + "');");
            }
    
            if (fromVersion < 20072) {
                db.execSQL("DROP TABLE IF EXISTS " + OnlineRank.TABLE_NAME);
                db.execSQL("CREATE TABLE IF NOT EXISTS " + OnlineRank.TABLE_NAME + " (" +
                        OnlineRank.SCHEMA_COLUMNS_DEFINITION + ");");
            }
    
            if (fromVersion < 20073) {
                createRadioCategory(db);
            }
    
            if (fromVersion < 20074) {
                createDbIndex(db);
            }
    
            if (fromVersion < 20075) {
                db.execSQL("DELETE FROM smusic_db_info WHERE " +
                        "sync_content_type = 'online_ultimate_radio_category';");
                db.execSQL("DROP TABLE IF EXISTS " + OnlineRadioCategory.TABLE_NAME);
                db.execSQL("CREATE TABLE IF NOT EXISTS " + OnlineRadioCategory.TABLE_NAME + " (" +
                        OnlineRadioCategory.SCHEMA_COLUMNS_DEFINITION + ");");
            }
    
            if (fromVersion < 20076) {
                if (AppFeatures.REGIONAL_CHN_PINYIN_ENABLED) {
                    try {
                        db.execSQL("ALTER TABLE audio_meta ADD COLUMN title_pinyin TEXT;");
                        db.execSQL(
                                "ALTER TABLE audio_meta ADD COLUMN genre_name_pinyin TEXT default '<unknown>';");
                        db.execSQL(
                                "ALTER TABLE audio_meta ADD COLUMN composer_pinyin TEXT default '<unknown>';");
                        db.execSQL("ALTER TABLE audio_meta ADD COLUMN _display_name_pinyin TEXT;");
                        db.execSQL(
                                "ALTER TABLE audio_meta ADD COLUMN bucket_display_name_pinyin TEXT;");
    
                        db.execSQL(
                                "ALTER TABLE audio_meta ADD COLUMN artist_pinyin TEXT default '<unknown>';");
                        db.execSQL(
                                "ALTER TABLE audio_meta ADD COLUMN album_pinyin TEXT default '<unknown>';");
    
                        db.execSQL("ALTER TABLE audio_meta ADD COLUMN artist_search_key TEXT;");
                        db.execSQL("ALTER TABLE audio_meta ADD COLUMN album_search_key TEXT;");
                        db.execSQL("ALTER TABLE audio_meta ADD COLUMN title_search_key TEXT;");
    
                        db.execSQL("ALTER TABLE audio_playlists ADD COLUMN name_pinyin TEXT;");
                    } catch (SQLiteException e) {
                        iLog.e(TAG, "duplicate column :" + e.toString());
                    }
    
                    db.execSQL("UPDATE audio_meta SET date_modified = 0 WHERE content_location = 1;");
                }
            }
    
            if (fromVersion < 20078) {
                // constraint is changed - artist_id -> (artist_id, artist_category_id)
                db.execSQL("DROP TABLE IF EXISTS " + OnlineArtists.TABLE_NAME);
                db.execSQL("CREATE TABLE IF NOT EXISTS " + OnlineArtists.TABLE_NAME + " (" +
                        OnlineArtists.SCHEMA_COLUMNS_DEFINITION + ");");
            }
    
            if (fromVersion < 20079) {
                // For local view
    
                createArtistMapView(db);
    
                createSearchHelperTitleView(db);
            }
    
            if (fromVersion < 20080) {
                db.execSQL("DROP TABLE IF EXISTS " + MusicDBInfo.AUDIO_PLAYLISTS_MAP_CACHE_TABLE_NAME);
                db.execSQL("CREATE TABLE IF NOT EXISTS " +
                        MusicDBInfo.AUDIO_PLAYLISTS_MAP_CACHE_TABLE_NAME + " (" +
                        MusicDBInfo.PLAYLIST_MAP_CACHE_TABLE_COLUMNS_DEFINITION + ");");
            }
    
            if (fromVersion < 20081) {
                createOnlineFmCategory(db);
            }
    
            if (fromVersion < 20083) {
                recreateTableWithCpAttrsColumn(db);
    
                createAlbumInfoView(db);
                createArtistInfoView(db);
                createGenresInfoView(db);
                createFolderInfoView(db);
                createComposerInfoView(db);
                createSearchView(db);
            }
    
            if (fromVersion < 20084) {
                db.execSQL("update audio_meta SET date_modified = 0");
    
                // @formatter:off
                // Cleans up when an audio file is deleted
                db.execSQL("CREATE TRIGGER IF NOT EXISTS audio_meta_cleanup DELETE ON audio_meta "
                    + "BEGIN "
                    + "  DELETE FROM audio_playlists_map WHERE audio_id = old._id;"
                    + "END");
    
                // for categorized tracks trigger.
                // Cleans up when an audio file is deleted
                db.execSQL("CREATE TRIGGER IF NOT EXISTS audio_meta_categorized_tracks_map_trigger DELETE ON audio_meta "
                    + "BEGIN "
                    + "  DELETE FROM " + OnlineTracks.MAP_TABLE_NAME
                    + " WHERE audio_id = old._id;"
                    + "END");
                // @formatter:on
            }
    
            if (fromVersion < 20085) {
                db.execSQL(
                        "DELETE FROM audio_playlists_map WHERE audio_id NOT IN (SELECT _id FROM audio_meta)");
            }
    
            if (fromVersion < 20086) {
                db.execSQL("DROP TABLE IF EXISTS online_cache_tracks");
            }
    
            if (fromVersion < 20087) {
                createDownloadTable(db);
            }
    
            if (fromVersion < 20088) {
                db.execSQL("AlTER TABLE " + MusicDBInfo.AUDIO_TABLE_NAME +
                        " ADD COLUMN drm_type INTEGER;");
            }
    
            if (fromVersion < 20089) {
                // streaming cache table has been move to external streaming cache db.
                db.execSQL("DROP TABLE IF EXISTS streaming_cache_table");
            }
    
            if (fromVersion < 20090) {
                MusicSyncService.sync(context, MusicSyncService.EVENT_SYNC_DOWNLOADED);
            }
    
            if (fromVersion < 20091) {
                createAlbumInfoView(db);
                createSearchView(db);
            }
        }
    
        private static void createPlaylistTable(SQLiteDatabase db) {
            db.execSQL("DROP TABLE IF EXISTS " + MusicDBInfo.AUDIO_PLAYLIST_TABLE_NAME);
            db.execSQL("DROP TABLE IF EXISTS " + MusicDBInfo.AUDIO_PLAYLISTS_MAP_TABLE_NAME);
    
            // Contains audio playlist definitions
            db.execSQL("CREATE TABLE IF NOT EXISTS " + MusicDBInfo.AUDIO_PLAYLIST_TABLE_NAME + " (" +
                    MusicDBInfo.PLAYLIST_TABLE_COLUMNS_DEFINITION + ");");
    
            // Contains mappings between audio playlists and audio files
            db.execSQL(
                    "CREATE TABLE IF NOT EXISTS " + MusicDBInfo.AUDIO_PLAYLISTS_MAP_TABLE_NAME + " (" +
                            MusicDBInfo.PLAYLIST_MAP_TABLE_COLUMNS_DEFINITION + ");");
    
            // @formatter:off
            // Cleans up when an audio playlist is deleted
            db.execSQL("CREATE TRIGGER IF NOT EXISTS audio_playlists_cleanup DELETE ON audio_playlists "
                    + "BEGIN "
                    + "  DELETE FROM audio_playlists_map WHERE playlist_id = old._id;"
                    + "  SELECT _DELETE_FILE(old._data);"
                    + "END");
    
            // Cleans up when an audio file is deleted
            db.execSQL("CREATE TRIGGER IF NOT EXISTS audio_meta_cleanup DELETE ON audio_meta "
                    + "BEGIN "
                    + "  DELETE FROM audio_playlists_map WHERE audio_id = old._id;"
                    + "END");
            // @formatter:on
        }
    
        private static void createMusicCacheMapTable(SQLiteDatabase db) {
            db.execSQL("DROP TABLE IF EXISTS " + MusicDBInfo.MusicCacheMap.MAP_TABLE_NAME);
            db.execSQL("CREATE TABLE IF NOT EXISTS " + MusicDBInfo.MusicCacheMap.MAP_TABLE_NAME + " (" +
                    MusicDBInfo.MusicCacheMap.SCHEMA_COLUMNS_DEFINITION_V1 + ");");
        }
    
        private static void createDLNATable(SQLiteDatabase db) {
            // create all share table
            db.execSQL("DROP TABLE IF EXISTS " + MusicDBInfo.DLNA_TABLE_NAME);
            db.execSQL("CREATE TABLE " + MusicDBInfo.DLNA_TABLE_NAME + " (" +
                    MusicDBInfo.DLNA_TABLE_COLUMNS_DEFINITION + ");");
            // create all share open intent table
            db.execSQL("DROP TABLE IF EXISTS " + MusicDBInfo.DLNA_OPEN_INTENT_CONTENTS_TABLE_NAME);
            db.execSQL("CREATE TABLE " + MusicDBInfo.DLNA_OPEN_INTENT_CONTENTS_TABLE_NAME + " (" +
                    MusicDBInfo.DLNA_TABLE_COLUMNS_DEFINITION + ");");
            // create all share provider table
            db.execSQL("DROP TABLE IF EXISTS " + MusicDBInfo.DLNA_PROVIDER_TABLE_NAME);
            db.execSQL("CREATE TABLE " + MusicDBInfo.DLNA_PROVIDER_TABLE_NAME + " (" +
                    MusicDBInfo.DLNA_PROVIDER_TABLE_COLUMNS_DEFINITION + ");");
            // create all share avplayer table
            db.execSQL("DROP TABLE IF EXISTS " + MusicDBInfo.DLNA_AVPLAYER_TABLE_NAME);
            db.execSQL("CREATE TABLE " + MusicDBInfo.DLNA_AVPLAYER_TABLE_NAME + " (" +
                    MusicDBInfo.DLNA_AVPLAYER_TABLE_COLUMNS_DEFINITION + ");");
    
            // album art Table for DLNA
            db.execSQL("DROP TABLE IF EXISTS dlna_album_art");
            db.execSQL("CREATE TABLE IF NOT EXISTS dlna_album_art (" + "album_id INTEGER PRIMARY KEY," +
                    "album_art TEXT" + ");");
        }
    
        static final String SEC_PLAYLIST_COLUMNS_ADDED = ",mini_thumb_data";
    
        private static void createAudioTable(SQLiteDatabase db) {
            iLog.d(TAG, "createAudioTable");
    
            db.execSQL("DROP TABLE IF EXISTS " + MusicDBInfo.AUDIO_TABLE_NAME);
            db.execSQL("CREATE TABLE IF NOT EXISTS " + MusicDBInfo.AUDIO_TABLE_NAME + " (" +
                    MusicDBInfo.AUDIO_TABLE_COLUMNS_DEFINITION_V1 + ");");
    
            db.execSQL("DROP VIEW IF EXISTS " + MusicDBInfo.AUDIO_VIEW_NAME);
            db.execSQL("CREATE VIEW " + MusicDBInfo.AUDIO_VIEW_NAME + " AS SELECT * FROM " +
                    MusicDBInfo.AUDIO_TABLE_NAME);
        }
    
        private static void createMusicDBInfoTable(SQLiteDatabase db) {
            db.execSQL("DROP TABLE IF EXISTS " + MusicDBInfo.DBSyncInfo.TABLE_NAME);
            db.execSQL("CREATE TABLE IF NOT EXISTS " + MusicDBInfo.DBSyncInfo.TABLE_NAME + " (" +
                    MusicDBInfo.DBSyncInfo.SCHEMA_COLUMNS_DEFINITION + ");");
        }
    
        private static void createAlbumInfoView(SQLiteDatabase db) {
            iLog.d(TAG, "createAlbumInfoView");
            db.execSQL("DROP VIEW IF EXISTS " + MusicDBInfo.ALBUM_INFO_VIEW_NAME);
            db.execSQL("CREATE VIEW IF NOT EXISTS " + MusicDBInfo.ALBUM_INFO_VIEW_NAME + " AS " +
                    MusicDBInfo.VIEW_ALBUM_INFO_QUERY);
        }
    
        private static void createArtistInfoView(SQLiteDatabase db) {
            iLog.d(TAG, "createArtistInfoView");
            db.execSQL("DROP VIEW IF EXISTS " + MusicDBInfo.ARTIST_INFO_VIEW_NAME);
            db.execSQL("CREATE VIEW IF NOT EXISTS " + MusicDBInfo.ARTIST_INFO_VIEW_NAME + " AS " +
                    MusicDBInfo.VIEW_ARTIST_INFO_QUERY);
        }
    
        private static void createArtistMapView(SQLiteDatabase db) {
            iLog.d(TAG, "createArtistMapView");
            db.execSQL("DROP VIEW IF EXISTS " + MusicDBInfo.ARTIST_ALBUM_MAP_VIEW_NAME);
            db.execSQL("CREATE VIEW IF NOT EXISTS " + MusicDBInfo.ARTIST_ALBUM_MAP_VIEW_NAME + " AS " +
                    MusicDBInfo.VIEW_ARTIST_ALBUM_MAP_QUERY);
        }
    
        private static void createComposerInfoView(SQLiteDatabase db) {
            iLog.d(TAG, "createComposerInfoView");
            db.execSQL("DROP VIEW IF EXISTS " + MusicDBInfo.COMPOSER_INFO_VIEW_NAME);
            db.execSQL("CREATE VIEW IF NOT EXISTS " + MusicDBInfo.COMPOSER_INFO_VIEW_NAME + " AS " +
                    MusicDBInfo.VIEW_COMPOSER_INFO_QUERY);
        }
    
        private static void createFolderInfoView(SQLiteDatabase db) {
            iLog.d(TAG, "createFolderInfoView");
            db.execSQL("DROP VIEW IF EXISTS " + MusicDBInfo.FOLDER_INFO_VIEW_NAME);
            db.execSQL("CREATE VIEW IF NOT EXISTS " + MusicDBInfo.FOLDER_INFO_VIEW_NAME + " AS " +
                    MusicDBInfo.VIEW_FOLDER_INFO_QUERY);
        }
    
        private static void createGenresInfoView(SQLiteDatabase db) {
            iLog.d(TAG, "createFolderInfoView");
            db.execSQL("DROP VIEW IF EXISTS " + MusicDBInfo.GENRES_INFO_VIEW_NAME);
            db.execSQL("CREATE VIEW IF NOT EXISTS " + MusicDBInfo.GENRES_INFO_VIEW_NAME + " AS " +
                    MusicDBInfo.VIEW_GENRE_INFO_QUERY);
        }
    
        private static void createSearchHelperTitleView(SQLiteDatabase db) {
            iLog.d(TAG, "createSearchHelperTitleView");
            db.execSQL("DROP VIEW IF EXISTS " + MusicDBInfo.SEARCH_HELPER_TITLE_VIEW_NAME);
            db.execSQL(
                    "CREATE VIEW IF NOT EXISTS " + MusicDBInfo.SEARCH_HELPER_TITLE_VIEW_NAME + " AS " +
                            MusicDBInfo.VIEW_SEARCH_HELPER_TITLE_QUERY);
        }
    
        private static void createSearchView(SQLiteDatabase db) {
            iLog.d(TAG, "createSearchView");
    
            // artist, album, title integrated search view
            db.execSQL("DROP VIEW IF EXISTS " + MusicDBInfo.SEARCH_VIEW_NAME);
            db.execSQL("CREATE VIEW IF NOT EXISTS " + MusicDBInfo.SEARCH_VIEW_NAME + " AS " +
                    MusicDBInfo.LOCAL_VIEW_SEARCH_QUERY_ARTIST
                    // Local Album union
                    + " UNION ALL " + MusicDBInfo.LOCAL_VIEW_SEARCH_QUERY_ALBUM
                    // Local Title union
                    + " UNION ALL " + MusicDBInfo.LOCAL_VIEW_SEARCH_QUERY_TRACK);
    
            // artist search view
            db.execSQL("DROP VIEW IF EXISTS " + MusicDBInfo.SEARCH_ALBUM_VIEW_NAME);
            db.execSQL("CREATE VIEW IF NOT EXISTS " + MusicDBInfo.SEARCH_ALBUM_VIEW_NAME + " AS " +
                    MusicDBInfo.LOCAL_VIEW_SEARCH_QUERY_ALBUM);
    
            // album search view
            db.execSQL("DROP VIEW IF EXISTS " + MusicDBInfo.SEARCH_ARTIST_VIEW_NAME);
            db.execSQL("CREATE VIEW IF NOT EXISTS " + MusicDBInfo.SEARCH_ARTIST_VIEW_NAME + " AS " +
                    MusicDBInfo.LOCAL_VIEW_SEARCH_QUERY_ARTIST);
    
            // track search view
            db.execSQL("DROP VIEW IF EXISTS " + MusicDBInfo.SEARCH_TRACK_VIEW_NAME);
            db.execSQL("CREATE VIEW IF NOT EXISTS " + MusicDBInfo.SEARCH_TRACK_VIEW_NAME + " AS " +
                    MusicDBInfo.LOCAL_VIEW_SEARCH_QUERY_TRACK);
        }
    
        private static void createOnlineTable(SQLiteDatabase db) {
            iLog.d("TAG", "createOnlineTable");
            // for categorized tracks
            db.execSQL("DROP TABLE IF EXISTS " + OnlineTracks.MAP_TABLE_NAME);
            db.execSQL("CREATE TABLE IF NOT EXISTS " + OnlineTracks.MAP_TABLE_NAME + " (" +
                    OnlineTracks.SCHEMA_COLUMNS_DEFINITION + ");");
    
            // for categorized tracks trigger.
            // Cleans up when an audio file is deleted
            db.execSQL("DROP TRIGGER IF EXISTS audio_meta_categorized_tracks_map_trigger;");
            db.execSQL(
                    "CREATE TRIGGER IF NOT EXISTS audio_meta_categorized_tracks_map_trigger DELETE ON audio_meta " +
                            "BEGIN DELETE FROM " + OnlineTracks.MAP_TABLE_NAME +
                            " WHERE audio_id = old._id; END");
    
            // online artist
            db.execSQL("DROP TABLE IF EXISTS " + OnlineArtists.TABLE_NAME);
            db.execSQL("CREATE TABLE IF NOT EXISTS " + OnlineArtists.TABLE_NAME + " (" +
                    OnlineArtists.SCHEMA_COLUMNS_DEFINITION + ");");
    
            // online album
            db.execSQL("DROP TABLE IF EXISTS " + OnlineAlbums.TABLE_NAME);
            db.execSQL("CREATE TABLE IF NOT EXISTS " + OnlineAlbums.TABLE_NAME + " (" +
                    OnlineAlbums.SCHEMA_COLUMNS_DEFINITION + ");");
    
            // online topic
            db.execSQL("DROP TABLE IF EXISTS " + OnlineTopics.TABLE_NAME);
            db.execSQL("CREATE TABLE IF NOT EXISTS " + OnlineTopics.TABLE_NAME + " (" +
                    OnlineTopics.SCHEMA_COLUMNS_DEFINITION + ");");
        }
    
        /**
         * Before create table, drop table
         */
        private static void createTableInternal(SQLiteDatabase db, String tableName,
                String tableDefinition) {
            db.execSQL("DROP TABLE IF EXISTS " + tableName);
            db.execSQL("CREATE TABLE IF NOT EXISTS " + tableName + " (" + tableDefinition + ");");
        }
    
        private static void createRadioCategory(SQLiteDatabase db) {
            db.execSQL("DROP TABLE IF EXISTS " + OnlineRadioCategory.TABLE_NAME);
            db.execSQL("CREATE TABLE IF NOT EXISTS " + OnlineRadioCategory.TABLE_NAME + " (" +
                    OnlineRadioCategory.SCHEMA_COLUMNS_DEFINITION + ");");
        }
    
        private static void createOnlineFmCategory(SQLiteDatabase db) {
            db.execSQL("DROP TABLE IF EXISTS " + OnlineFmCategory.TABLE_NAME);
            db.execSQL("DROP TABLE IF EXISTS " + OnlineFmRecently.TABLE_NAME);
            db.execSQL("CREATE TABLE IF NOT EXISTS " + OnlineFmCategory.TABLE_NAME + " (" +
                    OnlineFmCategory.SCHEMA_COLUMNS_DEFINITION + ");");
            db.execSQL("CREATE TABLE IF NOT EXISTS " + OnlineFmRecently.TABLE_NAME + " (" +
                    OnlineFmRecently.SCHEMA_COLUMNS_DEFINITION + ");");
        }
    
        private static void createDownloadTable(SQLiteDatabase db) {
            db.execSQL("DROP TABLE IF EXISTS " + MusicDBInfo.Download.TABLE_NAME);
            db.execSQL("CREATE TABLE IF NOT EXISTS " + MusicDBInfo.Download.TABLE_NAME + " (" +
                    MusicDBInfo.Download.TABLE_COLUMNS_DEFINITION + ");");
    
            db.execSQL("DROP TABLE IF EXISTS " + MusicDBInfo.Download.Tracks.TABLE_NAME);
            db.execSQL("CREATE TABLE IF NOT EXISTS " + MusicDBInfo.Download.Tracks.TABLE_NAME + " (" +
                    MusicDBInfo.Download.Tracks.TABLE_COLUMNS_DEFINITION + ");");
    
            db.execSQL(
                    "DROP TRIGGER IF EXISTS " + MusicDBInfo.Download.Trigger.DOWNLOAD_COMPLETE_TRIGGER);
            db.execSQL("CREATE TRIGGER IF NOT EXISTS " +
                    MusicDBInfo.Download.Trigger.DOWNLOAD_COMPLETE_TRIGGER + " " +
                    MusicDBInfo.Download.Trigger.DOWNLOAD_COMPLETE_SCHEMA);
        }
    
        private static void createDbIndex(SQLiteDatabase db) {
            db.execSQL("CREATE INDEX genre_name_index ON audio_meta(genre_name);");
            db.execSQL("CREATE INDEX composer_index ON audio_meta(composer);");
            db.execSQL("CREATE INDEX bucket_id_index ON audio_meta(bucket_id);");
        }
    
        private static void recreateTableWithCpAttrsColumn(SQLiteDatabase db) {
            //@formatter:off
            recreateTableWithCpAttrsColumn(db, MusicDBInfo.AUDIO_TABLE_NAME, MusicDBInfo.AUDIO_TABLE_COLUMNS_DEFINITION_V2, RESERVED_COLUMNS_AUDIO_META, "content_location", "cp_attrs");
            recreateTableWithCpAttrsColumn(db, MusicDBInfo.MusicCacheMap.MAP_TABLE_NAME, MusicDBInfo.MusicCacheMap.SCHEMA_COLUMNS_DEFINITION_V2, RESERVED_COLUMNS_MUSIC_CACHE_MAP, "content_location", "cp_attrs");
            //@formatter:on
        }
    
        private static void recreateTableWithCpAttrsColumn(SQLiteDatabase db, String tableName,
                String columnsDefinition, String reservedColumns, String oldColumnName,
                String newColumnName) {
            //@formatter:off
            String tempTable = tableName + "_temp";
    
            db.execSQL("DROP TABLE IF EXISTS " + tempTable);
            db.execSQL("CREATE TABLE IF NOT EXISTS " + tempTable + " (" + columnsDefinition + ");");
    
            db.execSQL("INSERT INTO " + tempTable + " (" + reservedColumns + ", " + newColumnName + ") " +
                    "SELECT " + reservedColumns + "," +
                    " CASE WHEN " + oldColumnName + " = 1 THEN " + CpAttrs.LOCAL +
                    " WHEN " + oldColumnName + " = 2 THEN " + CpAttrs.ULTIMATE +
                    " WHEN " + oldColumnName + " = 0 THEN " + CpAttrs.LOCAL +
                    " WHEN " + oldColumnName + " = 4 THEN " + CpAttrs.DLNA + " END " +
                    "FROM " + tableName);
            db.execSQL("DROP TABLE " + tableName);
            db.execSQL("ALTER TABLE " + tempTable + " RENAME TO " + tableName);
            //@formatter:on
        }
    
        private static final String RESERVED_COLUMNS_AUDIO_META =
                "_id, source_id, _data, _size, mime_type, title, title_key, _display_name, duration, " +
                        "track, artist_id, artist, artist_key, album_id, album, album_key, album_art, " +
                        "album_artist, genre_name, composer, year, year_name, bucket_id, " +
                        "bucket_display_name, sampling_rate, bit_depth, is_music, is_favorite, " +
                        "is_secretbox, date_added, date_modified, date_updated, recently_played, " +
                        "most_played, provider_id, provider_name, extension, seed, media_type, " +
                        "is_downloaded, exclusivity";
    
        private static final String RESERVED_COLUMNS_MUSIC_CACHE_MAP =
                "_id, category, keyword, title, album_id, played_count, date_added, number_of_tracks, total_duration";
    }
    

    八、数据库的加密

    开发中对于存储于数据库中的敏感数据,我们可以通过对数据库加密来进行保护。GreenDao可以通过SQLCipher来进行加密处理。

    //build.gradle(module)
    apply plugin: 'com.android.application'
    apply plugin: 'org.greenrobot.greendao' // apply plugin
    
    android {
        compileSdkVersion 29
        buildToolsVersion "29.0.0"
        defaultConfig {
            applicationId "com.example.sourcecodetest"
            minSdkVersion 19
            targetSdkVersion 29
            versionCode 1
            versionName "1.0"
            testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
        }
        buildTypes {
            release {
                minifyEnabled false
                proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
            }
        }
    }
    
    dependencies {
        implementation fileTree(dir: 'libs', include: ['*.jar'])
        implementation 'androidx.appcompat:appcompat:1.1.0'
        implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
        testImplementation 'junit:junit:4.12'
        androidTestImplementation 'androidx.test.ext:junit:1.1.1'
        androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
    
        implementation 'org.greenrobot:greendao:3.2.2' // add library
        implementation 'net.zetetic:android-database-sqlcipher:3.5.6' // add sqlcipher library
    }
    
    greendao {
        schemaVersion 7 //数据库版本号
        daoPackage 'com.example.sourcecodetest.database'
        //设置DaoMaster、DaoSession、Dao包名
        targetGenDir 'src/main/java' //设置DaoMaster、DaoSession、Dao目录,请注意,这里路径用 / 不要用 .
        generateTests false //设置为true以自动生成单元测试
        targetGenDirTests 'src/main/java' //应存储生成的单元测试的基本目录。默认为src/androidTest/java
    }
    
    //MyApplication
    public class MyApplication extends Application {
        private static final String TAG = "MyApplication";
        private DaoSession daoSession;
    
        @Override
        public void onCreate() {
            super.onCreate();
            Log.d(TAG, "zwm, onCreate");
            initGreenDao();
        }
    
        /**
         * 初始化GreenDao,直接在Application中进行初始化操作
         */
        private void initGreenDao() {
            Log.d(TAG, "zwm, initGreenDao");
            //MyDaoMaster helper = new MyDaoMaster(this, "tomorrow.db"); //自定义DaoMaster.OpenHelper,用于处理数据库升级
            DaoMaster.DevOpenHelper helper = new DaoMaster.DevOpenHelper(this, "tomorrow.db");
            //SQLiteDatabase db = helper.getWritableDatabase(); //不加密的写法
            Database db = helper.getEncryptedWritableDb("zwm"); //数据库加密密码为“zwm"的写法
            DaoMaster daoMaster = new DaoMaster(db);
            daoSession = daoMaster.newSession();
        }
    
        public DaoSession getDaoSession() {
            return daoSession;
        }
    }
    
    //MainActivity
    public class MainActivity extends AppCompatActivity {
        private static final String TAG = "MainActivity";
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            Log.d(TAG, "zwm, onCreate");
    
            insert(); //插入数据后注释掉,用于测试数据库升级
            List<Student> list = loadStudents();
            for(Student student : list) {
                Log.d(TAG, "zwm, student NO." + student.getStudentNo() + ", _id: " + student.getId() + ", age: " + student.getAge() + ", name: " + student.getName());
                Log.d(TAG, "zwm, student newField: " + student.getAddNewField());
                List<Teacher> teacherList = student.getTeacherList();
                Log.d(TAG, "zwm, teacherList.size: " + teacherList.size());
                if(teacherList != null && teacherList.size() > 0) {
                    for(Teacher teacher : teacherList) {
                        Log.d(TAG, "zwm, teacher NO." + teacher.getTeacherNo() + ", _id: " + teacher.getId() + ", age: " + teacher.getAge() + ", name: " + teacher.getName());
                    }
                }
            }
    
            List<Teacher> list2 = loadTeachers();
            for(Teacher teacher : list2) {
                Log.d(TAG, "zwm, teacher NO." + teacher.getTeacherNo() + ", _id: " + teacher.getId() + ", age: " + teacher.getAge() + ", name: " + teacher.getName());
                List<Student> studentList = teacher.getStudentList();
                Log.d(TAG, "zwm, studentList.size: " + studentList.size());
                if(studentList != null && studentList.size() > 0) {
                    for(Student student : studentList) {
                        Log.d(TAG, "zwm, student NO." + student.getStudentNo() + ", _id: " + student.getId() + ", age: " + student.getAge() + ", name: " + student.getName());
                    }
                }
            }
        }
    
        public void insert() {
            Log.d(TAG, "zwm, insert");
            DaoSession daoSession = ((MyApplication) getApplication()).getDaoSession();
            Student student = new Student();
            student.setStudentNo(5551);
            student.setAge(18);
            student.setTelPhone("5524307");
            student.setName("学生1");
            student.setSex("男");
            student.setAddress("广州");
            student.setGrade("一");
            student.setSchoolName("大学");
            daoSession.insert(student);
    
            Student student2 = new Student();
            student2.setStudentNo(5552);
            student2.setAge(19);
            student2.setTelPhone("5524308");
            student2.setName("学生2");
            student2.setSex("男");
            student2.setAddress("深圳");
            student2.setGrade("二");
            student2.setSchoolName("大学");
            daoSession.insert(student2);
    
            Student student3 = new Student();
            student3.setStudentNo(5553);
            student3.setAge(20);
            student3.setTelPhone("5524309");
            student3.setName("学生3");
            student3.setSex("男");
            student3.setAddress("北京");
            student3.setGrade("三");
            student3.setSchoolName("大学");
            daoSession.insert(student3);
    
            Teacher teacher1 = new Teacher();
            teacher1.setTeacherNo(9991);
            teacher1.setAge(28);
            teacher1.setTelPhone("9924307");
            teacher1.setName("教师1");
            teacher1.setSex("男");
            teacher1.setSubject("语文");
            teacher1.setSchoolName("大学");
            daoSession.insert(teacher1);
    
            Teacher teacher2 = new Teacher();
            teacher2.setTeacherNo(9992);
            teacher2.setAge(29);
            teacher2.setTelPhone("9924308");
            teacher2.setName("教师2");
            teacher2.setSex("男");
            teacher2.setSubject("数学");
            teacher2.setSchoolName("大学");
            daoSession.insert(teacher2);
    
            Teacher teacher3 = new Teacher();
            teacher3.setTeacherNo(9993);
            teacher3.setAge(30);
            teacher3.setTelPhone("9924309");
            teacher3.setName("教师3");
            teacher3.setSex("男");
            teacher3.setSubject("英语");
            teacher3.setSchoolName("大学");
            daoSession.insert(teacher3);
    
            StudentAndTeacherBean studentAndTeacher = new StudentAndTeacherBean();
            studentAndTeacher.setStudentId(Long.valueOf(1));
            studentAndTeacher.setTeacherId(Long.valueOf(1));
            daoSession.insert(studentAndTeacher);
    
            StudentAndTeacherBean studentAndTeacher2 = new StudentAndTeacherBean();
            studentAndTeacher2.setStudentId(Long.valueOf(1));
            studentAndTeacher2.setTeacherId(Long.valueOf(2));
            daoSession.insert(studentAndTeacher2);
    
            StudentAndTeacherBean studentAndTeacher3 = new StudentAndTeacherBean();
            studentAndTeacher3.setStudentId(Long.valueOf(2));
            studentAndTeacher3.setTeacherId(Long.valueOf(1));
            daoSession.insert(studentAndTeacher3);
    
            StudentAndTeacherBean studentAndTeacher4 = new StudentAndTeacherBean();
            studentAndTeacher4.setStudentId(Long.valueOf(2));
            studentAndTeacher4.setTeacherId(Long.valueOf(3));
            daoSession.insert(studentAndTeacher4);
    
            StudentAndTeacherBean studentAndTeacher5 = new StudentAndTeacherBean();
            studentAndTeacher5.setStudentId(Long.valueOf(3));
            studentAndTeacher5.setTeacherId(Long.valueOf(1));
            daoSession.insert(studentAndTeacher5);
    
            StudentAndTeacherBean studentAndTeacher6 = new StudentAndTeacherBean();
            studentAndTeacher6.setStudentId(Long.valueOf(3));
            studentAndTeacher6.setTeacherId(Long.valueOf(2));
            daoSession.insert(studentAndTeacher6);
    
            StudentAndTeacherBean studentAndTeacher7 = new StudentAndTeacherBean();
            studentAndTeacher7.setStudentId(Long.valueOf(3));
            studentAndTeacher7.setTeacherId(Long.valueOf(3));
            daoSession.insert(studentAndTeacher7);
        }
    
        public List<Student> loadStudents(){
            Log.d(TAG, "zwm, loadStudents");
            DaoSession daoSession = ((MyApplication) getApplication()).getDaoSession();
            List<Student> students = daoSession.loadAll(Student.class);
            return students;
        }
    
        public List<Teacher> loadTeachers(){
            Log.d(TAG, "zwm, loadTeachers");
            DaoSession daoSession = ((MyApplication) getApplication()).getDaoSession();
            List<Teacher> teachers = daoSession.loadAll(Teacher.class);
            return teachers;
        }
    }
    
    //输出log
    2020-01-08 20:23:43.476 3853-3853/com.example.sourcecodetest D/MyApplication: zwm, onCreate
    2020-01-08 20:23:43.476 3853-3853/com.example.sourcecodetest D/MyApplication: zwm, initGreenDao
    2020-01-08 20:23:44.113 3853-3853/com.example.sourcecodetest D/MainActivity: zwm, onCreate
    2020-01-08 20:23:44.113 3853-3853/com.example.sourcecodetest D/MainActivity: zwm, insert
    2020-01-08 20:23:44.357 3853-3853/com.example.sourcecodetest D/MainActivity: zwm, loadStudents
    2020-01-08 20:23:44.361 3853-3853/com.example.sourcecodetest D/MainActivity: zwm, student NO.5551, _id: 1, age: 18, name: 学生1
    2020-01-08 20:23:44.361 3853-3853/com.example.sourcecodetest D/MainActivity: zwm, student newField: false
    2020-01-08 20:23:44.369 3853-3853/com.example.sourcecodetest D/MainActivity: zwm, teacherList.size: 2
    2020-01-08 20:23:44.369 3853-3853/com.example.sourcecodetest D/MainActivity: zwm, teacher NO.9991, _id: 1, age: 28, name: 教师1
    2020-01-08 20:23:44.370 3853-3853/com.example.sourcecodetest D/MainActivity: zwm, teacher NO.9992, _id: 2, age: 29, name: 教师2
    2020-01-08 20:23:44.370 3853-3853/com.example.sourcecodetest D/MainActivity: zwm, student NO.5552, _id: 2, age: 19, name: 学生2
    2020-01-08 20:23:44.370 3853-3853/com.example.sourcecodetest D/MainActivity: zwm, student newField: false
    2020-01-08 20:23:44.376 3853-3853/com.example.sourcecodetest D/MainActivity: zwm, teacherList.size: 2
    2020-01-08 20:23:44.376 3853-3853/com.example.sourcecodetest D/MainActivity: zwm, teacher NO.9991, _id: 1, age: 28, name: 教师1
    2020-01-08 20:23:44.376 3853-3853/com.example.sourcecodetest D/MainActivity: zwm, teacher NO.9993, _id: 3, age: 30, name: 教师3
    2020-01-08 20:23:44.377 3853-3853/com.example.sourcecodetest D/MainActivity: zwm, student NO.5553, _id: 3, age: 20, name: 学生3
    2020-01-08 20:23:44.377 3853-3853/com.example.sourcecodetest D/MainActivity: zwm, student newField: false
    2020-01-08 20:23:44.380 3853-3853/com.example.sourcecodetest D/MainActivity: zwm, teacherList.size: 3
    2020-01-08 20:23:44.380 3853-3853/com.example.sourcecodetest D/MainActivity: zwm, teacher NO.9991, _id: 1, age: 28, name: 教师1
    2020-01-08 20:23:44.380 3853-3853/com.example.sourcecodetest D/MainActivity: zwm, teacher NO.9992, _id: 2, age: 29, name: 教师2
    2020-01-08 20:23:44.380 3853-3853/com.example.sourcecodetest D/MainActivity: zwm, teacher NO.9993, _id: 3, age: 30, name: 教师3
    2020-01-08 20:23:44.380 3853-3853/com.example.sourcecodetest D/MainActivity: zwm, loadTeachers
    2020-01-08 20:23:44.384 3853-3853/com.example.sourcecodetest D/MainActivity: zwm, teacher NO.9991, _id: 1, age: 28, name: 教师1
    2020-01-08 20:23:44.389 3853-3853/com.example.sourcecodetest D/MainActivity: zwm, studentList.size: 3
    2020-01-08 20:23:44.389 3853-3853/com.example.sourcecodetest D/MainActivity: zwm, student NO.5551, _id: 1, age: 18, name: 学生1
    2020-01-08 20:23:44.389 3853-3853/com.example.sourcecodetest D/MainActivity: zwm, student NO.5552, _id: 2, age: 19, name: 学生2
    2020-01-08 20:23:44.390 3853-3853/com.example.sourcecodetest D/MainActivity: zwm, student NO.5553, _id: 3, age: 20, name: 学生3
    2020-01-08 20:23:44.390 3853-3853/com.example.sourcecodetest D/MainActivity: zwm, teacher NO.9992, _id: 2, age: 29, name: 教师2
    2020-01-08 20:23:44.393 3853-3853/com.example.sourcecodetest D/MainActivity: zwm, studentList.size: 2
    2020-01-08 20:23:44.394 3853-3853/com.example.sourcecodetest D/MainActivity: zwm, student NO.5551, _id: 1, age: 18, name: 学生1
    2020-01-08 20:23:44.394 3853-3853/com.example.sourcecodetest D/MainActivity: zwm, student NO.5553, _id: 3, age: 20, name: 学生3
    2020-01-08 20:23:44.394 3853-3853/com.example.sourcecodetest D/MainActivity: zwm, teacher NO.9993, _id: 3, age: 30, name: 教师3
    2020-01-08 20:23:44.396 3853-3853/com.example.sourcecodetest D/MainActivity: zwm, studentList.size: 2
    2020-01-08 20:23:44.396 3853-3853/com.example.sourcecodetest D/MainActivity: zwm, student NO.5552, _id: 2, age: 19, name: 学生2
    2020-01-08 20:23:44.397 3853-3853/com.example.sourcecodetest D/MainActivity: zwm, student NO.5553, _id: 3, age: 20, name: 学生3
    
    //数据库文件
    取出数据库文件(tomorrow.db)到电脑本地,无法通过SQLite Expert Professional软件打开,提示数据库文件已经加密了。
    

    九、源码解析

    GreenDao源码解析

    相关文章

      网友评论

          本文标题:数据库操作能力 -- GreenDao -- 2

          本文链接:https://www.haomeiwen.com/subject/fycyactx.html