328 lines
6.3 KiB
Markdown
328 lines
6.3 KiB
Markdown
# 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年*
|