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

数据库操作能力-- Room

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

一、概念

Room是一个对象关系映射(ORM)数据库框架。Room抽象了SQLite的使用,可以在充分利用SQLite的同时访问流畅的数据库。

Room包含三大组件:

  • Database:利用该组件来创建一个数据库持有者。
  • Entity:该组件表示持有数据库行的类。对于每个实体,将会创建一个数据库表来持有他们。
    Entity类中需要映射到表中的字段需要保证外部能够访问。要么把字段设置为public,要么实现字段的getter和setter方法。
  • DAO:该组件表示作为数据访问对象(DAO)的类或接口。DAO是Room的主要组件,负责定义访问数据库的方法。

二、基本使用

1.Insert(插入)

@Insert注解可以设置一个属性:onConflict,默认值是OnConflictStrategy.ABORT,表示当插入有冲突的时候的处理策略。

OnConflictStrategy封装了Room解决冲突的相关策略:

  • OnConflictStrategy.REPLACE:冲突策略是取代旧数据同时继续事务。
  • OnConflictStrategy.ROLLBACK:冲突策略是回滚事务。
  • OnConflictStrategy.ABORT:冲突策略是终止事务。
  • OnConflictStrategy.FAIL:冲突策略是事务失败。
  • OnConflictStrategy.IGNORE:冲突策略是忽略冲突。
@Dao
public interface UserDao {
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    void insertUsers(User... users);
}

当@Insert注解的方法只有一个参数的时候,这个方法也可以返回一个long,当@Insert注解的方法有多个参数的时候,则可以返回long[]或者List<Long>,long都是表示插入的rowId。

2.Update(更新)

当DAO里面的某个方法添加了@Update注解,Room会把对应的参数信息更新到数据库里面去,会根据参数里面的primary key做更新操作。

@Update和@Insert一样也是可以设置onConflict来表明冲突的时候的解决办法。

@Dao
public interface UserDao {
    @Update(onConflict = OnConflictStrategy.REPLACE)
    int updateUsers(User... users);
}

@Update注解的方法也可以返回int变量,表示更新了多少行。

3.Delete(删除)

当DAO里面的某个方法添加了@Delete注解,Room会把对应的参数信息指定的行删除掉,通过参数里面的primary key找到要删除的行。

@Delete也是可以设置onConflict来表明冲突的时候的解决办法。

@Dao
public interface UserDao {
    @Delete
    void deleteUsers(User... users);
}

@Delete对应的方法也是可以设置int返回值来表示删除了多少行。

4.Query(查询)

@Query注解是DAO类中使用的主要注解,它允许对数据库执行读/写操作。@Query在编译的时候会验证准确性,所以如果查询出现问题在编译的时候就会报错。

Room还会验证查询的返回值,如果返回对象中的字段名称与查询响应中的相应列名称不匹配的时候,Room会通过以下两种方式之一提醒:

  • 如果只有一些字段名称匹配,它会发出警告。
  • 如果没有字段名称匹配,它会发生错误。

@Query注解value参数:查询语句,这也是查询操作最关键的部分。

5.Demo

//build.gradle(project)
// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
    repositories {
        google()
        jcenter()
        mavenCentral() // add repository
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:3.2.1'
        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

allprojects {
    repositories {
        google()
        jcenter()
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}

//build.gradle(module)
apply plugin: 'com.android.application'

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'

    // add for room
    implementation "android.arch.persistence.room:runtime:1.1.1"
    // room 配合 RxJava
    implementation "android.arch.persistence.room:rxjava2:1.1.1"
    // annotationProcessor 用于编译期间根据注解(Annotation)获取相关数据
    annotationProcessor 'android.arch.persistence.room:compiler:1.1.1'
}

//AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.sourcecodetest">
    <application
        android:name=".MyApplication"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>

//Student
@Entity
public class Student {
    @PrimaryKey(autoGenerate = true)
    public  int id;

    @Ignore
    public  String secret;

    public  long studentNo; //学号

    public  int age; //年龄

    public  String name; //姓名
}

//StudentDao
@Dao
public interface StudentDao {
    @Query("SELECT * FROM student")
    List<Student> queryAll();

    @Query("SELECT * FROM student WHERE studentNo IN (:studentNos)")
    List<Student> queryByNos(int[] studentNos);

    @Query("SELECT * FROM student WHERE age LIKE :age AND name LIKE :name LIMIT 1")
    Student queryByAgeAndName(int age, String name);

    @Insert
    void insert(Student... students);

    @Update
    void update(Student... students);

    @Delete
    void delete(Student... students);
}

//AppDatabase
@Database(entities = {Student.class}, version = 1)
public abstract class AppDatabase extends RoomDatabase {
    public abstract StudentDao studentDao();
}

//MyApplication
public class MyApplication extends Application {
    private static final String TAG = "MyApplication";
    private AppDatabase db;

    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(TAG, "zwm, onCreate");
        initRoom();
    }

    private void initRoom() {
        db = Room.databaseBuilder(getApplicationContext(), AppDatabase.class, "tomorrow.db").build();
    }

    public AppDatabase getAppDatabase() {
        return db;
    }
}

//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");
        new Thread(new Runnable() {
            @Override
            public void run() {
                test();
            }
        }).start();
    }

    private void test() {
        Log.d(TAG, "zwm, test thread: " + Thread.currentThread().getName());
        StudentDao studentDao = ((MyApplication)getApplication()).getAppDatabase().studentDao();
        Student student = new Student();
        student.studentNo = 10086;
        student.secret = "aaaaa";
        student.age = 18;
        student.name = "中国移动";

        Student student2 = new Student();
        student2.studentNo = 10010;
        student2.secret = "bbbbb";
        student2.age = 19;
        student2.name = "中国联通";

        Student student3 = new Student();
        student3.studentNo = 10000;
        student3.secret = "ccccc";
        student3.age = 20;
        student3.name = "中国电信";

        studentDao.insert(student, student2, student3);
        Log.d(TAG, "zwm, insert");
        List<Student> list = studentDao.queryAll();
        Log.d(TAG, "zwm, queryAll list.size: " + list.size());
        for(Student item : list) {
            Log.d(TAG, "zwm, student id: " + item.id + ", No." + item.studentNo + ", age: " + item.age + ", name: " + item.name + ", secret: " + item.secret);
        }

        list = studentDao.queryByNos(new int[]{10000, 10086});
        Log.d(TAG, "zwm, queryByNos list.size: " + list.size());
        for(Student item : list) {
            Log.d(TAG, "zwm, student id: " + item.id + ", No." + item.studentNo + ", age: " + item.age + ", name: " + item.name + ", secret: " + item.secret);
        }

        Student result = studentDao.queryByAgeAndName(18, "中国移动");
        Log.d(TAG, "zwm, queryByAgeAndName");
        if(result != null) {
            Log.d(TAG, "zwm, student id: " + result.id + ", No." + result.studentNo + ", age: " + result.age + ", name: " + result.name + ", secret: " + result.secret);
        }

        student.id = 1;
        student.age = 28;
        studentDao.update(student);
        Log.d(TAG, "zwm, update");
        list = studentDao.queryAll();
        Log.d(TAG, "zwm, queryAll list.size: " + list.size());
        for(Student item : list) {
            Log.d(TAG, "zwm, student id: " + item.id + ", No." + item.studentNo + ", age: " + item.age + ", name: " + item.name + ", secret: " + item.secret);
        }

        studentDao.delete(student);
        Log.d(TAG, "zwm, delete");
        list = studentDao.queryAll();
        Log.d(TAG, "zwm, queryAll list.size: " + list.size());
        for(Student item : list) {
            Log.d(TAG, "zwm, student id: " + item.id + ", No." + item.studentNo + ", age: " + item.age + ", name: " + item.name + ", secret: " + item.secret);
        }
    }
}

//输出log
2020-01-09 16:30:07.353 9197-9197/com.example.sourcecodetest D/MyApplication: zwm, onCreate
2020-01-09 16:30:07.718 9197-9197/com.example.sourcecodetest D/MainActivity: zwm, onCreate
2020-01-09 16:30:07.721 9197-9286/com.example.sourcecodetest D/MainActivity: zwm, test thread: Thread-6
2020-01-09 16:30:07.871 9197-9286/com.example.sourcecodetest D/MainActivity: zwm, insert
2020-01-09 16:30:07.879 9197-9286/com.example.sourcecodetest D/MainActivity: zwm, queryAll list.size: 3
2020-01-09 16:30:07.879 9197-9286/com.example.sourcecodetest D/MainActivity: zwm, student id: 1, No.10086, age: 18, name: 中国移动, secret: null
2020-01-09 16:30:07.879 9197-9286/com.example.sourcecodetest D/MainActivity: zwm, student id: 2, No.10010, age: 19, name: 中国联通, secret: null
2020-01-09 16:30:07.879 9197-9286/com.example.sourcecodetest D/MainActivity: zwm, student id: 3, No.10000, age: 20, name: 中国电信, secret: null
2020-01-09 16:30:07.884 9197-9286/com.example.sourcecodetest D/MainActivity: zwm, queryByNos list.size: 2
2020-01-09 16:30:07.884 9197-9286/com.example.sourcecodetest D/MainActivity: zwm, student id: 1, No.10086, age: 18, name: 中国移动, secret: null
2020-01-09 16:30:07.884 9197-9286/com.example.sourcecodetest D/MainActivity: zwm, student id: 3, No.10000, age: 20, name: 中国电信, secret: null
2020-01-09 16:30:07.887 9197-9286/com.example.sourcecodetest D/MainActivity: zwm, queryByAgeAndName
2020-01-09 16:30:07.887 9197-9286/com.example.sourcecodetest D/MainActivity: zwm, student id: 1, No.10086, age: 18, name: 中国移动, secret: null
2020-01-09 16:30:07.889 9197-9286/com.example.sourcecodetest D/MainActivity: zwm, update
2020-01-09 16:30:07.900 9197-9286/com.example.sourcecodetest D/MainActivity: zwm, queryAll list.size: 3
2020-01-09 16:30:07.900 9197-9286/com.example.sourcecodetest D/MainActivity: zwm, student id: 1, No.10086, age: 28, name: 中国移动, secret: null
2020-01-09 16:30:07.900 9197-9286/com.example.sourcecodetest D/MainActivity: zwm, student id: 2, No.10010, age: 19, name: 中国联通, secret: null
2020-01-09 16:30:07.900 9197-9286/com.example.sourcecodetest D/MainActivity: zwm, student id: 3, No.10000, age: 20, name: 中国电信, secret: null
2020-01-09 16:30:07.927 9197-9286/com.example.sourcecodetest D/MainActivity: zwm, delete
2020-01-09 16:30:07.938 9197-9286/com.example.sourcecodetest D/MainActivity: zwm, queryAll list.size: 2
2020-01-09 16:30:07.938 9197-9286/com.example.sourcecodetest D/MainActivity: zwm, student id: 2, No.10010, age: 19, name: 中国联通, secret: null
2020-01-09 16:30:07.939 9197-9286/com.example.sourcecodetest D/MainActivity: zwm, student id: 3, No.10000, age: 20, name: 中国电信, secret: null

三、其它用法

@Entity //创建数据表
class User {
    @PrimaryKey //主键
    public int id;

    public String firstName;
    public String lastName;

    @Ignore //不持久化
    Bitmap picture;
}


@Entity(primaryKeys = {"firstName", "lastName"}) //多个主键
class User {
    public String firstName;
    public String lastName;

    @Ignore
    Bitmap picture;
}


@Entity(tableName = "users") //默认情况下Entity类的名字就是表的名字(不区分大小写),这里可以自定义表名
class User {
    ...
}


@Entity(tableName = "users")
class User {
    @PrimaryKey
    public int id;

    @ColumnInfo(name = "first_name") //定义列名
    public String firstName;

    @ColumnInfo(name = "last_name")
    public String lastName;

    @Ignore
    Bitmap picture;
}


@Entity(indices = {@Index({"first_name", "last_name"})}) //索引
class User {
    @PrimaryKey
    public int id;

    @ColumnInfo(name = "first_name")
    public String firstName;

    @ColumnInfo(name = "last_name")
    public String lastName;

    @Ignore
    Bitmap picture;
}


@Entity(indices = {@Index(value = {"first_name", "last_name"}, unique = true)}) //索引和唯一性
class User {
    @PrimaryKey
    public int id;

    @ColumnInfo(name = "first_name")
    public String firstName;

    @ColumnInfo(name = "last_name")
    public String lastName;

    @Ignore
    Bitmap picture;
}


@Entity(foreignKeys = @ForeignKey(entity = User.class,
                                  parentColumns = "id",
                                  childColumns = "user_id")) //外键
class Book {
    @PrimaryKey
    public int bookId;

    public String title;

    @ColumnInfo(name = "user_id")
    public int userId;
}


class Address {
    public String street;
    public String state;
    public String city;

    @ColumnInfo(name = "post_code")
    public int postCode;
}

@Entity //表包含的列有:id,firstName,street,state,city和post_code。
class User {
    @PrimaryKey
    public int id;

    public String firstName;

    @Embedded //代表一个希望分解成一个表中的次级字段的对象
    public Address address;
}


@Dao
public interface MyDao {
    @Query("SELECT * FROM user") //查询语句
    public User[] loadAllUsers();
}


@Dao
public interface MyDao {
    @Query("SELECT * FROM user WHERE age > :minAge") //查询语句
    public User[] loadAllUsersOlderThan(int minAge);
}


@Dao
public interface MyDao {
    @Query("SELECT * FROM user WHERE age BETWEEN :minAge AND :maxAge") //查询语句
    public User[] loadAllUsersBetweenAges(int minAge, int maxAge);

    @Query("SELECT * FROM user WHERE first_name LIKE :search "
           + "OR last_name LIKE :search")
    public List<User> findUserWithName(String search);
}


public class NameTuple {
    @ColumnInfo(name="first_name")
    public String firstName;

    @ColumnInfo(name="last_name")
    public String lastName;
}

@Dao
public interface MyDao {
    @Query("SELECT first_name, last_name FROM user") //查询语句
    public List<NameTuple> loadFullName();
}


@Dao
public interface MyDao {
    @Query("SELECT first_name, last_name FROM user WHERE region IN (:regions)") //查询语句
    public List<NameTuple> loadUsersFromRegions(List<String> regions);
}


//LiveData,当数据更新时UI自动更新
@Dao
public interface MyDao {
    @Query("SELECT first_name, last_name FROM user WHERE region IN (:regions)")
    public LiveData<List<User>> loadUsersFromRegionsSync(List<String> regions);
}


//RxJava,引入android.arch.persistence.room:rxjava2依赖
@Dao
public interface MyDao {
    @Query("SELECT * from user where id = :id LIMIT 1")
    public Flowable<User> loadUserById(int id);
}


//直接游标访问,不建议使用
@Dao
public interface MyDao {
    @Query("SELECT * FROM user WHERE age > :minAge LIMIT 5")
    public Cursor loadRawUsersOlderThan(int minAge);
}


//多表查询
@Dao
public interface MyDao {
    @Query("SELECT * FROM book "
           + "INNER JOIN loan ON loan.book_id = book.id "
           + "INNER JOIN user ON user.id = loan.user_id "
           + "WHERE user.name LIKE :userName")
   public List<Book> findBooksBorrowedByNameSync(String userName);
}


//多表查询
@Dao
public interface MyDao {
   @Query("SELECT user.name AS userName, pet.name AS petName "
          + "FROM user, pet "
          + "WHERE user.id = pet.user_id")
   public LiveData<List<UserPet>> loadUserAndPetNames();

   // You can also define this class in a separate file, as long as you add the
   // "public" access modifier.
   static class UserPet {
       public String userName;
       public String petName;
   }
}


//使用类型转换
Room为原始类型和可选的装箱类型提供嵌入支持。然而,有时你可能使用一个单独存入数据库的自定义数据类型。为了添加这种类型的支持,你可以提供一个把自定义类转化为一个Room能够持久化的已知类型的TypeConverter。

//Converters
//定义了两个函数:一个把Date对象转换为Long对象。另一个逆向转换,从Long到Date。
//因为Room已经知道了如何持久化Long对象,所以它能使用转换器持久化Date类型。
public class Converters {
    private static final String TAG = "Converters";

    @TypeConverter
    public static Date fromTimestamp(Long value) {
        Log.d(TAG, "zwm, fromTimestamp");
        return value == null ? null : new Date(value);
    }

    @TypeConverter
    public static Long dateToTimestamp(Date date) {
        Log.d(TAG, "zwm, dateToTimestamp");
        return date == null ? null : date.getTime();
    }
}

//Student
@Entity
public class Student {
    @PrimaryKey(autoGenerate = true)
    public  int id;

    @Ignore
    public  String secret;

    public  long studentNo; //学号

    public  int age; //年龄

    public  String name; //姓名

    public Date birthday; //生日,Date类型
}

//StudentDao
@Dao
public interface StudentDao {
    @Insert
    void insert(Student... students);

    @Query("SELECT * FROM student")
    List<Student> queryAll();

    @Query("SELECT * FROM student WHERE birthday BETWEEN :from AND :to")
    List<Student> findStudentsBornBetweenDates(Date from, Date to);
}

//AppDatabase
@Database(entities = {Student.class}, version = 1)
@TypeConverters({Converters.class})
public abstract class AppDatabase extends RoomDatabase {
    public abstract StudentDao studentDao();
}

//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");
        new Thread(new Runnable() {
            @Override
            public void run() {
                test();
            }
        }).start();
    }

    private void test() {
        Log.d(TAG, "zwm, test thread: " + Thread.currentThread().getName());
        StudentDao studentDao = ((MyApplication)getApplication()).getAppDatabase().studentDao();
        Student student = new Student();
        student.studentNo = 10086;
        student.secret = "aaaaa";
        student.age = 18;
        student.name = "中国移动";
        student.birthday = strToDate("2016-12-13 07:00:00");

        Student student2 = new Student();
        student2.studentNo = 10010;
        student2.secret = "bbbbb";
        student2.age = 19;
        student2.name = "中国联通";
        student2.birthday = strToDate("2017-12-13 07:00:00");

        Student student3 = new Student();
        student3.studentNo = 10000;
        student3.secret = "ccccc";
        student3.age = 20;
        student3.name = "中国电信";
        student3.birthday = strToDate("2020-12-13 07:00:00");

        studentDao.insert(student, student2, student3);
        Log.d(TAG, "zwm, insert");
        List<Student> list = studentDao.queryAll();
        Log.d(TAG, "zwm, queryAll list.size: " + list.size());
        for(Student item : list) {
            Log.d(TAG, "zwm, student id: " + item.id + ", No." + item.studentNo + ", age: " + item.age + ", name: " + item.name + ", secret: " + item.secret);
        }
        Date from = strToDate("2015-01-01 07:00:00");
        Date to = strToDate("2020-01-01 07:00:00");
        list = studentDao.findStudentsBornBetweenDates(from, to);
        Log.d(TAG, "zwm, findStudentsBornBetweenDates list.size: " + list.size());
        for(Student item : list) {
            Log.d(TAG, "zwm, student id: " + item.id + ", No." + item.studentNo + ", age: " + item.age + ", name: " + item.name + ", secret: " + item.secret);
        }
    }

    private Date strToDate(String strDate) {
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        ParsePosition pos = new ParsePosition(0);
        return formatter.parse(strDate, pos);
    }
}

//输出log
2020-01-10 14:34:09.039 3373-3373/com.example.sourcecodetest D/MyApplication: zwm, onCreate
2020-01-10 14:34:10.124 3373-3373/com.example.sourcecodetest D/MainActivity: zwm, onCreate
2020-01-10 14:34:10.125 3373-3513/com.example.sourcecodetest D/MainActivity: zwm, test thread: Thread-6
2020-01-10 14:34:10.192 3373-3513/com.example.sourcecodetest D/Converters: zwm, dateToTimestamp
2020-01-10 14:34:10.192 3373-3513/com.example.sourcecodetest D/Converters: zwm, dateToTimestamp
2020-01-10 14:34:10.194 3373-3513/com.example.sourcecodetest D/MainActivity: zwm, insert
2020-01-10 14:34:10.197 3373-3513/com.example.sourcecodetest D/Converters: zwm, fromTimestamp
2020-01-10 14:34:10.197 3373-3513/com.example.sourcecodetest D/Converters: zwm, fromTimestamp
2020-01-10 14:34:10.198 3373-3513/com.example.sourcecodetest D/MainActivity: zwm, queryAll list.size: 3
2020-01-10 14:34:10.198 3373-3513/com.example.sourcecodetest D/MainActivity: zwm, student id: 1, No.10086, age: 18, name: 中国移动, secret: null
2020-01-10 14:34:10.198 3373-3513/com.example.sourcecodetest D/MainActivity: zwm, student id: 2, No.10010, age: 19, name: 中国联通, secret: null
2020-01-10 14:34:10.198 3373-3513/com.example.sourcecodetest D/MainActivity: zwm, student id: 3, No.10000, age: 20, name: 中国电信, secret: null
2020-01-10 14:34:10.200 3373-3513/com.example.sourcecodetest D/Converters: zwm, dateToTimestamp
2020-01-10 14:34:10.200 3373-3513/com.example.sourcecodetest D/Converters: zwm, dateToTimestamp
2020-01-10 14:34:10.202 3373-3513/com.example.sourcecodetest D/Converters: zwm, fromTimestamp
2020-01-10 14:34:10.202 3373-3513/com.example.sourcecodetest D/Converters: zwm, fromTimestamp
2020-01-10 14:34:10.202 3373-3513/com.example.sourcecodetest D/MainActivity: zwm, findStudentsBornBetweenDates list.size: 2
2020-01-10 14:34:10.202 3373-3513/com.example.sourcecodetest D/MainActivity: zwm, student id: 1, No.10086, age: 18, name: 中国移动, secret: null
2020-01-10 14:34:10.202 3373-3513/com.example.sourcecodetest D/MainActivity: zwm, student id: 2, No.10010, age: 19, name: 中国联通, secret: null

四、数据库升级

Room允许使用Migration类保留用户数据。每个Migration类在运行时指明一个开始版本和一个结束版本,Room执行每个Migration类的migrate()方法,使用正确的顺序去迁移数据库到一个最近版本。

注意:如果不提供必需的Migration类,Room重建数据库,也就意味着将丢失数据库中的所有数据。

//Student
@Entity
public class Student {
    @PrimaryKey(autoGenerate = true)
    public  int id;

    @Ignore
    public  String secret;

    public  long studentNo; //学号

    public  int age; //年龄

    public  String name; //姓名

    public Date birthday; //生日,Date类型

    public int addField1;

    public int addField2;
}

//AppDatabase
@Database(entities = {Student.class}, version = 3)
@TypeConverters({Converters.class})
public abstract class AppDatabase extends RoomDatabase {
    public abstract StudentDao studentDao();
}

//MyApplication
public class MyApplication extends Application {
    private static final String TAG = "MyApplication";
    private AppDatabase db;

    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(TAG, "zwm, onCreate");
        initRoom();
    }

    private void initRoom() {
        //db = Room.databaseBuilder(getApplicationContext(), AppDatabase.class, "tomorrow.db").build();
        db = Room.databaseBuilder(getApplicationContext(), AppDatabase.class, "tomorrow.db")
                .addMigrations(MIGRATION_1_2, MIGRATION_2_3).build();
    }

    static final Migration MIGRATION_1_2 = new Migration(1, 2) {
        @Override
        public void migrate(SupportSQLiteDatabase database) {
            Log.d(TAG, "zwm, migrate MIGRATION_1_2");
            database.execSQL("ALTER TABLE student "
                    + " ADD COLUMN addField1 INTEGER NOT NULL DEFAULT 222");
        }
    };

    static final Migration MIGRATION_2_3 = new Migration(2, 3) {
        @Override
        public void migrate(SupportSQLiteDatabase database) {
            Log.d(TAG, "zwm, migrate MIGRATION_2_3");
            database.execSQL("ALTER TABLE Student "
                    + " ADD COLUMN addField2 INTEGER NOT NULL DEFAULT 333");
        }
    };

    public AppDatabase getAppDatabase() {
        return db;
    }
}

五、源码解析

Room源码解析系列

相关文章

网友评论

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

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