preface

Android data persistence layer directly using SQLite is very troublesome, Google officially launched Room, Google’s definition of Room: The Room persistence library provides an abstraction layer over SQLite to allow fluent database access while harnessing SQLite. Room is an abstraction layer on SQLite, which is used to get rid of tedious database operations, including creating, updating databases, tables, adding, deleting, checking, etc.

Room database structure

As shown below, the Room database contains three objects:

Entity: Corresponds to a table in the database. You can use the Entity annotation to turn a class into a table structure in the database.

DAO: full name Database Access

Object defines operations such as reading and writing data in the database. DAO can use SQL statements to operate the database.

RoomDatabase: Database holding classes for creating or connecting to databases. Internal contains DAO and Entity.

Entity

An Entity in Room Database represents a data table structure, and an Entity instance is a row in the table, such as an Entity that defines a Person class.

@Entity
public class Person{
    @PrimaryKey
    public int id;
    public String firstName;
    public String lastName;
}
Copy the code

When there are two Person objects in a table, the table contains the following data:

Key points:

An Entity object represents a row in a table, and an Entity class represents a table.

Entity member variables are columns in the data table.

3, a Java class is defined as Entity by the Entity annotation.

The use of the Entity

1. Define an Entity

@Entity(tableName = "person_table")
public class Person{
    @PrimaryKey
    public int id;

    public String firstName;
    public String lastName;
}
Copy the code

If you want to name an Entity, you can add (tableName = “person_table”) to the end of the @entity annotation. If you don’t, the default name will be used. The id, firstName, and lastName are defined as public. So that the database can have permission to manipulate the data, or you can choose to set it all to private and do it through setters and getters.

2. Define primary keys

Define at least one primary key for each Entity, even if there is only one variable in the Entity. Use the @primaryKey annotation in the Room database to define the primary key. There are two ways to use @primarykey: you can add it before the class variable, or you can add it after the @entity annotation if the PrimaryKey is more complex.

@Entity(primaryKeys = {"firstName"."lastName"})
public class User {
    public String firstName;
    public String lastName;
}
Copy the code

3. Change the attribute column name

As with tableName, you can change column names in a table, using @columnInfo to change column names. By default, the variable name is lowercase.

@Entity(tableName = "person_table")
public class Person {
    @PrimaryKey
    public int id;

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

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

4, some variables do not generate data table fields

If you do not want a variable to generate an attribute column in the table, you can use the @ignore annotation.

@Entity
public class Person {
    @PrimaryKey
    public int id;
    public String firstName;
    public String lastName;

    @Ignore
    Bitmap picture;
}
Copy the code

IgnoredColumns can be used if a class inherits from the Person class above and does not want Picture to generate columns in the data table

@Entity(ignoredColumns = "picture")
public class RemotePerson extends Person {
    @PrimaryKey
    public int id;

    public boolean hasVpn;
}
Copy the code

5. Two tables are associated

SQLite is a relational database, which can specify the relationship between two objects. Most relational databases can specify the association between tables, but Room database can not specify the relationship between two tables, but can carry out the association of tables through the @foreignKey annotation.

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

    public String title;

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

6. Nested Entity

If you define an Entity class that has an object in it and you want the table column fields in the Entity class to contain variables in the Entity class object, you can add the @Embedded annotation to the Entity class object.

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

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

@Entity
public class Person{
    @PrimaryKey
    public int id;

    public String firstName;

    @Embedded
    public Address address;
}
Copy the code

So the column fields in the Person table have ID, firstName, street, state, city, and post_code.

DAO

In the DAO(Data Access Object), database operations can be performed using SQL statements and associated with Java method calls. The compiler checks the SQL statements and generates the corresponding query statements through annotations, such as @INSERT.

Note:

DAO must now be an abstract class or interface

2. All queries must be executed in a separate thread.

The use of DAO

You can use statements in SQL to implement DAO operations.

1. Insert data

When the @INSERT annotation is used before a method, the Room database inserts all the parameters of the method into the data table.

@Dao
public interface MyDao {
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    public void insertUsers(User... users);

    @Insert
    public void insertBothUsers(User user1, User user2);

    @Insert
    public void insertUsersAndFriends(User user, List<User> friends);
}
Copy the code

When the @INSERT method inserts only one parameter, the Insert returns long data representing the row number of the inserted object in the table. When an array or collection is inserted, the long array or collection is returned. 2. Update data

The @update annotation method looks for the same data in the table as the given data primary key and updates it.

@Dao
public interface MyDao {
    @Update
    public void updateUsers(User... users);
}
Copy the code

3. Query data

The @query annotated Query method is the most used method, and each Query method is validated at compile time. If it fails, an error is reported, and no further failure is reported at runtime. in

@Dao
public interface MyDao {
    @Query("SELECT * FROM user")
    public User[] loadAllUsers();
}
Copy the code

If there is a query syntax error, or if the user table does not exist in the database, the Room database will display an error message at compile time. Complex queries can also be implemented using SQL statements

@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);
}
Copy the code

Query the data in the list and return the sublist

Sometimes it is not necessary to return all fields of the query data; most of the time it is only necessary to return a subfield of the query data. The following implementation returns a subdomain of the query.

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

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

The query then returns the fields in the subdomain

@Dao
public interface MyDao {
    @Query("SELECT first_name, last_name FROM user")
    public List<NameTuple> loadFullName(a);
}
Copy the code

RoomDatabase

Entity defines a table. The DAO defines operations on the data in the table. RoomDatabase contains the DAO and provides methods for creating and connecting to the database.

Create Room database

Creating a RoomDatabase involves three steps: 1. Create an abstract class that inherits from RoomDatabase.

2. Use the @database annotation before inherited classes.

Declare the Entity of the database structure and set the version number of the database.

@Database(entities = {Word.class}, version = 1)// Declare the version number of Entity and database
public abstract class WordRoomDatabase 
                      extends RoomDatabase { 
   public abstract WordDao wordDao(a);// Create an abstract class for DAO

   private static WordRoomDatabase INSTANCE;// Create a singleton
   
   static WordRoomDatabase getDatabase(final Context context) {
 		 if (INSTANCE == null) {
    			synchronized (WordRoomDatabase.class) {
      			if (INSTANCE == null)    {
       				    INSTANCE = Room.databaseBuilder(
						context.getApplicationContext(),
						WordRoomDatabase.class, "word_database") .addCallback(sOnOpenCallback) .fallbackToDestructiveMigration() .build(); }}}returnINSTANCE; }private static RoomDatabase.Callback sOnOpenCallback =
  new RoomDatabase.Callback(){
	@Override
	public void onOpen (@NonNull SupportSQLiteDatabase db){
		super.onOpen(db);
		initializeData();
	}};

}
Copy the code

Note: 1. Check whether the SQL statement is correct during compilation

2. Do not perform database operations on the main thread

3. RoomDatabase is best used in singleton mode

Finally, Android interacts with the Room database while using the Room database

Room database Migration

When upgrading an Android application, it is sometimes necessary to change the structure of the data in the database to keep the original data unchanged when users upgrade the application. Migration using the database is necessary. The Room Persistence Library library in the Room database provides a way to save user data when upgrading the database. Methods are used to define Migration objects, each containing the start and end version numbers of the database.

    static final Migration MIGRATION_1_2 = new Migration(1.2) {
        @Override
        public void migrate(SupportSQLiteDatabase database) {
            // Change the structure of the table}};Copy the code

Implement the Migration object above and override the Migrate method to implement the upgrade operations in the Migrate method.

    static final Migration MIGRATION_2_3 = new Migration(2.3) {
        @Override
        public void migrate(SupportSQLiteDatabase database) {
            database.execSQL("ALTER TABLE users "
                    + " ADD COLUMN last_update INTEGER"); }};Copy the code

If we were to upgrade our database from version 1 to version base, we would define MIGRATION_1_2, MIGRATION_2_3, MIGRATION_3_4, MIGRATION_1_4 and rewrite the singleton methods.

    public static UsersDatabase getInstance(Context context) {
        synchronized (sLock) {
            if (INSTANCE == null) {
                INSTANCE = Room.databaseBuilder(context.getApplicationContext(),
                        UsersDatabase.class, "Sample.db")
                        .addMigrations(MIGRATION_1_2, MIGRATION_2_3, MIGRATION_3_4, MIGRATION_1_4)
                        .build();
            }
            returnINSTANCE; }}Copy the code

MIGRATION_1_2, MIGRATION_2_3, MIGRATION_3_4, MIGRATION_1_4, MIGRATION_1_4, MIGRATION_1_4, MIGRATION_1_4, MIGRATION_1_4, MIGRATION_1_4 However, if sufficient MIGRATION is not provided and the Room database changes from the current version to the latest version, the original data will be overwritten.

reference

1, developer.android.com/training/da…

2, codelabs.developers.google.com/codelabs/an…

My CSDN

Blog.csdn.net/u013309870/…