面试题答案
一键面试1. 双写方案
数据写入
- 先写MySQL:使用数据库事务确保数据准确写入MySQL表中。例如在Java中使用JDBC,开启事务后执行
INSERT
语句,成功后提交事务。
Connection conn = DriverManager.getConnection(url, user, password);
conn.setAutoCommit(false);
try {
PreparedStatement pstmt = conn.prepareStatement("INSERT INTO your_table (column1, column2) VALUES (?,?)");
pstmt.setString(1, value1);
pstmt.setString(2, value2);
pstmt.executeUpdate();
conn.commit();
} catch (SQLException e) {
conn.rollback();
e.printStackTrace();
}
- 再写Redis:利用Redis客户端将相同数据写入缓存。以Jedis为例:
Jedis jedis = new Jedis("localhost", 6379);
jedis.set("key", "value");
jedis.close();
数据更新
- 先更新MySQL:同样通过事务保证数据更新准确。如使用
UPDATE
语句:
Connection conn = DriverManager.getConnection(url, user, password);
conn.setAutoCommit(false);
try {
PreparedStatement pstmt = conn.prepareStatement("UPDATE your_table SET column1 =? WHERE id =?");
pstmt.setString(1, newValue1);
pstmt.setInt(2, id);
pstmt.executeUpdate();
conn.commit();
} catch (SQLException e) {
conn.rollback();
e.printStackTrace();
}
- 再更新Redis:确保Redis中的数据与MySQL同步更新:
Jedis jedis = new Jedis("localhost", 6379);
jedis.set("key", "newValue");
jedis.close();
2. 缓存失效方案
数据写入
- 写MySQL:通过事务确保数据成功写入MySQL。
- 使Redis缓存失效:不直接更新Redis,而是删除Redis中对应的缓存键。例如使用Jedis删除键:
Jedis jedis = new Jedis("localhost", 6379);
jedis.del("key");
jedis.close();
下次读取时,发现Redis中没有数据,就会从MySQL读取并重新写入Redis。
数据更新
- 更新MySQL:通过事务更新MySQL中的数据。
- 使Redis缓存失效:删除Redis中对应的缓存键,后续读取时重新加载数据到Redis。
3. 性能与可靠性考量
性能
- 批量操作:在写MySQL时,可以采用批量插入或更新语句,减少数据库交互次数。对于Redis,也支持批量操作,如
mset
等命令。 - 异步处理:将写Redis操作异步化,通过消息队列(如Kafka、RabbitMQ)来解耦。写MySQL成功后,发送消息到队列,由消费者负责更新或删除Redis缓存,提高系统整体响应速度。
可靠性
- 重试机制:对于写MySQL或Redis失败的情况,设置重试逻辑。例如在Java中可以使用
guava-retrying
库实现重试。 - 监控与报警:建立监控系统,实时监测MySQL和Redis的写入、更新操作状态。一旦出现异常,及时报警通知运维人员处理。
- 数据校验:定期进行MySQL和Redis数据的一致性校验,可通过定时任务扫描关键数据,发现不一致及时修复。