当前位置: 首页 > news >正文

Android开发-数据库SQLite

一、SQLite 基础:Android 内置的轻量级数据库

1. 什么是 SQLite?

  • 轻量级、嵌入式、零配置的 SQL 数据库引擎
  • 数据存储在设备的私有目录中(/data/data/<package_name>/databases/)。
  • 支持标准的 SQL 语法(如 CREATEINSERTUPDATEDELETESELECT)。
  • 单文件数据库,无需独立的服务器进程。

2. 原生 SQLite 操作(不推荐直接使用)

// 继承 SQLiteOpenHelper
public class MyDatabaseHelper extends SQLiteOpenHelper {private static final String DB_NAME = "app.db";private static final int DB_VERSION = 1;public MyDatabaseHelper(Context context) {super(context, DB_NAME, null, DB_VERSION);}@Overridepublic void onCreate(SQLiteDatabase db) {String CREATE_TABLE_USER = "CREATE TABLE users (" +"id INTEGER PRIMARY KEY AUTOINCREMENT, " +"name TEXT NOT NULL, " +"age INTEGER, " +"email TEXT UNIQUE)";db.execSQL(CREATE_TABLE_USER);}@Overridepublic void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {db.execSQL("DROP TABLE IF EXISTS users");onCreate(db);}
}

⚠️ 问题:代码繁琐、易出错、SQL 字符串拼接风险、无编译时检查。

二、Room 持久化库:现代化的 SQLite 抽象

Room 在 SQLite 基础上提供了三个核心组件:

  1. @Entity:定义数据库表和实体类。
  2. @Dao (Data Access Object):定义数据访问方法(增删改查)。
  3. @Database:数据库持有者,作为访问底层数据源的入口。

1. 添加依赖

app/build.gradle 中添加:

dependencies {def room_version = "2.6.1"implementation "androidx.room:room-runtime:$room_version"annotationProcessor "androidx.room:room-compiler:$room_version" // For Java// Kotlin 使用 kapt// kapt "androidx.room:room-compiler:$room_version"// 可选:Room Kotlin 协程支持implementation "androidx.room:room-ktx:$room_version"// 可选:RxJava 支持implementation "androidx.room:room-rxjava3:$room_version"
}

2. 定义 Entity(实体类)

@Entity(tableName = "users")
public class User {@PrimaryKey(autoGenerate = true)public long id;@ColumnInfo(name = "name")public String name;@ColumnInfo(name = "age")public int age;@ColumnInfo(name = "email", index = true) // 添加索引public String email;// 必须提供空参构造函数或 Room 兼容的构造函数public User() {}public User(String name, int age, String email) {this.name = name;this.age = age;this.email = email;}// Getter 和 Setter ...
}

关键注解

  • @Entity:标记为数据库表。
  • @PrimaryKey:主键,autoGenerate=true 自动增长。
  • @ColumnInfo:指定列名、是否索引等。
  • @Ignore:忽略该字段,不存入数据库。

3. 定义 DAO(数据访问对象)

@Dao
public interface UserDao {// 插入@Insertlong insertUser(User user); // 返回插入行的主键@InsertList<Long> insertUsers(List<User> users); // 批量插入// 查询@Query("SELECT * FROM users")List<User> getAllUsers();@Query("SELECT * FROM users WHERE age > :minAge")List<User> getUsersOlderThan(int minAge);@Query("SELECT * FROM users WHERE name LIKE :name")List<User> findUsersByName(String name);@Query("SELECT * FROM users WHERE id = :userId")User getUserById(long userId);// 更新@Updateint updateUser(User user); // 返回更新的行数// 删除@Deleteint deleteUser(User user); // 返回删除的行数@Query("DELETE FROM users WHERE age < :minAge")int deleteUsersYoungerThan(int minAge);
}

优势

  • @Query:编写 SQL 查询,支持参数绑定(:paramName)。
  • @Insert@Update@Delete:无需写 SQL,Room 自动生成。
  • 编译时检查:SQL 语法错误在编译时报错,非运行时崩溃。

4. 定义 Database

@Database(entities = {User.class}, version = 1, exportSchema = false)
@TypeConverters({Converters.class}) // 注册类型转换器
public abstract class AppDatabase extends RoomDatabase {public static final String DATABASE_NAME = "app_database";// 抽象方法,返回 DAO 实例public abstract UserDao userDao();// 单例模式private static volatile AppDatabase INSTANCE;public static AppDatabase getInstance(Context context) {if (INSTANCE == null) {synchronized (AppDatabase.class) {if (INSTANCE == null) {INSTANCE = Room.databaseBuilder(context.getApplicationContext(),AppDatabase.class, DATABASE_NAME)// .allowMainThreadQueries() // ❌ 仅用于测试,禁止在主线程查询.addCallback(roomCallback) // 数据库创建/升级回调.build();}}}return INSTANCE;}// 数据库回调private static RoomDatabase.Callback roomCallback = new RoomDatabase.Callback() {@Overridepublic void onCreate(@NonNull SupportSQLiteDatabase db) {super.onCreate(db);// 数据库创建时执行,如插入初始数据new PopulateDbAsync(INSTANCE).execute();}};// 异步填充初始数据static class PopulateDbAsync extends AsyncTask<Void, Void, Void> {private UserDao userDao;PopulateDbAsync(AppDatabase db) {userDao = db.userDao();}@Overrideprotected Void doInBackground(Void... voids) {userDao.insertUser(new User("张三", 25, "zhangsan@email.com"));userDao.insertUser(new User("李四", 30, "lisi@email.com"));return null;}}
}

三、高级特性与最佳实践

1. 类型转换器(TypeConverters)

Room 默认不支持存储复杂类型(如 Date, List<String>, 自定义对象)。

public class Converters {@TypeConverterpublic static Date fromTimestamp(Long value) {return value == null ? null : new Date(value);}@TypeConverterpublic static Long dateToTimestamp(Date date) {return date == null ? null : date.getTime();}// 存储 List<String> 为 JSON 字符串@TypeConverterpublic static List<String> fromString(String value) {if (value == null || value.isEmpty()) return Collections.emptyList();return Arrays.asList(value.split(","));}@TypeConverterpublic static String toString(List<String> list) {return list == null ? null : TextUtils.join(",", list);}
}

@Database 上使用 @TypeConverters({Converters.class})

2. 数据库升级(Migration)

version 增加时,必须提供 Migration 策略。

static final Migration MIGRATION_1_2 = new Migration(1, 2) {@Overridepublic void migrate(@NonNull SupportSQLiteDatabase database) {// 例如:添加新列database.execSQL("ALTER TABLE users ADD COLUMN phone TEXT");}
};// 在 databaseBuilder 中添加
.addMigrations(MIGRATION_1_2)

⚠️ 重要:必须为每一对版本(如 1->2, 2->3)提供 Migration,或使用 fallbackToDestructiveMigration()慎用,会丢失数据)。

3. 异步操作(推荐)

绝对禁止在主线程进行数据库操作!

(1) 使用 ExecutorService
private ExecutorService executor = Executors.newFixedThreadPool(4);executor.execute(() -> {User user = AppDatabase.getInstance(context).userDao().getUserById(1);// 在子线程中处理结果,再切回主线程更新 UI
});
(2) 使用 Kotlin 协程(推荐)
// 在 DAO 中返回 Flow 或 suspend 函数
@Query("SELECT * FROM users")
fun getAllUsers(): Flow<List<User>> // Flow 支持实时更新@Query("SELECT * FROM users WHERE id = :id")
suspend fun getUserById(id: Long): User
(3) 使用 RxJava
@Query("SELECT * FROM users")
Observable<List<User>> getAllUsers();

4. 关系查询(@Relation)

Room 支持简单的关联查询(1对1,1对多)。

public class UserWithBooks {@Embeddedpublic User user;@Relation(parentColumn = "id",entityColumn = "user_id")public List<Book> books;
}

5. 全文搜索(FTS)

使用 @Fts3@Fts4 注解创建全文搜索表。

四、最佳实践总结

实践说明
✅ 使用 Room 而非原生 SQLite更安全、更高效、更易维护
✅ 异步操作使用协程、RxJava 或 Executor
✅ 数据库版本管理提供 Migration,避免数据丢失
✅ 合理使用索引在频繁查询的列上添加 index = true
✅ 避免 N+1 查询使用 @Relation 或 JOIN 查询一次性获取关联数据
✅ 编译时检查依赖 room-compiler,及时发现 SQL 错误
✅ 数据观察使用 LiveData 或 Flow 实现数据变更自动刷新 UI

五、Room vs 原生 SQLite vs 其他方案

方案优点缺点推荐度
原生 SQLite完全控制,性能极致代码繁琐,易出错,无编译检查
Room类型安全,编译检查,抽象层,性能好需学习注解⭐⭐⭐⭐⭐
Realm实时同步,跨平台,易用商业许可,APK 体积大⭐⭐⭐
ObjectBox速度极快,NoSQL学习成本,社区较小⭐⭐⭐

结论:对于绝大多数 Android 应用,Room 是首选

六、动手实践:构建一个笔记应用

  1. 创建 Note Entity(包含 id, title, content, timestamp)。
  2. 定义 NoteDao(增删改查,按标题搜索)。
  3. 创建 NoteDatabase
  4. 使用 ViewModel 和 LiveData 观察数据变化。
  5. 在 RecyclerView 中展示笔记列表

七、结语

感谢您的阅读!如果你有任何疑问或想要分享的经验,请在评论区留言交流!


文章转载自:

http://lT7J8iXh.zcsch.cn
http://0qw8cspe.zcsch.cn
http://wCZv7uem.zcsch.cn
http://Pl4XMXe2.zcsch.cn
http://9SCrT6OF.zcsch.cn
http://AcycdmoY.zcsch.cn
http://2GGLpDZT.zcsch.cn
http://cXM3eBFX.zcsch.cn
http://4qO6byX7.zcsch.cn
http://rCB7EVe0.zcsch.cn
http://DPHAJ3nn.zcsch.cn
http://6AFwtx1i.zcsch.cn
http://AdkKeq9y.zcsch.cn
http://weE3hs2Q.zcsch.cn
http://Kb8dzwiQ.zcsch.cn
http://dT6xSK1S.zcsch.cn
http://CUoDfav9.zcsch.cn
http://fGSp8hUA.zcsch.cn
http://b2TdXALD.zcsch.cn
http://2ZZu5Kfe.zcsch.cn
http://YG0cO78f.zcsch.cn
http://t0mkNo1Q.zcsch.cn
http://8jGKuey4.zcsch.cn
http://4eFrnYEt.zcsch.cn
http://tzCGtiOP.zcsch.cn
http://9TyBRxok.zcsch.cn
http://5S6NbsaW.zcsch.cn
http://WMZKa6Q6.zcsch.cn
http://S8XfO9bR.zcsch.cn
http://b1yM9Qv8.zcsch.cn
http://www.dtcms.com/a/383700.html

相关文章:

  • (附源码)基于springboot的幼儿园管理系统
  • 【从零到公网】本地电脑部署服务并实现公网访问(IPv4/IPv6/DDNS 全攻略)
  • VTK基础(01):VTK中的基本概念
  • Sentinel:微服务架构下的高可用流量防卫兵
  • Unity学习----【进阶】TextMeshPro学习(三)--进阶知识点(TMP基础设置,材质球相关,两个辅助工具类)
  • OpenCV:指纹识别
  • map/multimap容器
  • leetcode 966. 元音拼写检查器 中等
  • esp32程序存储结构--自用笔记版
  • leetcode 21 合并两个有序链表
  • OneCode 移动套件多平台适配详细报告
  • RAGAS新手入门教程:从基础到实践
  • 在 CentOS 中安装 VirtualBox 增强功能的步骤
  • 网络编程-day4
  • 学习笔记:第一个Python程序
  • Docker-compose.yml集群设置
  • 课后作业-2025-09-14
  • 软件工程实践一:Git 使用教程(含分支与 Gitee)
  • 知识贡献缺乏激励该如何改善
  • 一个冷门算法——Floyd判圈算法在Leetcode中的应用
  • 程晓明在链改 2.0 六方会谈首提 “双众筹 + 私交所” 回应 RWA 国内落地可行方案
  • 【车载audio开发】【基础概念1】【音频基础概念通俗讲解】
  • O3DE社区发布2505.0版本
  • VSCode 的 Run and Debug 下拉菜单都是怎么配置的,原理是什么?
  • Ligero 和 Brakedown PCS中的tensor product结构
  • 高效群签名方案与优化方法
  • [第一章] web入门—N1book靶场详细思路讲解(二)
  • 行优先 vs 列优先:性能差异揭秘
  • python把文件从一个文件复制到另一个文件夹
  • 平衡车 -- 遥控器