1. 程式人生 > >資料庫事務(二): java事務處理

資料庫事務(二): java事務處理

在平時我們做業務開發的時候,資料庫操作一般都需要使用到事務。如果是基於spring的專案,很簡單,有兩種方法:
1.配置一個DataSource給spring容器託管,再配置一個TransactionManager事務管理器,然後在需要事務的方法上加上Transactional註解就ok,這樣的話方法結束後事務才提交。
2. 配置好TransactionManager事務管理器後,可以在配置一個程式設計式事務模版,資料庫操作時直接呼叫程式設計式事務就ok,而這樣的話執行完所有sql語句後事務就提交,無需等待整個方法跑完。
這些簡單操作的背後,框架給我們做了太多的工作,作為一個有技術追求的程式設計師,應該瞭解Java事務的底層工作原理。

JDBC提供的事務處理api

java通過jdbc與資料庫進行互動,現在一般不直接使用jdbc,大多采用mybatis、hibernate等orm框架。但這些框架的底層,還是繞不開jdbc,事務處理同樣如此。
JDBC提供的事務處理API非常少,請不要被Spring中事務處理的那一堆原始碼所打擊得信心盡失,這些框架提供的事務處理功能歸根結底主要通過以java.sql.Connection類的方法完成:
Connection.setAutoCommit(boolean);
Connection.commit();
Connection.rollback();
在javax.sql.DataSource中,通過我們自己配置的資料庫DataSource,可以獲得Connection物件:

public interface DataSource  extends CommonDataSource, Wrapper {
    Connection getConnection() throws SQLException;
    ...
}

java底層的事務處理就是依靠上訴的兩個物件和幾個方法實現的。

舉一個例子,銀行轉賬方法transfer,將A賬號下的一筆前轉到B賬號下,分兩步,從A中扣除一筆錢,再在B中扣除一筆錢,程式碼如下:

public class BankServiceImpl implements BankService{
    private DataSource dataSource;
    //建構函式,傳如DataSource物件
public BankServiceImpl(DataSource dataSource){ this.dataSource=dataSource; } //轉賬方法 public void transfer(int fromId, int toId, int amount){ Connection connection = dataSource.getConnection(); //自動提交設為false connection.setAutoCommit(false); //呼叫倉儲層方法扣款和加款 bankDao.withdraw(fromId,amount); bankDao.deposit(toId,amount); //提交 connection.commit(); }catch (Exception e) { try { assert connection != null; connection.rollback(); } catch (SQLException e1) { e1.printStackTrace(); } } finally { try{ assert connection != null; connection.close(); } catch (SQLException e){ e.printStackTrace(); } } } }

在上訴transfer方法中,要想保證資料的一致性,也就是事務起作用,必須保證整個轉賬流程都使用的是同一個Connection物件。也就是說,BankService.transfer()方法、BankDao.withdraw()、BankDao.deposit()方法,需呼叫同一個Connection物件。

因此,上訴的事務處理是錯誤的,無法保證Service和Dao層呼叫的是同一個Connection物件。
實際上,java事務處理,包括其它的一些框架spring,最關鍵的地方其實也是如何保證呼叫同一個Connection物件。
下一篇我們探討如何自己構建一個TransactionManager,保證獲得同一個Connection物件,從而實現可靠的事務處理,保證資料一致性。