【Android】Room数据库的基本使用
一、什么是Room
1.1 Room简介
Room是Android Jetpack组件库中的一部分,对SQLite进行了封装,简化了对SQLite数据库的操作,让开发者使用面向对象的方式(通过Java/Kotlin)来操作SQLite数据库,从而避免了编写大量繁琐的SQL代码和解析数据。
1.2 三大核心组件
- Entity(实体类):用于表示数据库表的数据结构。
- DAO(Data A***ess Object):用于定义数据库操作的方法。
- Database(数据库类):用于创建数据库实例,并将 Entity 和 DAO 关联起来
二、使用步骤
2.1 添加依赖
在app下的build.gradle下添加:
// app/build.gradle
dependencies {
implementation "androidx.room:room-runtime:2.6.1"
annotationProcessor "androidx.room:room-***piler:2.6.1"
}
2.2 创建实体类 (Entity)
创建一个表示数据库表的 Java 类:
@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 MyUser(int age, String name, String email) {
this.age = age;
this.name = name;
this.email = email;
}
// Getter 和 Setter 方法
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; }
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
}
- 各注解作用:
-
@Entity(tableName = "user-room"):标记这是一个数据库表,同时指定表名 -
@PrimaryKey(autoGenerate = true):设置主键并启用自动生成 -
@ColumnInfo(name = "user_age"):设置列名
2.3 创建数据访问对象(DAO)
创建一个接口定义数据库操作:
@Dao
public interface MyUserDao {
// 插入用户
@Insert
void insertUser(MyUser user);
// 更新用户(通过对象)
@Update
int updateUser(MyUser user);
// 更新用户(通过名称,将age更新为传入的值)
@Query("UPDATE `user-room` SET user_age = :age WHERE user_name = :name")
int updateUser(String name, int age);
// 查询所有用户
@Query("SELECT * FROM `user-room`")
List<MyUser> getAllUsers();
// 查询特定用户(通过名称)
@Query("SELECT * FROM `user-room` WHERE user_name = :name")
List<MyUser> getUserByName(String name);
// 删除用户(通过对象)
@Delete
int deleteUser(MyUser user);
// 删除用户(通过名称)
@Query("DELETE FROM `user-room` WHERE user_name = :name")
int deleteUserByName(String name);
}
- 各注解作用:
-
@Dao:标记这是一个数据访问对象接口 -
@Insert、@Update、@Delete:由Room 提供的便捷注解,可以自动生成对应 SQL -
@Query:自定义 SQL 查询,:参数名表示方法参数
2.4 创建数据库类
创建一个抽象类用于扩展 RoomDatabase:
@Database(entities = {MyUser.class}, version = 1)
public abstract class MyUserDatabase extends RoomDatabase {
public abstract MyUserDao userDao();
// 数据库迁移(版本1到2)
static final Migration MIGRATION_1_2 = new Migration(1, 2) {
@Override
public void migrate(@NonNull SupportSQLiteDatabase database) {
// 添加新列user_email
database.execSQL("ALTER TABLE `user-room` ADD COLUMN user_email TEXT");
}
};
}
- 各注解作用:
-
@Database(entities = {MyUser.class}, version = 1):标记数据库类,指定包含的表和版本号 -
Migration:定义数据库版本迁移逻辑
关于数据库迁移:
-
数据库迁移的核心作用是在修改数据库结构后(比如在实体类中添加新字段或是在库中添加新表),安全、无损地将旧版本数据库升级到新版本,同时保留用户的原有数据。
-
版本迁移逻辑:必须增加数据库的版本号,并提供一个Migration对象来告诉Room如何从旧版本正确迁移到新版本。
2.5 在Activity中使用数据库
在Activity中初始化数据库并执行操作:
public class MainActivity extends App***patActivity {
private MyUserDatabase userDatabase;
private EditText nameEditText, ageEditText, emailEditText;
private TextView resultTextView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 初始化视图
nameEditText = findViewById(R.id.et_name);
ageEditText = findViewById(R.id.et_age);
emailEditText = findViewById(R.id.et_email);
resultTextView = findViewById(R.id.tv_result);
// 初始化数据库
userDatabase = Room.databaseBuilder(getApplicationContext(),
MyUserDatabase.class, "user-database.db")
.addMigrations(MyUserDatabase.MIGRATION_1_2) // 添加迁移规则
.build();
// 设置按钮点击事件
findViewById(R.id.btn_insert).setOnClickListener(v -> insertUser());
findViewById(R.id.btn_query).setOnClickListener(v -> queryUsers());
findViewById(R.id.btn_update).setOnClickListener(v -> updateUser());
findViewById(R.id.btn_delete).setOnClickListener(v -> deleteUser());
}
// 插入用户
private void insertUser() {
new Thread(() -> {
try {
String name = nameEditText.getText().toString();
int age = Integer.parseInt(ageEditText.getText().toString());
String email = emailEditText.getText().toString();
MyUser user = new MyUser(age, name, email);
userDatabase.userDao().insertUser(user);
runOnUiThread(() -> Toast.makeText(MainActivity.this,
"用户添加成功", Toast.LENGTH_SHORT).show());
} catch (Exception e) {
e.printStackTrace();
}
}).start();
}
// 查询用户
private void queryUsers() {
new Thread(() -> {
List<MyUser> users = userDatabase.userDao().getAllUsers();
StringBuilder result = new StringBuilder("所有用户:\n");
for (MyUser user : users) {
result.append("ID: ").append(user.getId())
.append(", 姓名: ").append(user.getName())
.append(", 年龄: ").append(user.getAge())
.append(", 邮箱: ").append(user.getEmail())
.append("\n");
}
runOnUiThread(() -> resultTextView.setText(result.toString()));
}).start();
}
// 更新用户
private void updateUser() {
new Thread(() -> {
try {
String name = nameEditText.getText().toString();
int age = Integer.parseInt(ageEditText.getText().toString());
int updatedRows = userDatabase.userDao().updateUser(name, age);
runOnUiThread(() -> Toast.makeText(MainActivity.this,
"更新了 " + updatedRows + " 行数据", Toast.LENGTH_SHORT).show());
} catch (Exception e) {
e.printStackTrace();
}
}).start();
}
// 删除用户
private void deleteUser() {
new Thread(() -> {
try {
String name = nameEditText.getText().toString();
int deletedRows = userDatabase.userDao().deleteUserByName(name);
runOnUiThread(() -> Toast.makeText(MainActivity.this,
"删除了 " + deletedRows + " 行数据", Toast.LENGTH_SHORT).show());
} catch (Exception e) {
e.printStackTrace();
}
}).start();
}
@Override
protected void onDestroy() {
super.onDestroy();
if (userDatabase != null && userDatabase.isOpen()) {
userDatabase.close();
}
}
}
2.5.1 创建数据库
// 初始化数据库
userDatabase = Room.databaseBuilder(getApplicationContext(),
MyUserDatabase.class, "user-database.db")
.addMigrations(MyUserDatabase.MIGRATION_1_2) // 添加迁移规则
.build();
- 参数一:上下文
- 参数二:数据库的class对象
- 参数三:表示要创建的 SQLite 数据库文件的名称。
2.5.1 增
// 插入用户
@Insert
void insertUser(MyUser user);
// 插入用户
private void insertUser() {
new Thread(() -> {
try {
String name = nameEditText.getText().toString();
int age = Integer.parseInt(ageEditText.getText().toString());
String email = emailEditText.getText().toString();
MyUser user = new MyUser(age, name, email);
userDatabase.userDao().insertUser(user);
runOnUiThread(() -> Toast.makeText(MainActivity.this,
"用户添加成功", Toast.LENGTH_SHORT).show());
} catch (Exception e) {
e.printStackTrace();
}
}).start();
}
主要要在非主线程中进行,数据库操作是一个非常耗时的操作,在主线程进行可能会引起卡顿和崩溃,不过在Room操作中可以不用新开线程,因为它内部已经帮我们处理好了
2.5.2 删
// 删除用户(通过对象)
@Delete
int deleteUser(MyUser user);
// 删除用户(通过名称)
@Query("DELETE FROM `user-room` WHERE user_name = :name")
int deleteUserByName(String name);
// 删除用户
private void deleteUser() {
new Thread(() -> {
try {
String name = nameEditText.getText().toString();
int deletedRows = userDatabase.userDao().deleteUserByName(name);
runOnUiThread(() -> Toast.makeText(MainActivity.this,
"删除了 " + deletedRows + " 行数据", Toast.LENGTH_SHORT).show());
} catch (Exception e) {
e.printStackTrace();
}
}).start();
}
2.5.3 查
// 查询所有用户
@Query("SELECT * FROM `user-room`")
List<MyUser> getAllUsers();
// 查询用户
private void queryUsers() {
new Thread(() -> {
List<MyUser> users = userDatabase.userDao().getAllUsers();
StringBuilder result = new StringBuilder("所有用户:\n");
for (MyUser user : users) {
result.append("ID: ").append(user.getId())
.append(", 姓名: ").append(user.getName())
.append(", 年龄: ").append(user.getAge())
.append(", 邮箱: ").append(user.getEmail())
.append("\n");
}
runOnUiThread(() -> resultTextView.setText(result.toString()));
}).start();
}
2.5.4 改
// 更新用户(通过对象)
@Update
int updateUser(MyUser user);
// 更新用户(通过名称,将age更新为传入的值)
@Query("UPDATE `user-room` SET user_age = :age WHERE user_name = :name")
int updateUser(String name, int age);
// 更新用户
private void updateUser() {
new Thread(() -> {
try {
String name = nameEditText.getText().toString();
int age = Integer.parseInt(ageEditText.getText().toString());
int updatedRows = userDatabase.userDao().updateUser(name, age);
runOnUiThread(() -> Toast.makeText(MainActivity.this,
"更新了 " + updatedRows + " 行数据", Toast.LENGTH_SHORT).show());
} catch (Exception e) {
e.printStackTrace();
}
}).start();
}
2.6 布局文件(activity_main)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.***/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp">
<EditText
android:id="@+id/et_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="输入姓名"/>
<EditText
android:id="@+id/et_age"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="输入年龄"
android:inputType="number"/>
<EditText
android:id="@+id/et_email"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="输入邮箱"
android:inputType="textEmailAddress"/>
<Button
android:id="@+id/btn_insert"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="添加用户"/>
<Button
android:id="@+id/btn_query"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="查询所有用户"/>
<Button
android:id="@+id/btn_update"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="更新用户"/>
<Button
android:id="@+id/btn_delete"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="删除用户"/>
<TextView
android:id="@+id/tv_result"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"/>
</LinearLayout>