面试题答案
一键面试数据库索引创建
- 分析查询语句:仔细研究项目中频繁执行的SQL查询,特别是
WHERE
子句中涉及的列。例如,如果经常执行SELECT * FROM users WHERE age > 30
,那么在age
列上创建索引可能会显著提升查询性能。 - 使用索引注解:在Room中,可以在实体类的相应字段上使用
@Index
注解来创建索引。示例如下:
@Entity(indices = [Index("age")])
data class User(
@PrimaryKey val id: Int,
val name: String,
val age: Int
)
- 复合索引:对于涉及多个列的查询,如
SELECT * FROM orders WHERE customer_id = 1 AND order_date > '2023 - 01 - 01'
,可以创建复合索引。在Room中这样定义:
@Entity(indices = [Index(value = ["customer_id", "order_date"], unique = false)])
data class Order(
@PrimaryKey val id: Int,
val customer_id: Int,
val order_date: String
)
批量操作
- 使用事务进行批量插入/更新:Room允许在一个事务中执行多个数据操作。例如,批量插入用户数据:
@Dao
interface UserDao {
@Insert
fun insertUser(user: User)
@Transaction
fun insertUsers(users: List<User>) {
users.forEach { insertUser(it) }
}
}
- 减少数据库交互次数:批量操作减少了应用程序与数据库之间的交互次数,从而提高了性能。相比于逐个插入数据,批量插入在一次数据库事务中完成所有操作,降低了开销。
缓存策略
- 内存缓存:在应用层实现简单的内存缓存,特别是对于经常读取但不经常变化的数据。例如,可以使用
HashMap
来缓存用户数据。
private val userCache = HashMap<Int, User>()
fun getUserFromCache(id: Int): User? = userCache[id]
fun putUserInCache(user: User) {
userCache[user.id] = user
}
- 结合Room和缓存:在查询数据时,首先检查缓存中是否存在数据。如果存在,则直接返回缓存数据;否则,从数据库中查询,并将查询结果存入缓存。
fun getUser(id: Int): User {
getUserFromCache(id)?.let { return it }
val user = userDao.getUserById(id)
putUserInCache(user)
return user
}
事务管理
- 确保数据一致性和完整性:事务可以保证一组数据库操作要么全部成功,要么全部失败。在Room中,可以使用
@Transaction
注解标记方法,在该方法内执行的所有数据库操作都在同一个事务中。例如,在一个电商应用中,当用户下单时,需要同时更新订单表和库存表,确保订单数量与库存数量的一致性。
@Dao
interface OrderDao {
@Insert
fun insertOrder(order: Order)
@Update
fun updateStock(stock: Stock)
@Transaction
fun placeOrder(order: Order, newStock: Stock) {
insertOrder(order)
updateStock(newStock)
}
}
- 复杂业务场景示例:假设一个社交应用,用户发布一条带有图片的动态,这涉及到向动态表插入动态信息,向图片表插入图片信息,并关联动态和图片。
@Dao
interface PostDao {
@Insert
fun insertPost(post: Post)
@Insert
fun insertImage(image: Image)
@Insert
fun insertPostImageLink(link: PostImageLink)
@Transaction
fun createPostWithImage(post: Post, image: Image) {
val postId = insertPost(post)
val imageId = insertImage(image)
insertPostImageLink(PostImageLink(postId, imageId))
}
}
在上述示例中,如果任何一个操作失败,整个事务将回滚,确保数据的一致性和完整性。