Room框架學(xué)習(xí)媒吗、使用

Room Persistence Library(官方介紹)
官方ORM(Object Relational Mapping)框架專題
Google官方推出的Android架構(gòu)組件系列文章(六)Room持久化庫

Room 的官方API 可以查看這里

Room


介紹

Room是谷歌官方的數(shù)據(jù)庫ORM(對象關(guān)系映射)框架服傍,使用起來非常方便。

Room提供了一個(gè)SQLite之上的抽象層,使得在充分利用SQLite功能的前提下順暢的訪問數(shù)據(jù)庫骇径。

對于需要處理大量結(jié)構(gòu)化數(shù)據(jù)的App來說假残,把這些數(shù)據(jù)做本地持久化會帶來很大的好處缭贡。常見的用例是緩存重要數(shù)據(jù)塊。這樣當(dāng)設(shè)備無法連網(wǎng)的時(shí)候辉懒,用戶仍然可以瀏覽內(nèi)容阳惹。而用戶對內(nèi)容做出的任何改動(dòng)都在網(wǎng)絡(luò)恢復(fù)的時(shí)候同步到服務(wù)端。


引入

1眶俩、項(xiàng)目build.gradle中添加如下代碼倉庫

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

2莹汤、app Module中引入

 // Room依賴
    implementation 'android.arch.persistence.room:runtime:1.1.0'
    annotationProcessor "android.arch.persistence.room:compiler:1.1.0"

組成

Room中有三個(gè)主要的組件:

1、Database

數(shù)據(jù)庫組件颠印,底層連接的主要入口纲岭,主要作用:

  • 創(chuàng)建database holder
  • 使用注解定義實(shí)體類
  • 實(shí)體類定義了從數(shù)據(jù)庫中獲取數(shù)據(jù)的對象(DAO)

這個(gè)被注解的類是一個(gè)繼承RoomDatabase的抽象類。在運(yùn)行時(shí)线罕,可以通過調(diào)用Room.databaseBuilder() 或者 Room.inMemoryDatabaseBuilder()來得到它的實(shí)例止潮。


2、Entity

實(shí)體類組件钞楼, 一個(gè)類表示數(shù)據(jù)庫的一個(gè)表喇闸。

注意

  • 1、你必須在Database類中的entities數(shù)組中引用這些entity類
  • 2询件、entity中的每一個(gè)field都將被持久化到數(shù)據(jù)庫仅偎,除非使用了@Ignore注解。

3雳殊、DAO

DAO查詢組件橘沥,DAO(Data Access Object) 數(shù)據(jù)訪問對象是一個(gè)面向?qū)ο蟮臄?shù)據(jù)庫接口。
DAO是Room的主要組件夯秃,負(fù)責(zé)定義查詢(添加或者刪除等)數(shù)據(jù)庫的方法座咆。


4、示意圖

image

示例代碼

1仓洼、User.java ---- 實(shí)體類組件(Entity)

  • 建表:當(dāng)一個(gè)類用@Entity注解并且被@Database注解中的entities屬性所引用時(shí)(@Database(entities = {User.class}, version = 1))介陶,Room就會在數(shù)據(jù)庫中為那個(gè)entity創(chuàng)建一張表。
  • 表名:Room默認(rèn)把類名作為數(shù)據(jù)庫的表名色建,自定義表名需要使用@Entity注解的tableName屬性哺呜,@Entity(tableName = "users")。
  • 建列:默認(rèn)Room會為實(shí)體類中定義的每一個(gè)字段(field)都創(chuàng)建一個(gè)數(shù)據(jù)表列(column)箕戳。
  • 列名:默認(rèn)使用字段名作為列名某残,如果想指定列名国撵,可以使用 @ColumnInfo(name = "your_name")。
  • 持久化:要持久化一個(gè)字段(字段數(shù)據(jù)寫入數(shù)據(jù)庫)玻墅,Room必須有獲取它的渠道介牙。你可以把字段寫成public,也可以為它提供一個(gè)setter和getter澳厢。如果你使用setter和getter的方式环础,記住它們要基于Room的Java Bean規(guī)范。
  • 忽略:如果一個(gè)實(shí)體類中有你不想持久化的字段剩拢,那么你可以使用@Ignore來注釋它們线得。
  • 主鍵:每個(gè)實(shí)體類Entity都必須至少定義一個(gè)field作為主鍵(primary key),主鍵自增需要使用@PrimaryKey的autoGenerate屬性徐伐。
  • 組合主鍵:需要使用@Entity注解的primaryKeys屬性贯钩,比如@Entity(primaryKeys = {"firstName", "lastName"}),多個(gè)字段聯(lián)合形成一個(gè)主鍵組合呵晨,保證主鍵的唯一性
@Entity(tableName = "users")
public class User {
    @PrimaryKey(autoGenerate = true)
    private int uid;
 
    @ColumnInfo(name = "first_name")
    private String firstName;
 
    @ColumnInfo(name = "last_name")
    private String lastName;
 
    @Ignore
    Bitmap picture;
}

2魏保、UserDao.java ---- DAO查詢組件

@Dao
public interface UserDao {
    @Query("SELECT * FROM user")
    List<User> getAll();
 
    @Query("SELECT * FROM user WHERE uid IN (:userIds)")
    List<User> loadAllByIds(int[] userIds);
 
    @Query("SELECT * FROM user WHERE first_name LIKE :first AND "
           + "last_name LIKE :last LIMIT 1")
    User findByName(String first, String last);
 
    @Insert
    void insertAll(User... users);
 
    @Delete
    void delete(User user);
}

3、AppDatabase.java ---- 數(shù)據(jù)庫組件

@Database(entities = {User.class}, version = 1)
public abstract class AppDatabase extends RoomDatabase {
    public abstract UserDao userDao();
}

4摸屠、獲取database實(shí)例

獲取database實(shí)例的時(shí)候應(yīng)該保持單例模式谓罗,因?yàn)閿?shù)據(jù)庫的實(shí)例對內(nèi)存的開銷是比較大的,而且程序內(nèi)一般也不需要多個(gè)database的實(shí)例季二。

AppDatabase db = Room.databaseBuilder(getApplicationContext(),AppDatabase.class, "database-name").build();

相關(guān)概念

1檩咱、索引(Indices )

為了提高查詢的效率,可能給特定的字段建立索引胯舷。
要為一個(gè)entity添加索引刻蚯,在@Entity注解中添加indices屬性,列出你想放在索引或者組合索引中的字段桑嘶。
代碼示例:

@Entity(indices = {@Index("name"), @Index("last_name", "address")})
class User {
    @PrimaryKey
    public int id;
 
    public String firstName;
    public String address;
 
    @ColumnInfo(name = "last_name")
    public String lastName;
 
    @Ignore
    Bitmap picture;
}

2炊汹、唯一性(uniqueness)

指定某個(gè)字段或者幾個(gè)字段的值必須是唯一的,比如用戶名或手機(jī)號之類的賬戶唯一標(biāo)識字段逃顶。
可以通過把@Index注解的unique屬性設(shè)置為true來實(shí)現(xiàn)唯一性

@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;
}

3讨便、外鍵約束(Foreign Key)

一個(gè)表中的外鍵(Foreign Key) 指向另一個(gè)表中的主鍵(Primary Key),在更新和刪除時(shí)起到約束的作用以政。比如霸褒,如果你想在刪除主鍵表中的一條數(shù)據(jù)時(shí)可以同時(shí)刪除外鍵約束表中相對應(yīng)的數(shù)據(jù),你可以在@ForeignKey注解中加上onDelete=CASCADE盈蛮。

下面的代碼就指定了Book表中的user_id字段為User表的外鍵废菱,與User表的id字段一一對應(yīng),使用Entity的foreignKeys屬性指定,寫法如下:

@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;
}
  • 注意
    替換沖突『 @Insert(onConfilict=REPLACE) 』不適用于外鍵約束殊轴,onConfilict不是單獨(dú)的sql命令衰倦,可以理解為一組REMOVE和REPLACE的操作,請參見SQLite文檔的ON_CONFLICT語句梳凛,onConfilict有如下五種沖突解決算法耿币。

4梳杏、對象嵌套

就是一個(gè)實(shí)體類中嵌入另一個(gè)實(shí)體類韧拒,可以多層嵌套。比如你在User中嵌套Address十性,如果你使用@Embedded注解Address的話叛溢,那么User表中就擁有了Address的所有字段了。
為了防止多個(gè)實(shí)體嵌套造成字段重復(fù)劲适,你可以通過設(shè)置prefix屬性來保持每列的唯一性楷掉。Room會將提供的值添加到嵌入對象的每個(gè)列名的開頭。

@Entity
class User {
    @PrimaryKey
    public int id;
 
    public String firstName;
 
    @Embedded
    public Address address;
}
class Address {
    public String street;
    public String state;
    public String city;
 
    @ColumnInfo(name = "post_code")
    public int postCode;
}

數(shù)據(jù)查詢(DAO)

DAO抽象出了一種操作數(shù)據(jù)庫的簡便方法霞势。下面介紹一下常見的查詢方式烹植。

1、新增愕贡、插入(Insert)

創(chuàng)建一個(gè)DAO方法并使用@Insert注解草雕,Room就會在工作線程中將所有參數(shù)插入到數(shù)據(jù)庫。
如果@Insert方法僅僅接收一個(gè)參數(shù)固以,那它可以返回一個(gè)long墩虹,表示插入項(xiàng)的rowId。如果參數(shù)是一個(gè)數(shù)組或集合憨琳,它會返回long []或List<Long>诫钓。

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

2、修改篙螟、更新(Update)

根據(jù)每個(gè)entity的主鍵作為更新的依據(jù)菌湃,此方法可以返回一個(gè)int值,指示數(shù)據(jù)庫中更新的行數(shù)遍略。

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

3惧所、刪除(Delete)

使用主鍵找到要?jiǎng)h除的entity,此方法可以返回一個(gè)int值墅冷,指示數(shù)據(jù)庫中被刪除的行數(shù)纯路。

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

4、查詢(Query)

@Query(查詢)是DAO類中使用的主要注解寞忿〕刍#可以讓你執(zhí)行數(shù)據(jù)庫讀/寫操作。每個(gè)@Query方法都會在編譯時(shí)驗(yàn)證,如果查詢語句有問題叫编,會發(fā)生編譯錯(cuò)誤而不是運(yùn)行時(shí)故障辖佣。

Room還會檢查查詢的返回值,如果返回的對象字段名和查詢結(jié)果的相應(yīng)字段名不匹配搓逾,Room將以下面兩種方式提醒你:

  • 如果是某些字段名不匹配會給出警告卷谈。
  • 如果沒有匹配的字段名則會給出錯(cuò)誤提示。

4-1霞篡、簡單查詢

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

4-2世蔗、條件查詢 (傳參)

注意查詢方法的入?yún)⒃诓樵冋Z句中的寫法“:minAge”,另外朗兵,在使用in操作符進(jìn)行查詢時(shí)污淋,別忘記加上“()”哦!

@Dao
public interface MyDao {
    //查詢User表中年齡大于入?yún)⒌臄?shù)據(jù)集合
    @Query("SELECT * FROM user WHERE age > :minAge")
    public User[] loadAllUsersOlderThan(int minAge);

    //查詢User表中年齡介于入?yún)⒅g的數(shù)據(jù)集合
    @Query("SELECT * FROM user WHERE age BETWEEN :minAge AND :maxAge")
    public User[] loadAllUsersBetweenAges(int minAge, int maxAge);
 
   //查詢User表中名字中入?yún)㈥P(guān)鍵字的數(shù)據(jù)集合
    @Query("SELECT * FROM user WHERE first_name LIKE :search "
           + "OR last_name LIKE :search")
    public List<User> findUserWithName(String search);

    //查詢User表中id符合入?yún)⒓现械臄?shù)據(jù)集合
    @Query("SELECT * FROM user WHERE uid IN (:userIds)")
    List<User> loadAllByIds(int[] userIds);

}

4-3余掖、部分查詢

有時(shí)候我們僅僅需要的是數(shù)據(jù)表中的部分?jǐn)?shù)據(jù)寸爆,這個(gè)時(shí)候我們可以指定DAO的查詢方法只返回我們需要的字段,這樣不僅節(jié)約資源而且查詢更快盐欺。

方法是在查詢語句中指定需要獲取的字段赁豆,然后指定對應(yīng)的實(shí)體類來獲取查詢的返回?cái)?shù)據(jù)。

例如冗美,User的實(shí)際字段有如下四個(gè)魔种,但是我們只需要其中的first_name和last_name,那么我們可以重新定義一個(gè)實(shí)體類UserName墩衙,然后在查詢方法中指定只查詢first_name和last_name字段务嫡,并使用UserName實(shí)體來獲取查詢語句的返回?cái)?shù)據(jù)。

注:這些“裁剪”的實(shí)體類也是可以使用@Embedded注解的漆改。

@Entity(tableName = "users")
public class User {
    @PrimaryKey(autoGenerate = true)
    private int uid;

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

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

    @Ignore
    Bitmap picture;
}
public class UserName{
    @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();
}

4-4心铃、原始查詢 RawQuery

我們可以利用 RawQuery 進(jìn)行原始SQL語句查詢,示例代碼:

 @Dao
 interface RawDao {
     @RawQuery
     User getUserViaQuery(SupportSQLiteQuery query);
 }
 SimpleSQLiteQuery query = new SimpleSQLiteQuery("SELECT * FROM User WHERE id = ? LIMIT 1", new Object[]{userId});
 User user2 = rawDao.getUserViaQuery(query);

1挫剑、Room將根據(jù)函數(shù)的返回類型("User ")生成代碼去扣,如果未能通過正確的查詢,將導(dǎo)致運(yùn)行時(shí)異常樊破。
2愉棱、RawQuery方法只能用于讀取查詢。對于寫入查詢哲戚,請使用RoomDatabase.getOpenHelper().getWritableDatabase()


5奔滑、可觀察的查詢(Observable queries)

5-1、Query

當(dāng)執(zhí)行查詢的時(shí)候顺少,你通常希望app的UI能自動(dòng)在數(shù)據(jù)更新的時(shí)候更新朋其。為此王浴,在query方法中使用 LiveData 類型的返回值。當(dāng)數(shù)據(jù)庫變化的時(shí)候梅猿,Room會生成所有的必要代碼來更新LiveData氓辣。

@Dao
public interface MyDao {
    @Query("SELECT * FROM user WHERE age BETWEEN :minAge AND :maxAge")
     public LiveData<List<User>> loadAllUsersBetweenAges(int minAge, int maxAge);
}

使用步驟:

  • 創(chuàng)建一個(gè)LiveData實(shí)例來保存某種類型的數(shù)據(jù)。 這通常在您的ViewModel類中完成袱蚓。
public class UserViewModel extends ViewModel {

private LiveData<List<User>> mUsers;

public LiveData<List<User>> getUsers() {
    if (mUsers== null) {
        mUsers= MyDao.loadAllUsersBetweenAges(10,30);
    }
    return mUsers;
}

...
}
  • 創(chuàng)建一個(gè)Observer對象钞啸,該對象定義onChanged()方法,該方法在LiveData對象的數(shù)據(jù)發(fā)生變化時(shí)回調(diào)喇潘, 通常是在UI控制器中創(chuàng)建Observer對象辟躏,比如Activity或Fragment鬼贱。
public class UserActivity extends AppCompatActivity {

    private UserViewModel mModel;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mModel = ViewModelProviders.of(this).get(UserViewModel.class);
 
        final Observer<List<User>> userObserver = new Observer<List<User>>() {
            @Override
            public void onChanged(@Nullable List<User> users) {
                //update the ui
            }
        };

        mModel.getCurrentName().observe(this, userObserver);
    }
}
  • 使用observe()方法將Observer對象附加到LiveData對象简十。 observe()方法使用LifecycleOwner對象鄙早。 這將Observer對象訂閱到LiveData對象哨毁,以便通知其更改枫甲。 您通常將Observer對象附加到UI控制器中,比如Activity或Fragment扼褪。

5-2想幻、RawQuery

RawQuery方法可以返回可觀察的類型,但您需要使用注釋中的observedEntities()字段指定在查詢中訪問哪些表话浇。
代碼示例:

 @Dao
 interface RawDao {
     @RawQuery(observedEntities = User.class)
     LiveData<List<User>> getUsers(SupportSQLiteQuery query);
 }
 LiveData<List<User>> liveUsers = rawDao.getUsers(
     new SimpleSQLiteQuery("SELECT * FROM User ORDER BY name DESC"));

Rxjava

Room還可以讓你定義的查詢返回RxJava2的Publisher和Flowable對象脏毯。要使用這個(gè)功能,在Gradle dependencies中添加android.arch.persistence.room:rxjava2幔崖。然后你就可以返回RxJava2中定義的對象類型了食店,如下面的代碼所示:

@Dao
public interface MyDao {
    @Query("SELECT * from user where id = :id LIMIT 1")
    public Flowable<User> loadUserById(int id);
}

Cursor

如果你的app需要直接獲得返回的行,你可以在查詢中返回Cursor對象赏寇。但是非常不鼓勵(lì)使用Cursor 吉嫩,因?yàn)樗鼰o法保證行是否存在,或者行包含什么值嗅定。

public interface MyDao {
    @Query("SELECT * FROM user WHERE age > :minAge LIMIT 5")
    public Cursor loadRawUsersOlderThan(int minAge);
}

多表查詢

一些查詢可能要求查詢多張表來計(jì)算結(jié)果自娩。Room允許你書寫任何查詢,因此表連接(join)也是可以的渠退。
而且如果響應(yīng)是一個(gè)可觀察的數(shù)據(jù)類型忙迁,比如Flowable或者LiveData,Room將觀察查詢中涉及到的所有表碎乃,檢測出所有的無效表姊扔。

下面的代碼演示了如何執(zhí)行一個(gè)表連接查詢來查出借閱圖書的user與被借出圖書之間的信息。
邏輯:入?yún)serName ---- (user.name LIKE :userName) ----> user ---- (user.id = loab.userid) ----> loab ---- (loan.book_id = book.id) ----> book
語句:book <---- (loan.book_id = book.id) ---- loab <---- (user.id = loab.userid) ---- user <---- (user.name LIKE :userName) ---- userName

@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);
}
  • INNER JOIN:內(nèi)連接梅誓,顯示左表和右表符合連接條件的記錄
  • JOIN: 如果表中有至少一個(gè)匹配恰梢,則返回行
  • LEFT JOIN: 即使右表中沒有匹配晨川,也從左表返回所有的行
  • RIGHT JOIN: 即使左表中沒有匹配,也從右表返回所有的行
  • FULL JOIN: 只要其中一個(gè)表中存在匹配删豺,就返回行

類型轉(zhuǎn)換

1共虑、Room對Java的基本數(shù)據(jù)類型以及其包裝類型都提供了支持
2、但是有時(shí)候你可能使用了一個(gè)自定義的數(shù)據(jù)類型呀页,并且你想將此類型的數(shù)據(jù)存儲到數(shù)據(jù)庫表中的字段里妈拌。

為了實(shí)現(xiàn)自定義數(shù)據(jù)類型的轉(zhuǎn)換,你需要一個(gè)類型轉(zhuǎn)換器TypeConverter蓬蝶,它將負(fù)責(zé)處理自定義數(shù)據(jù)類和Room可以保存的已知類型之間的轉(zhuǎn)換尘分。

比如,如果我們想要保存Date實(shí)例丸氛,那么第一步

  • 寫一個(gè)TypeConverter類培愁,實(shí)現(xiàn)Date類型和Long類型的數(shù)據(jù)轉(zhuǎn)換
public class Converters {
    @TypeConverter
    public static Date fromTimestamp(Long value) {
        return value == null ? null : new Date(value);
    }

    @TypeConverter
    public static Long dateToTimestamp(Date date) {
        return date == null ? null : date.getTime();
    }
}

可以看到上面的轉(zhuǎn)換類,提供了兩個(gè)方法以實(shí)現(xiàn)Date類型和Long類型的數(shù)據(jù)相互轉(zhuǎn)換缓窜。

  • 使用TypeConverter類定续,實(shí)現(xiàn)持久化Date類型的數(shù)據(jù)
    這里就需要把這個(gè)轉(zhuǎn)換類Converters添加到我們的數(shù)據(jù)庫組件AppDatabase中了
@Database(entities = {User.java}, version = 1)
@TypeConverters({Converter.class})
public abstract class AppDatabase extends RoomDatabase {
    public abstract UserDao userDao();
}

數(shù)據(jù)庫升級

  • 基本使用
    實(shí)現(xiàn)就是在對應(yīng)的Database中通過Migration進(jìn)行升級,使用的方式是:
    1禾锤、利用Migration 構(gòu)建數(shù)據(jù)庫升級語句
    //數(shù)據(jù)庫升級
    private static final Migration migration_1_2 = new Migration(1, 2) {
        @Override
        public void migrate(@NonNull SupportSQLiteDatabase database) {
            
        }
    };

2私股、在數(shù)據(jù)庫的構(gòu)造方法中通過addMigrations()方法傳入對應(yīng)的Migration

 public synchronized static AppDatabase getInstance(byte[] passphrase) {
        if (INSTANCE == null) {
            synchronized (AppDatabase.class) {
                if (INSTANCE == null) {
                    INSTANCE = Room
                            .databaseBuilder(mContext.getApplicationContext(), AppDatabase.class, sDbPath)
                            .openHelperFactory(new HelperFactory(passphrase))
                            .allowMainThreadQueries()
                            .addMigrations(migration_1_2)
                            .build();
                }

            }
        }
        return INSTANCE;
    }

3、數(shù)據(jù)庫版本(version )+1

@Database(entities = {MarkBook.class}, version = 2, exportSchema = false)
public abstract class AppDatabase extends RoomDatabase {
....

總結(jié):就是把數(shù)據(jù)庫的變化通過SQL語句傳到數(shù)據(jù)庫的構(gòu)造方法中恩掷。


  • 常用的幾種數(shù)據(jù)庫升級

新增表

    //數(shù)據(jù)庫升級
    private static final Migration migration_1_2 = new Migration(1, 2) {
        @Override
        public void migrate(@NonNull SupportSQLiteDatabase database) {
            database.execSQL("CREATE TABLE IF NOT EXISTS SYMBOL_SETTING (_id INTEGER primary key NOT NULL, dbName TEXT, symbolJson TEXT)");
        }
    };

增加字段

    //數(shù)據(jù)庫升級
    private static final Migration migration_1_2 = new Migration(1, 2) {
        @Override
        public void migrate(@NonNull SupportSQLiteDatabase database) {
            database.execSQL("ALTER TABLE SURVEY_RECORD ADD STATUS INTEGER  DEFAULT 0");
        }
    };

數(shù)據(jù)庫多次升級

    //數(shù)據(jù)庫升級,SURVEY_RECORD新增SJBZ倡鲸、SZFHZZZB字段
    private static final Migration migration_2_3 = new Migration(2, 3) {
        @Override
        public void migrate(@NonNull SupportSQLiteDatabase database) {
            database.execSQL("ALTER TABLE SURVEY_RECORD ADD SJBZ TEXT");
            database.execSQL("ALTER TABLE SURVEY_RECORD ADD SZFHZZZB TEXT");
        }
    };

    //數(shù)據(jù)庫升級
    private static final Migration migration_1_2 = new Migration(1, 2) {
        @Override
        public void migrate(@NonNull SupportSQLiteDatabase database) {
            database.execSQL("ALTER TABLE SURVEY_RECORD ADD STATUS INTEGER  DEFAULT 0");
        }
    };

    public synchronized static TaskDatabase getInstance(byte[] passphrase) {
        if (INSTANCE == null) {
            synchronized (TaskDatabase.class) {
                if (INSTANCE == null) {
                    INSTANCE = Room
                            .databaseBuilder(mContext.getApplicationContext(), TaskDatabase.class, sDbPath)
                            .openHelperFactory(new HelperFactory(passphrase))
                            .allowMainThreadQueries()
                            .addMigrations(migration_1_2,migration_2_3)
                            .build();
                }

            }
        }
        return (INSTANCE);
    }

備注:數(shù)據(jù)庫升級的時(shí)候最好文字說明一下這次升級了什么,不要因?yàn)橛蠸QL語句就不寫注解了黄娘,這樣不好峭状。

以普通的方式打開SQLite數(shù)據(jù)庫

有時(shí)候我們需要以普通的方式打開SQLite數(shù)據(jù)庫,以方便我們使用原生的更新逼争、刪除优床、查詢語句

TaskDatabase database = TaskDatabase.getInstance(Encryption.getInstance().getDBEncryptionPassword());
SupportSQLiteDatabase db = database.getOpenHelper().getWritableDatabase();
db.execSQL("");
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市氮凝,隨后出現(xiàn)的幾起案子羔巢,更是在濱河造成了極大的恐慌,老刑警劉巖罩阵,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件竿秆,死亡現(xiàn)場離奇詭異,居然都是意外死亡稿壁,警方通過查閱死者的電腦和手機(jī)幽钢,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來傅是,“玉大人匪燕,你說我怎么就攤上這事蕾羊。” “怎么了帽驯?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵龟再,是天一觀的道長。 經(jīng)常有香客問我尼变,道長利凑,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任嫌术,我火速辦了婚禮哀澈,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘度气。我一直安慰自己割按,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布磷籍。 她就那樣靜靜地躺著适荣,像睡著了一般。 火紅的嫁衣襯著肌膚如雪择示。 梳的紋絲不亂的頭發(fā)上束凑,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天,我揣著相機(jī)與錄音栅盲,去河邊找鬼。 笑死废恋,一個(gè)胖子當(dāng)著我的面吹牛谈秫,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播鱼鼓,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼拟烫,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了迄本?” 一聲冷哼從身側(cè)響起硕淑,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎嘉赎,沒想到半個(gè)月后置媳,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡公条,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年拇囊,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片靶橱。...
    茶點(diǎn)故事閱讀 39,690評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡寥袭,死狀恐怖路捧,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情传黄,我是刑警寧澤杰扫,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站膘掰,受9級特大地震影響涉波,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜炭序,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一啤覆、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧惭聂,春花似錦窗声、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至耕腾,卻和暖如春见剩,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背扫俺。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工苍苞, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人狼纬。 一個(gè)月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓羹呵,卻偏偏與公主長得像,于是被迫代替她去往敵國和親疗琉。 傳聞我的和親對象是個(gè)殘疾皇子冈欢,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評論 2 353

推薦閱讀更多精彩內(nèi)容

  • 通常來說柠贤,重疾險(xiǎn)香浩、壽險(xiǎn)、意外險(xiǎn)是我們保障的主力軍种吸。而醫(yī)療險(xiǎn)則是性價(jià)比很高的補(bǔ)充弃衍。那么我們?nèi)绾螢椴煌彝コ蓡T,做好具...
    water2017閱讀 459評論 0 0
  • iOS上傳圖片后臺旋轉(zhuǎn)展示問題 在一次上傳圖片到服務(wù)器后坚俗,去后臺頁面查看镜盯,發(fā)現(xiàn)iOS顯示的圖片總是旋轉(zhuǎn)90℃的岸裙,而...
    reloadRen閱讀 4,440評論 0 49
  • 你云虹般衣衫蹁躚蛇舞,以柔媚速缆, 蒼天大地臣服你偉跡降允,恭迎登堂 像女人向來朝拜深?yuàn)W的圣潔分娩, 踏上造物邊岸艺糜,佯裝縱...
    SupA閱讀 265評論 0 1
  • 開篇第三章 一剧董、網(wǎng)頁上有很多信息的列表,如新聞列表破停、圖片列...
    多語閱讀 218評論 0 0