【Android】Room數據庫的使用

在這里插入圖片描述

三三要成為安卓糕手

引入

Room是一個抽象層,對SQLite進行了封裝,簡化了SQLite數據庫的操作,讓開發者能以更加對象化的方式進行數據庫操作;Room解決了SQLite操作繁瑣,容易產生錯誤的問題,讓開發者能以更加對象化的方式進行數據庫操作。

一:添加依賴

Room屬于Jetpack中關于數據庫操作的庫,不屬于安卓原生SDK開發包,所以需要單獨添加依賴

// app/build.gradle
dependencies {//添加room運行時依賴庫implementation "androidx.room:room-runtime:2.6.1"// Room 編譯時注解處理器annotationProcessor "androidx.room:room-compiler:2.6.1"// 可選:RxJava2 支持 (如果需要使用RxJava2的異步機制配合Room使用,需要添加這個依賴)implementation "androidx.room:room-rxjava2:2.6.1"// 可選:RxJava3 支持 (如果需要)implementation "androidx.room:room-rxjava3:2.6.1"
}

二:Room 的核心組件

Room 數據庫主要有三個核心組件:

  • Entity(實體類):用于表示數據庫表的數據結構。

  • DAO(Data Access Object):用于定義數據庫操作的方法。

  • Database(數據庫類):用于創建數據庫實例,并將 Entity 和 DAO 關聯起來

1:Entity層

定義與作用Entity 代表數據庫中的一張表,它是一個 Java 類,通過 @Entity 注解來標識。每個 Entity 類的實例對應表中的一行數據,類中的屬性對應表中的列

@Entity(tableName = "user-room")
public class MyUser {@PrimaryKey(autoGenerate = true)private int id;@ColumnInfo(name = "user_age")private int age;@ColumnInfo(name = "user_name")private String name;@ColumnInfo(name = "user_email")private String email;public String getEmail() {return email;}public void setEmail(String email) {this.email = email;}public int getId() {return id;}public void setId(int id) {this.id = id;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}
}
  • Entity [?ent?ti] 實體

    理解:把注解轉化成編譯器能夠看懂的東西

  • tableName = "user-room" 指定了該實體類對應的數據庫表名為 user - room

  • @ColumnInfo(name = "user_age")當前的字段對應我們數據庫中那一列的字段

  • @PrimaryKey(autoGenerate = true) 自增主鍵,設置為fasle的話就需要程序員自己設置id了

2:DAO層(數據訪問對象)

定義與作用Dao 接口定義了對數據庫進行增刪改查(CRUD,Create、Read、Update、Delete)操作的方法。它是應用代碼與數據庫之間交互的橋梁,通過定義不同的方法來執行具體的 SQL 語句或 Room 封裝的操作

@Dao
public interface MyUserDao {@Insertvoid insertUser(MyUser user);/*** 通過MyUser類型直接更新數據庫,Room會根據MyUser中的主鍵來查找對應的數據,并且更新* @param user*/@Updateint updateUser(MyUser user);/*** 更新user-room這個表中,名字是等于name(第一個參數)的數據,把這條數據的user_age更新為age(第二個參數)*/@Query("update `user-room` set user_age = :age where user_name = :name")int updateUser(String name , int age);/*** 通過name查詢user-room表中的某個數據* @param name* @return*/@Query("select * from `user-room` where user_name = :name")List<MyUser> getUserByName(String name);@Deleteint delUser(MyUser user);/*** 通過name刪除對應的用戶* @param name* @return*/@Query("delete from `user-room` where user_name = :name ")int delete(String name);
}
  • 這里設置的插入方法沒有返回值;有返回值的情況:當插入單個實體對象時,返回值是一個 long 類型,表示插入數據后自動生成的主鍵值(前提是自增主鍵)

3:Database層

它是一個抽象類,通過 @Database 注解來標識,通常會包含一個或者多個抽象方法),用于返回定義好的 Dao 接口實例,Room 會在運行時自動生成該抽象類的實現;(可以簡單理解成一個方法對應找庫中的一個表table)

@Database(entities = {MyUser.class} , version = 1)
public abstract class MyUserDatabase extends RoomDatabase {public abstract MyUserDao userDao();static final Migration MIGRATION_1_2 = new Migration(1,2) {@Overridepublic void migrate(@NonNull SupportSQLiteDatabase supportSQLiteDatabase) {supportSQLiteDatabase.execSQL("alter table `user-room` add column user_email text");}};
}
  • entities = {MyUser.class}關聯一張表的名字,可以關聯多張table,在花括號中填寫即可;前提這張表一定是被entity標注過的

(1)版本遷移

如果要實現從版本 1 遷移到版本 5,不能直接寫 Migration(1, 5) 來 “一步到位” 完成所有中間版本(1→2→3→4→5)的遷移。Room 要求必須為每一個相鄰的版本跨度都定義對應的 Migration,也就是需要分別定義:

  • 從版本 1 到版本 2 的 Migration
  • 從版本 2 到版本 3 的 Migration
  • 從版本 3 到版本 4 的 Migration
  • 從版本 4 到版本 5 的 Migration

然后在構建數據庫時,通過 addMigrations() 方法把這些所有相鄰版本的 Migration 都添加進去,Room 會在數據庫升級時,按順序執行這些 Migration,逐步完成從版本 1 到版本 5 的遷移。

(2)addMigration

        MyUserDatabase userDatabase = Room.databaseBuilder(ContentProviderActivity.this, MyUserDatabase.class, "user-database.db").addMigrations(MyUserDatabase.MIGRATION_1_2).build();

(3)數據庫升級的時機

前提:創建數據庫時add了對應的版本升級方法,這個遷移方法內部的具體規則需要再Database層中進行聲明

如果當前版本為1,由于要給表添加新的列或者修改某個字段等等,想要升級到版本2;

那么這里就要修改為2@Database(entities = {MyUser.class} , version = 2),再次運行代碼的時候,MyUserDatabase.MIGRATION_1_2 這個遷移規則,它會告訴 Room 如何將版本 1 的數據庫轉換為版本 2 的數據庫,這樣在數據庫版本升級時,就能按照這個規則來執行相應的操作

    static final Migration MIGRATION_1_2 = new Migration(1,2) {@Overridepublic void migrate(@NonNull SupportSQLiteDatabase supportSQLiteDatabase) {supportSQLiteDatabase.execSQL("alter table `user-room` add column user_email text");}};

migration 信息遷移 alter 修改

效果如下,我們在Entity層中新增加的字段user_email成功添加進來了,現在就是版本2

外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳

4:創建數據庫

        MyUserDatabase userDatabase = Room.databaseBuilder(ContentProviderActivity.this, MyUserDatabase.class, "user-database.db").addMigrations(MyUserDatabase.MIGRATION_1_2).build();
  • 參數一:上下文
  • 參數二:數據庫的class對象
  • 參數三:表示要創建的 SQLite 數據庫文件的名稱。

三:增刪查改

1:增

    @Insertvoid insertUser(MyUser user);
        /*** 插入數據*/findViewById(R.id.btn_insert).setOnClickListener(view -> {new Thread(new Runnable() {@Overridepublic void run() {//可以理解成操作table表的對象MyUserDao myUserDao = userDatabase.userDao();MyUser user = new MyUser();user.setName(etUserName.getText().toString().trim());user.setAge(Integer.valueOf(etUserAge.getText().toString().trim()));myUserDao.insertUser(user);userDatabase.close();}}).start();});

數據庫操作是一個非常耗時的操作,如果是在主線程操作會引起卡頓和崩潰,Room中插入數據需要指定在非主線程中進行,使用SQLite不用指定新線程,因為它內部已經幫我們處理好了外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳

(1)插入結果

Room數據庫會把我們的插入或者查詢操作進行分段讀寫,所以就有三個文件,沒有db后綴,Room也會自動幫我們轉化為db文件的

外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳

為了測試,我們手動去添加后綴;并且想要整合三個文件,就需要手動close一次數據庫操作

外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳

外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳

效果如下

外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳

外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳

2:查 & 改

(1)修改數據

    /*** 通過MyUser類型直接更新數據庫,Room會根據MyUser中的主鍵來查找對應的數據,并且更新* @param user*/@Updateint updateUser(MyUser user);
        /*** 更新數據*/findViewById(R.id.btn_update).setOnClickListener(view -> {new Thread(new Runnable() {@Overridepublic void run() {MyUserDao myUserDao = userDatabase.userDao();MyUser user = new MyUser();user.setId(1);user.setName(etUserName.getText().toString().trim());user.setAge(Integer.valueOf(etUserAge.getText().toString().trim()));myUserDao.updateUser(user);//通過名字查詢到對應的信息,修改這個用戶的年齡userDatabase.userDao().updateUser("lisi",100);}}).start();});

(2)根據主鍵查找

    /*** 通過name查詢user-room表中的某個數據* @param name* @return*/@Query("select * from `user-room` where user_name = :name")List<MyUser> getUserByName(String name);
        /*** 查詢數據*/findViewById(R.id.btn_select).setOnClickListener(view -> {new Thread(new Runnable() {@Overridepublic void run() {MyUserDao myUserDao = userDatabase.userDao();String queryName = etUserName.getText().toString().trim();List<MyUser> users = myUserDao.getUserByName(queryName);Log.i(TAG, "run:users.size" + users.size());if(users.size() > 0){runOnUiThread(new Runnable() {@Overridepublic void run() {//顯示查詢到的用戶數據MyUser user = users.get(0);tvMessage.setText(tvMessage.getText() +"\n" + user.getName() + ":" + user.getAge());}});}}}).start();});

效果如下

外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳

(3)根據字段查找

通過別的數據進行user的查找;不想通過User實體類和主鍵,進行查找

自定義查詢規則,sql語句

    /*** 更新user-room這個表中,名字是等于name(第一個參數)的數據,把這條數據的user_age更新為age(第二個參數)*/@Query("update `user-room` set user_age = :age where user_name = :name")int updateUser(String name , int age);

3:刪

多嘗試

    @Deleteint delUser(MyUser user);
    /*** 通過name刪除對應的用戶* @param name* @return*/@Query("delete from `user-room` where user_name = :name ")int delete(String name);
        findViewById(R.id.btn_delete).setOnClickListener(view -> {new Thread(new Runnable() {@Overridepublic void run() {
//                    MyUser user = new MyUser();
//                    user.setId(1);
//                    userDatabase.userDao().delUser(user);userDatabase.userDao().delete("wangwu");}}).start();});

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/95893.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/95893.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/95893.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Next.js 介紹:為什么選擇它來構建你的下一個 Web 應用?

Next.js 介紹&#xff1a;為什么選擇它來構建你的下一個 Web 應用&#xff1f; 作者&#xff1a;碼力無邊你好&#xff0c;歡迎來到我們的 Next.js 專欄&#xff01;在接下來的 30 篇文章中&#xff0c;我們將一起踏上一段從入門到精通的旅程&#xff0c;深入探索這個強大而優雅…

開發環境 之 編輯器、編譯器、IDE梳理

小生第一次學習編程時&#xff0c;懵懵搞不懂編輯器、編譯器、IDE區別&#xff0c;雖然這對前期學習編程語言語法的影響不是很大&#xff0c;但是現在梳理一下&#xff0c;總歸心里踏實些。 一、概念及區別 IDE是前面幾者的集成&#xff0c;前面幾個分別是IDE的子集。對比維度編…

高級RAG策略學習(六)——Contextual Chunk Headers(CCH)技術

Contextual Chunk Headers&#xff08;CCH&#xff09;技術深度解析 第一部分&#xff1a;理論基礎與核心原理 一、核心定義&#xff1a;給 “文本塊” 加 “上下文標簽” Contextual Chunk Headers&#xff08;上下文塊標題&#xff0c;簡稱 CCH&#xff09;本質是為文檔拆分后…

人形機器人控制系統核心芯片從SoC到ASIC的進化路徑

目錄&#xff1a; 0 前言 1 人形機器人控制系統核心芯片選擇ASIC而非SoC的理由 1.1 SoC的架構特征 1.2 ASIC的架構特征 1.3 SoC的優勢&#xff08;繼承軟件生態&#xff09; 1.4 ASIC的優勢&#xff08;硬件底層算法就是應用層算法&#xff09; 1.5 人形機器人控制系統核…

linux thread 線程一

thread線程是linux的重要概念。線程不能獨立存在&#xff0c;必須在進程中存在。一個進程必須有一個線程&#xff0c;如果進程中沒有創建新線程&#xff0c;進程啟動后本身就有一個線程。使用getpid、getppid獲取進程的進程ID和父進程ID。使用pthread_self獲取到當前線程的ID。…

Arduino Nano33 BLESense Rev2【室內空氣質量檢測語音識別藍牙調光臺燈】

一、硬件介紹 1、產品特點 Arduino Nano 33 BLE Rev2&#xff0c;利用了nRF52840微控制器的先進功能。這款32位Arm Cortex-M4 CPU 64 MHz與MicroPython的兼容性增強了板子的靈活性&#xff0c;該開發板的突出特點是其藍牙低功耗&#xff08;BLE&#xff09;功能&#xff0c;使…

【問題解決】mac筆記本遇到鼠標無法點擊鍵盤可響應處理辦法?(Command+Option+P+R)

背景 如題。鼠標無法點擊&#xff0c;但可以移動。觸控板能夠波動&#xff0c;鼠標翻頁能夠work&#xff0c;但是點擊后無法響應。 根因 電腦緩存問題 解決辦法 重置PRAM&#xff1a; 確保電腦關機狀態&#xff08;可以先sudo shutdown -t now)&#xff08;一定要確保&#xff…

23ai數據庫通過SQLcl生成AWR報告

?1. 查看現有快照SQL> awr list snap;SNAP_ID DBID BEGIN_INTERVAL_TIME END_INTERVAL_TIME FLUSH_LEVEL __________ _____________ __________________________________ __________________________________ ______________793 …

基于Django+Vue3+YOLO的智能氣象檢測系統

基于DjangoVue3YOLO的智能氣象檢測系統 項目簡介 本項目是一個集成了人工智能深度學習技術的現代化氣象檢測系統&#xff0c;采用前后端分離架構&#xff0c;結合YOLO目標檢測算法&#xff0c;實現了對氣象現象的智能識別與分析。系統提供了完整的用戶管理、實時檢測、歷史記錄…

(4)什么時候引入Seata‘‘

非常好的問題&#xff01;這兩個問題正是技術選型時需要重點考慮的。什么時候需要引入 Seata&#xff1f;需要引入 Seata 的場景&#xff1a;跨數據庫的分布式事務// 訂單服務&#xff08;MySQL&#xff09; 庫存服務&#xff08;PostgreSQL&#xff09; 賬戶服務&#xff08…

蘋果內部 AI聊天機器人“Asa”曝光,為零售員工打造專屬A

MacRumors網站的亞倫佩里斯&#xff08;Aaron Perris&#xff09;透露&#xff0c;蘋果正在內部測試一款名為“Asa”的AI聊天機器人。這款工具旨在賦能Apple Store零售員工&#xff0c;幫助他們快速掌握iPhone等產品的特色和差異化使用場景&#xff0c;從而提升與顧客互動時的解…

MySQL常見報錯分析及解決方案總結(12)---slave_net_timeout

關于超時報錯&#xff0c;一共有五種超時參數&#xff0c;詳見&#xff1a;MySQL常見報錯分析及解決方案總結(7)---超時參數connect_timeout、interactive_timeout/wait_timeout、lock_wait_timeout、net等-CSDN博客 以下是當前報錯的排查方法和解決方案&#xff1a; 在 Wind…

云計算學習筆記——日志、SELinux、FTP、systemd篇

《云計算學習日記Day15》—— 從零開始的云計算之旅 今天是系統學習云計算的第十五天&#xff0c;記錄了關于我的云計算學習&#xff0c;后續將每日更新我的筆記。歡迎大家一起來學習&#xff0c;如果內容有遺漏和錯誤&#xff0c;還請大家多多指正和包涵&#xff0c;謝謝大家 …

3Ds Max Gamma值完全指南:問題識別與正確設置解析

當渲染圖像與本地圖片相比亮度偏黑或偏白時&#xff0c;很可能是因為Gamma輸入輸出設置不一致。需要注意的是&#xff0c;Gamma問題通常表現為整體亮度偏差&#xff0c;而非大面積曝光或全黑狀況。Gamma設置教程問題一&#xff1a;Gamma校正未開啟如果使用VR幀緩沖窗口渲染但未…

用 Rust + Actix-Web 打造“Hello, WebSocket!”——從握手到回聲,只需 50 行代碼

用 Rust Actix-Web 打造“Hello, WebSocket!”——從握手到回聲&#xff0c;只需 50 行代碼 一、為什么選擇 Rust 寫 WebSocket&#xff1f; 零成本抽象&#xff1a;編譯期確定生命周期&#xff0c;無 GC 抖動&#xff0c;延遲低至微秒級actix-web&#xff1a;Tokio 生態最成熟…

基于Cursor的 STM32工程搭建 (編譯、下載、仿真)

嵌入式學習交流Q群 679912988 簡介 本工程使用GCC編譯器、MinGW、CMake構建工具和OpenOCD調試工具。實現了替代KEIL, IAR等在某些情況下不方便使用的情況。實現了編譯、調試、下載、燒錄一體。搭配Cursor的Tab補全功能&#xff0c;編碼效率大大提升。 工具下載及安裝 Cursor…

數據量太大處理不了?Hadoop+Spark輕松解決海洋氣象大數據分析難題

&#x1f34a;作者&#xff1a;計算機畢設匠心工作室 &#x1f34a;簡介&#xff1a;畢業后就一直專業從事計算機軟件程序開發&#xff0c;至今也有8年工作經驗。擅長Java、Python、微信小程序、安卓、大數據、PHP、.NET|C#、Golang等。 擅長&#xff1a;按照需求定制化開發項目…

Day34 UDP套接字編程 可靠文件傳輸與實時雙向聊天系統

day34 UDP套接字編程 可靠文件傳輸與實時雙向聊天系統 UDP文件傳輸 實現客戶端向服務器傳輸文件&#xff08;如圖片&#xff09;的功能&#xff0c;確保傳輸后文件內容完全一致且可正常打開。傳輸過程采用簡單的確認機制防止數據包丟失&#xff0c;傳輸完成后雙方程序自動退出。…

策略模式-不同的鴨子的案例

介紹了策略模式在C#中的應用&#xff0c;以一個鴨子的例子來說明。首先定義了鴨子類以及鴨子的行為&#xff08;方法&#xff09;&#xff0c;然后通過繼承和實現接口的方式來定義不同種類的鴨子的特性。介紹了策略模式的概念&#xff0c;將相同的算法封裝在不同的類中&#xf…

C++語言編程規范-初始化和類型轉換

01 C語言編程規范-常量 02 初始化和類型轉換 聲明、定義與初始化 03 禁止用 memcpy、memset 初始化非 POD 對象 說明&#xff1a;POD 全稱是“Plain Old Data”&#xff0c;是 C 98 標準(ISO/IEC 14882, first edition, 1998-09-01)中引入的一個概念&#xff0c; PO…