Files
mkdocs/docs/android面试/数据存储/SQLite数据库.md
2026-01-15 11:53:37 +08:00

6.3 KiB
Raw Blame History

SQLite数据库

目录


SQLite基础

SQLite 简介

// SQLite轻量级关系型数据库
// - 嵌入式数据库
// - 无需服务器
// - 支持 SQL 语法
// - 适合移动应用

创建数据库

public class DatabaseHelper extends SQLiteOpenHelper {
    private static final String DATABASE_NAME = "my_database.db";
    private static final int DATABASE_VERSION = 1;
    
    public DatabaseHelper(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
    }
    
    @Override
    public void onCreate(SQLiteDatabase db) {
        // 创建表
        db.execSQL("CREATE TABLE user (" +
            "id INTEGER PRIMARY KEY AUTOINCREMENT," +
            "name TEXT NOT NULL," +
            "email TEXT," +
            "age INTEGER" +
            ")");
    }
    
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        // 升级数据库
        db.execSQL("DROP TABLE IF EXISTS user");
        onCreate(db);
    }
}

SQLite操作

插入数据

// 方式1使用 execSQL
db.execSQL("INSERT INTO user (name, email, age) VALUES (?, ?, ?)",
    new String[]{"John", "john@example.com", "25"});

// 方式2使用 insert
ContentValues values = new ContentValues();
values.put("name", "John");
values.put("email", "john@example.com");
values.put("age", 25);
long id = db.insert("user", null, values);

查询数据

// 查询所有
Cursor cursor = db.query("user", null, null, null, null, null, null);

// 条件查询
Cursor cursor = db.query("user",
    new String[]{"id", "name", "email"},
    "age > ?",
    new String[]{"18"},
    null, null, "name ASC");

// 使用 SQL
Cursor cursor = db.rawQuery("SELECT * FROM user WHERE age > ?", new String[]{"18"});

// 遍历结果
while (cursor.moveToNext()) {
    int id = cursor.getInt(cursor.getColumnIndex("id"));
    String name = cursor.getString(cursor.getColumnIndex("name"));
    String email = cursor.getString(cursor.getColumnIndex("email"));
}
cursor.close();

更新数据

// 方式1使用 execSQL
db.execSQL("UPDATE user SET name = ? WHERE id = ?",
    new String[]{"Jane", "1"});

// 方式2使用 update
ContentValues values = new ContentValues();
values.put("name", "Jane");
int count = db.update("user", values, "id = ?", new String[]{"1"});

删除数据

// 方式1使用 execSQL
db.execSQL("DELETE FROM user WHERE id = ?", new String[]{"1"});

// 方式2使用 delete
int count = db.delete("user", "id = ?", new String[]{"1"});

SQLite性能优化

1. 使用索引

// 创建索引
db.execSQL("CREATE INDEX idx_name ON user(name)");

2. 使用事务

// 批量操作使用事务
db.beginTransaction();
try {
    for (int i = 0; i < 1000; i++) {
        db.insert("user", null, values);
    }
    db.setTransactionSuccessful();
} finally {
    db.endTransaction();
}

3. 使用预编译语句

// 使用 SQLiteStatement
SQLiteStatement stmt = db.compileStatement(
    "INSERT INTO user (name, email) VALUES (?, ?)");
stmt.bindString(1, "John");
stmt.bindString(2, "john@example.com");
stmt.executeInsert();
stmt.close();

4. 避免 N+1 查询

// ❌ 问题N+1 查询
List<User> users = getUsers();
for (User user : users) {
    List<Order> orders = getOrdersByUserId(user.getId()); // N 次查询
}

// ✅ 解决:使用 JOIN
SELECT u.*, o.* FROM user u LEFT JOIN order o ON u.id = o.user_id

SQLite事务

事务使用

// 开始事务
db.beginTransaction();
try {
    // 执行多个操作
    db.insert("user", null, values1);
    db.insert("user", null, values2);
    db.insert("user", null, values3);
    
    // 标记事务成功
    db.setTransactionSuccessful();
} finally {
    // 结束事务(如果未标记成功,会回滚)
    db.endTransaction();
}

事务优势

// 1. 原子性:要么全部成功,要么全部失败
// 2. 性能:批量操作性能更好
// 3. 一致性:保证数据一致性

SQLite索引

创建索引

// 单列索引
db.execSQL("CREATE INDEX idx_name ON user(name)");

// 复合索引
db.execSQL("CREATE INDEX idx_name_age ON user(name, age)");

// 唯一索引
db.execSQL("CREATE UNIQUE INDEX idx_email ON user(email)");

索引使用

// 索引会加速查询
// 但会增加写入开销和存储空间

// 适合创建索引的列:
// 1. 经常用于 WHERE 条件的列
// 2. 经常用于 JOIN 的列
// 3. 经常用于 ORDER BY 的列

SQLite最佳实践

1. 使用事务

// 批量操作使用事务
db.beginTransaction();
try {
    // 批量操作
    db.setTransactionSuccessful();
} finally {
    db.endTransaction();
}

2. 及时关闭 Cursor

// ✅ 正确
Cursor cursor = db.query(...);
try {
    // 使用 cursor
} finally {
    cursor.close();
}

// ❌ 错误:忘记关闭
Cursor cursor = db.query(...);
// 使用 cursor
// 忘记关闭,可能导致内存泄漏

3. 使用预编译语句

// 重复执行的 SQL 使用预编译语句
SQLiteStatement stmt = db.compileStatement("INSERT INTO user (name) VALUES (?)");

4. 数据库升级

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    // 根据版本号升级
    if (oldVersion < 2) {
        // 升级到版本2
    }
    if (oldVersion < 3) {
        // 升级到版本3
    }
}

面试常见问题

Q1: SQLite 的特点?

答案:

  • 轻量级关系型数据库
  • 嵌入式数据库,无需服务器
  • 支持 SQL 语法
  • 适合移动应用

Q2: 如何优化 SQLite 性能?

答案:

  1. 使用索引
  2. 使用事务
  3. 使用预编译语句
  4. 避免 N+1 查询

Q3: SQLite 事务的作用?

答案:

  1. 原子性:保证操作要么全部成功,要么全部失败
  2. 性能:批量操作性能更好
  3. 一致性:保证数据一致性

Q4: 什么时候创建索引?

答案:

  • 经常用于 WHERE 条件的列
  • 经常用于 JOIN 的列
  • 经常用于 ORDER BY 的列

最后更新2024年