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