鴻蒙關(guān)系型數(shù)據(jù)庫操作實踐嘗試
51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)
簡單使用
1. 創(chuàng)建數(shù)據(jù)庫
初始化數(shù)據(jù)庫
- public class HiDbHelper {
- //1. 配置數(shù)據(jù)庫相關(guān)信息
- private static StoreConfig config = StoreConfig.newDefaultConfig("RdbStoreTest.db");
- //RdbOpenCallback用于管理數(shù)據(jù)庫的創(chuàng)建、升級和降級
- private static RdbOpenCallback callback = new RdbOpenCallback() {
- @Override
- public void onCreate(RdbStore rdbStore) {
- //該方法當(dāng)數(shù)據(jù)庫不存在時會被調(diào)用
- //2. 初始化數(shù)據(jù)庫表
- rdbStore.executeSql("CREATE TABLE IF NOT EXISTS employee (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, age INTEGER, salary REAL, blobType BLOB)");
- }
- @Override
- public void onUpgrade(RdbStore rdbStore, int i, int i1) {
- }
- };
- //RdbStore是一個接口,提供了對數(shù)據(jù)庫進(jìn)行增刪改查等操作
- private static volatile RdbStore store;
- //3. 獲取對數(shù)據(jù)庫操作的對象
- public static RdbStore singleStore() {
- synchronized (HiDbHelper.class) {
- if (store == null) {
- synchronized (HiDbHelper.class) {
- //DatabaseHelper提供了多種模式來操作數(shù)據(jù)庫,主要是對ORM(Object Relational Mapping),RDB(Relational Database),Preferences這三類數(shù)據(jù)庫的構(gòu)建和刪除
- DatabaseHelper helper = new DatabaseHelper(MyApplication.appContext);
- //通過getRdbStore獲取關(guān)系型數(shù)據(jù)庫對象
- //getRdbStore四個參數(shù)分別是:
- //StoreConfig config: 對數(shù)據(jù)庫的配置,包括數(shù)據(jù)庫路徑,存儲模式,是否為只讀等
- //int version: 數(shù)據(jù)庫版本,主要用于指示數(shù)據(jù)庫的升級或降級
- //RdbOpenCallback openCallback: 用于管理數(shù)據(jù)庫的創(chuàng)建、升級和降級
- //ResultSetHook resultSetHook: 這個類允許用戶自定義結(jié)果集
- store = helper.getRdbStore(config, 1, callback, null);
- }
- }
- }
- return store;
- }
- }
2. 插入數(shù)據(jù)
關(guān)系型數(shù)據(jù)庫提供了插入數(shù)據(jù)的接口,通過ValuesBucket輸入要存儲的數(shù)據(jù),通過返回值判斷是否插入成功,插入成功時返回最新插入數(shù)據(jù)所在的行號,失敗則返回-1。
- //1. 構(gòu)建需要插入的數(shù)據(jù),關(guān)系型數(shù)據(jù)庫中,插入的數(shù)據(jù)是以ValuesBucket形式存儲的
- ValuesBucket values = new ValuesBucket();
- values.putInteger("id", 1);
- values.putString("name", "zhangsan");
- values.putInteger("age", 18);
- values.putDouble("salary", 100.5);
- values.putByteArray("blobType", new byte[] {1, 2, 3});
- //2. 執(zhí)行插入操作,第一個參數(shù)為數(shù)據(jù)需要插入的表名,第二個參數(shù)為需要插入的數(shù)據(jù)
- long id = HiDbHelper.singleStore().insert("employee", values);
3. 查詢數(shù)據(jù)
查詢操作
關(guān)系型數(shù)據(jù)庫查詢提供類兩種查詢方式:
1.通過調(diào)用ResultSet query(AbsRdbPredicates predicates, String[] columns)查詢,該方法將包含查詢條件的謂詞自動拼接成完整的SQL語句進(jìn)行查詢操作,無需調(diào)用者傳入原生的SQL
傳入?yún)?shù)說明
- AbsRdbPredicates predicates:謂詞,可設(shè)置查詢條件。AbsRdbPredicates的實現(xiàn)類有兩個:RdbPredicates和RawRdbPredicates
- RdbPredicates:支持調(diào)用謂詞提供的equalTo等接口,設(shè)置查詢條件。
- RawRdbPredicates:僅支持設(shè)置表名、where條件子句、whereArgs三個參數(shù),不支持equalTo等接口調(diào)用。
- columns:規(guī)定查詢返回的列。
關(guān)于更多謂詞的使用可以查詢官方文檔關(guān)系型數(shù)據(jù)庫開發(fā)指導(dǎo)
- //1. 需要查詢的列
- String[] columns = new String[] {"id", "name", "age", "salary"};
- //2. 構(gòu)建查詢條件
- RdbPredicates rdbPredicates = new RdbPredicates("employee").equalTo("age", 23).orderByAsc("salary");
- //3. 查詢獲取結(jié)果集
- ResultSet resultSet = HiDbHelper.singleStore().query(rdbPredicates, columns);
通過調(diào)用ResultSet querySql(String sql, String[] sqlArgs)使用原生SQL語句進(jìn)行查詢
參數(shù)說明:
- String sql:原生用于查詢的sql語句
- String[] sqlArgs:sql語句中占位符參數(shù)的值,若select語句中沒有使用占位符,該參數(shù)可以設(shè)置為null。
- String sql = "select id,name,age,salary from employee where age = 23";
- ResultSet resultSet = HiDbHelper.singleStore().querySql(sql, null);
結(jié)果集處理
當(dāng)調(diào)用查詢方法獲取到ResultSet時,其默認(rèn)并沒有指向當(dāng)前結(jié)果集中的數(shù)據(jù),如果此時調(diào)用其String getString(int columnIndex)獲取當(dāng)前行指定索列的值,則會拋出異常
- ohos.data.resultset.ResultSetIndexOutOfRangeException: checkState :row index is illegal.
正確的操作應(yīng)該是:
先調(diào)用boolean goToNextRow()將結(jié)果集向后移動一行,返回true這表示當(dāng)前位置有數(shù)據(jù),再對結(jié)果進(jìn)行處理,如果要獲取ResultSet更多使用方式,可以查看官方文檔
- if (resultSet.goToNextRow()) {
- HiLog.debug(TAG, "select name is %{public}s", resultSet.getString(1));
- }
4. 更新數(shù)據(jù)
調(diào)用更新接口,傳入要更新的數(shù)據(jù),并通過AbsRdbPredicates指定更新條件。該接口的返回值表示更新操作影響的行數(shù)。如果更新失敗,則返回0。
- //1. 構(gòu)建需要更新的數(shù)據(jù)的條件
- RdbPredicates rdbPredicates = new RdbPredicates("employee")
- .equalTo("id",1);
- //2. 構(gòu)建需要更新的數(shù)據(jù)
- ValuesBucket values = new ValuesBucket();
- values.putString("name","Mo");
- //3. 執(zhí)行更新操作
- HiDbHelper.singleStore().update(values, rdbPredicates);
5. 刪除數(shù)據(jù)
調(diào)用刪除接口,通過AbsRdbPredicates指定刪除條件。該接口的返回值表示刪除的數(shù)據(jù)行數(shù),可根據(jù)此值判斷是否刪除成功。如果刪除失敗,則返回0。
- //1. 構(gòu)建需要刪除數(shù)據(jù)的條件
- RdbPredicates rdbPredicates = new RdbPredicates("test")
- .equalTo("id", 1);
- //2. 執(zhí)行刪除操作
- HiDbHelper.singleStore().delete(rdbPredicates);
事務(wù)
關(guān)系型數(shù)據(jù)庫提供事務(wù)機(jī)制,來保證用戶操作的原子性。對單條數(shù)據(jù)進(jìn)行數(shù)據(jù)庫操作時,無需開啟事務(wù);插入大量數(shù)據(jù)時,開啟事務(wù)可以保證數(shù)據(jù)的準(zhǔn)確性。如果中途操作出現(xiàn)失敗,會執(zhí)行回滾操作。
事務(wù)的API一共有三個
beginTransaction():開啟事務(wù)。
markAsCommit():設(shè)置事務(wù)的標(biāo)記為成功。
endTransaction():結(jié)束事務(wù)。
其中markAsCommit()和endTransaction()必須與beginTransaction(),如果單獨(dú)調(diào)用,則會拋出異常
markAsCommit()與endTransaction()不能獨(dú)立調(diào)用
如果單獨(dú)調(diào)用markAsCommit()
則會拋出異常
- java.util.EmptyStackException
如果單獨(dú)調(diào)用endTransaction()
則會拋出異常
- java.lang.IllegalStateException: Cannot do the transaction operation, because there is no current transaction.
如果在事務(wù)塊中如果調(diào)用了markAsCommit(),本次批量操作數(shù)據(jù)出現(xiàn)錯誤,則不會進(jìn)行回滾操作,該方法可以用于某些情況下阻止回滾
示例代碼
- ValuesBucket values = new ValuesBucket();
- values.putInteger("id", 1);
- values.putString("name", "zhangsan");
- values.putInteger("age", 18);
- values.putDouble("salary", 100.5);
- values.putByteArray("blobType", new byte[] {1, 2, 3});
- //開啟事務(wù)
- HiDbHelper.singleStore().beginTransaction();
- //插入兩條id相同的數(shù)據(jù)
- long id1 = HiDbHelper.singleStore().insert("employee", values);
- long id2 = HiDbHelper.singleStore().insert("employee", values);
- //加入下列的判斷,即使id2插入不成功,本次事務(wù)也不會進(jìn)行回滾
- //if(id1 == 1) {
- // HiDbHelper.singleStore().markAsCommit();
- //}
- //結(jié)束事務(wù)
- HiDbHelper.singleStore().endTransaction();
開啟事務(wù)除使用beginTransaction()外,還可以使用beginTransactionWithObserver(TransactionObserver transactionObserver),在開啟事務(wù)的同時注冊觀察者,用于監(jiān)聽事務(wù)的開啟,提交,回滾操作。
注意:在開啟事務(wù)后,一定記得在適當(dāng)?shù)臅r機(jī)進(jìn)行關(guān)閉操作,否則在對數(shù)據(jù)庫進(jìn)行備份等操作時會拋出異常
- java.lang.IllegalArgumentException: The rdb is in transaction.
為了代碼的健壯性,可以在對數(shù)據(jù)庫進(jìn)行備份等操作前調(diào)用RdbStore的isInTransaction判斷當(dāng)前是否有事務(wù)還沒有關(guān)閉,如果沒有關(guān)閉,則進(jìn)行關(guān)閉操作
數(shù)據(jù)庫升級,降級,備份,刪除,恢復(fù)
作為一名老移動端開發(fā)者,由于最近事務(wù)繁忙,這部分功能暫時沒有有效的驗證,有玩過的朋友歡迎進(jìn)行進(jìn)一步的分享。也可以期待后續(xù)我的帖子。
51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)