上一篇
安卓开发之sqlite数据库
- 行业动态
- 2025-04-22
- 6
SQLite数据库简介
Android内置了SQLite数据库,支持轻量级本地数据存储,适用于:
- 离线数据缓存
- 用户配置保存
- 小规模数据管理
核心类:SQLiteDatabase
(操作数据库)、SQLiteOpenHelper
(管理数据库创建与升级)
创建与初始化数据库
定义SQLiteOpenHelper
子类
public class MyDatabaseHelper extends SQLiteOpenHelper { private static final String DATABASE_NAME = "app_data.db"; private static final int DATABASE_VERSION = 1; public MyDatabaseHelper(Context context) { super(context, DATABASE_NAME, null, DATABASE_VERSION); } @Override public void onCreate(SQLiteDatabase db) { // 创建表语句 String sql = "CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, age INTEGER)"; db.execSQL(sql); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { // 升级时删除旧表并创建新表(慎用!需考虑数据迁移) db.execSQL("DROP TABLE IF EXISTS users"); onCreate(db); } }
获取数据库实例
MyDatabaseHelper dbHelper = new MyDatabaseHelper(context); SQLiteDatabase db = dbHelper.getWritableDatabase(); // 读写权限 // 或 getReadableDatabase() 仅读权限
基本数据库操作
插入数据
ContentValues values = new ContentValues(); values.put("name", "Alice"); values.put("age", 25); long rowId = db.insert("users", null, values); // 返回插入行的ID
查询数据
// 查询所有用户 Cursor cursor = db.query("users", null, null, null, null, null, null); while (cursor.moveToNext()) { int id = cursor.getInt(cursor.getColumnIndex("id")); String name = cursor.getString(cursor.getColumnIndex("name")); int age = cursor.getInt(cursor.getColumnIndex("age")); // 处理数据... } cursor.close(); // 必须关闭游标
更新数据
ContentValues values = new ContentValues(); values.put("age", 26); int rowsAffected = db.update("users", values, "name=?", new String[]{"Alice"});
删除数据
int rowsDeleted = db.delete("users", "age < ?", new String[]{"20"}); // 删除年龄小于20的用户
数据库升级与迁移
版本号管理
DATABASE_VERSION
用于标识数据库结构版本- 每次结构变更需递增版本号,并在
onUpgrade
中处理迁移逻辑
数据迁移策略(示例)
@Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { if (oldVersion < 2) { // 添加新字段 db.execSQL("ALTER TABLE users ADD COLUMN email TEXT"); } if (oldVersion < 3) { // 复杂迁移:创建临时表 → 数据复制 → 替换旧表 } }
异步操作与线程安全
主线程禁止数据库操作
Android从API 11开始禁止在主线程执行数据库读写,否则抛NetworkOnMainThreadException
。
解决方案:
AsyncTask
(已过时,建议用其他方式)ExecutorService
LiveData
+ViewModel
(架构组件)- Kotlin协程(推荐)
Kotlin协程示例
GlobalScope.launch(Dispatchers.IO) { val db = dbHelper.writableDatabase db.insert("users", null, mapOf("name" to "Bob", "age" to 30)) // 其他操作... }
常见问题与优化
问题 | 解决方案 |
---|---|
多线程并发访问冲突 | 使用synchronized 或SQLiteDatabase.acquireLock() ,推荐通过单例模式管理SQLiteOpenHelper |
内存泄漏 | 避免长时间持有SQLiteDatabase 引用,及时关闭Cursor |
大数据量查询性能差 | 分页查询(LIMIT + OFFSET )、索引优化(CREATE INDEX ) |
敏感数据存储安全 | 使用SQLCipher 加密数据库,或AES加密后存储 |
相关问题与解答
问题1:如何将SQLite数据库迁移到Room持久库?
解答:
Room是Android官方推荐的抽象层,提供更简洁的API和编译时校验,迁移步骤:
- 定义
@Entity
实体类映射表结构 - 创建
@Dao
接口定义增删改查方法 - 通过
Room.databaseBuilder()
构建数据库实例 - 迁移原有SQLite逻辑到Room(需处理版本升级)
优势:类型安全、支持LiveData、RxJava、协程。
问题2:SQLite支持事务吗?如何保证原子性?
解答:
- 支持事务,通过
beginTransaction()
和setTransactionSuccessful()
实现 - 示例:
db.beginTransaction(); try { db.insert(...); db.update(...); db.setTransactionSuccessful(); // 标记成功 } finally { db.endTransaction(); // 提交或回滚 }
- 事务可确保多条操作要么全部成功,要么全部撤销