面試官問:Redis的操作如何與數據庫事務保持一致

每天分享java乾貨,歡迎關注! 你的成功源於點點滴滴!

面試官問:Redis的操作如何與數據庫事務保持一致

  • redis 如何 與 數據庫保持一致性的問題?

場景:如果我們在開發過程中遇到這樣的一種情況,我們刪除 redis中token 的同時 也需要修改數據庫中 儲存的 token 的狀態為不可用的狀態。如果這個時候我們不做處理的話,通常是先刪除redis中的token,然後在進行數據庫的修改。但是如果這個時候redis中的token刪除成功了,但是在執行數據庫操作之氣程序報錯了。那這個時候redis中的token已經被刪除了,但是數據庫中的token狀態還是可用的狀態,這個時候就導致了數據不一致的問題。

這時候我們需要使用統一的事務來進行解決這個問題,.但是如果只是單純的使用數據庫事務並不能解決這個問題,因為這個操作也涉及到了redis,所以這個時候我們應該使用 redis事務+數據庫的事務 來保證事務一致性的問題。

如果只是單純添加了 @Transactional(聲明式事務)只能保證數據庫的數據一致性問題,但是是無法控制redis中的事務的。redis中也是存在事務的。

解決方案:

我們可以使用自定義方法使用編程式事務 我們使用 begin(即控制reids事務也控制數據庫事務)、commit、rollback 都需要實現控制redis事務和數據庫事務。

下面直接上代碼 ,

  • 這個類 包裝了redis事務和數據庫事務 ,一起開啟事務,一起提交事務,一起回滾事務
面試官問:Redis的操作如何與數據庫事務保持一致

  • redisUtils相關代碼:
面試官問:Redis的操作如何與數據庫事務保持一致

  • 在寫業務代碼時 大致這樣寫
面試官問:Redis的操作如何與數據庫事務保持一致

代碼如下 自己copy用


RedisDataSoureceTransaction 代碼:

@Component
@Scope(ConfigurableListableBeanFactory.SCOPE_PROTOTYPE)
public class RedisDataSoureceTransaction {
 @Autowired
 private RedisUtil redisUtil;
 /**
 * 數據源事務管理器
 */
 @Autowired
 private DataSourceTransactionManager dataSourceTransactionManager;
 /**
 * 開始事務 採用默認傳播行為
 * 
 * @return
 */
 public TransactionStatus begin() {
 // 手動begin數據庫事務
 TransactionStatus transaction = dataSourceTransactionManager.getTransaction(new DefaultTransactionAttribute());
 redisUtil.begin();//
 return transaction;
 }
 /**
 * 提交事務
 * 
 * @param transactionStatus
 * 事務傳播行為
 * @throws Exception
 */
 public void commit(TransactionStatus transactionStatus) throws Exception {
 if (transactionStatus == null) {
 throw new Exception("transactionStatus is null");
 }
 // 支持Redis與數據庫事務同時提交
 dataSourceTransactionManager.commit(transactionStatus);
 redisUtil.exec();
 }
 /**
 * 回滾事務
 * 
 * @param transactionStatus
 * @throws Exception
 */
 public void rollback(TransactionStatus transactionStatus) throws Exception {
 if (transactionStatus == null) {
 throw new Exception("transactionStatus is null");
 }
 dataSourceTransactionManager.rollback(transactionStatus);
 redisUtil.discard();
 }

redisutil相關代碼:

/**
 * 開啟Redis 事務
 * 
 * @param isTransaction
 */
public void begin() {
 // 開啟Redis 事務權限
 stringRedisTemplate.setEnableTransactionSupport(true);
 // 開啟事務
 stringRedisTemplate.multi();
}
/**
 * 提交事務
 * 
 * @param isTransaction
 */
public void exec() {
 // 成功提交事務
 stringRedisTemplate.exec();
}
/**
 * 回滾Redis 事務
 */
public void discard() {
 stringRedisTemplate.discard();
}

業務的大致模板代碼:

@authwared 
private RedisDataSoureceTransaction manualTransaction 

TransactionStatus transactionStatus = null;
try {
 // // ####開啟手動事務
 transactionStatus = manualTransaction.begin();
 
 // 刪除或者更新數據庫的數據
 ...........(業務代碼省略)

 // 刪除或者更新redis的值
 .............(業務代碼省略)

 // #######提交事務
 manualTransaction.commit(transactionStatus);
 
} catch (Exception e) {
 try {
 // 回滾事務
 manualTransaction.rollback(transactionStatus);
 } catch (Exception e1) {
 }
 
}


分享到:


相關文章: