Files
mkdocs/docs/android面试/数据存储/SQLite数据库.md

328 lines
6.3 KiB
Markdown
Raw Normal View History

2026-01-15 11:53:37 +08:00
# SQLite数据库
## 目录
- [SQLite基础](#sqlite基础)
- [SQLite操作](#sqlite操作)
- [SQLite性能优化](#sqlite性能优化)
- [SQLite事务](#sqlite事务)
- [SQLite索引](#sqlite索引)
- [SQLite最佳实践](#sqlite最佳实践)
- [面试常见问题](#面试常见问题)
---
## SQLite基础
### SQLite 简介
```java
// SQLite轻量级关系型数据库
// - 嵌入式数据库
// - 无需服务器
// - 支持 SQL 语法
// - 适合移动应用
```
### 创建数据库
```java
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操作
### 插入数据
```java
// 方式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);
```
### 查询数据
```java
// 查询所有
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();
```
### 更新数据
```java
// 方式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"});
```
### 删除数据
```java
// 方式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. 使用索引
```java
// 创建索引
db.execSQL("CREATE INDEX idx_name ON user(name)");
```
### 2. 使用事务
```java
// 批量操作使用事务
db.beginTransaction();
try {
for (int i = 0; i < 1000; i++) {
db.insert("user", null, values);
}
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
```
### 3. 使用预编译语句
```java
// 使用 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 查询
```java
// ❌ 问题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事务
### 事务使用
```java
// 开始事务
db.beginTransaction();
try {
// 执行多个操作
db.insert("user", null, values1);
db.insert("user", null, values2);
db.insert("user", null, values3);
// 标记事务成功
db.setTransactionSuccessful();
} finally {
// 结束事务(如果未标记成功,会回滚)
db.endTransaction();
}
```
### 事务优势
```java
// 1. 原子性:要么全部成功,要么全部失败
// 2. 性能:批量操作性能更好
// 3. 一致性:保证数据一致性
```
---
## SQLite索引
### 创建索引
```java
// 单列索引
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)");
```
### 索引使用
```java
// 索引会加速查询
// 但会增加写入开销和存储空间
// 适合创建索引的列:
// 1. 经常用于 WHERE 条件的列
// 2. 经常用于 JOIN 的列
// 3. 经常用于 ORDER BY 的列
```
---
## SQLite最佳实践
### 1. 使用事务
```java
// 批量操作使用事务
db.beginTransaction();
try {
// 批量操作
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
```
### 2. 及时关闭 Cursor
```java
// ✅ 正确
Cursor cursor = db.query(...);
try {
// 使用 cursor
} finally {
cursor.close();
}
// ❌ 错误:忘记关闭
Cursor cursor = db.query(...);
// 使用 cursor
// 忘记关闭,可能导致内存泄漏
```
### 3. 使用预编译语句
```java
// 重复执行的 SQL 使用预编译语句
SQLiteStatement stmt = db.compileStatement("INSERT INTO user (name) VALUES (?)");
```
### 4. 数据库升级
```java
@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年*