摘抄至網絡,記下來。 java
1、簡介: mysql
前面一遍提到了jdbc事務相關的概念。從中瞭解到事務應具備ACID特性。因此對於javaweb開發來講,某一個service層的方法,應該是一個事務,應該是具備原子性的。特別是當一個service方法中須要調用屢次dao層的方法。應該必需要保證,這些屢次調用的dao方法必須是要不所有執行成功。要不所有執行失敗。好比說銀行業務的service方法的轉帳方法,須要經過dao調用對源轉帳戶信息進行更新減小指定金額,而後調用dao對目標帳戶信息進行更新增長指定金額。 web
那麼以下保證在跨dao層調用時,必須事務的acid特性呢? sql
2、解決方法思路: 數據庫
保證事務的ACID特性,默認狀況下對用jdbc對數據庫進行操做事務都是自動的commit狀態的。必須必需要將事務提交改爲手動提交。由程序來控制什麼一塊兒向數據庫提交。通常來講mysql、sql server與oracle默認的隔離級別是repeatable read級別。能夠避免髒讀與不可重複讀。因此須要重點控制的是事務的提交與回滾。 網絡
那麼一個service方法跨多個dao方法調用,如何保證是一個事務呢?首先要保證是同一鏈接Connection纔有可能保證是同一事務。接着須要關注的是如何在多個dao層中獲取是同一Connection。讓整個應用只有個Connection雖然能夠解決同一Connection,可是應用就變成了單線程了。確定不能夠。那麼多線程狀況下,如何保證同一線程內獲取的Connection都是同一對象呢?ThreadLocal類來幫忙,它能夠提供線程局部變量。放入到此ThreadLocal中的對象,在同一線程都保證都到的對象都是一致的。 多線程
解決方法:只須要編寫一個TransactionUtils類,此類有一個private static的ThreadLocal tl對象。而且靜態的getConnction方法體中,先判斷tl對象中是否存在Connection對象,存在直接返回tl中的Connection。不存在則先用數據源獲取個Connection對象而後放入到tl中,再返回Connection對象。此外TransactionUtils類還須要提供openTransaction方法、Commit方法、rollback方法,openTransaction、commit與rollback須要的Connection對象都直接找本類的getConnection方法。 oracle
接着後面service層,先調用TransactionUtils類的openTransaction方法,再對全部的dao層調用方法都try ... Catch...finally下。Catch中調用TransactionUtils類的rollback方法。finally裏中調用 TransactionUtils類的commit方法。 spa
而dao層獲取的Connection都直接找TransactionUtils類的getConnection方法,來確認獲得的都是同一Connection對象。 線程
3、示例代碼以下:
01 |
public class TransactionUtil { |
02 |
private static ThreadLocal<Connection> tl = new ThreadLocal<Connection>(); |
03 |
private static DataSource ds; |
07 |
InputStream in = DbcpUtil.class.getClassLoader() |
08 |
.getResourceAsStream("dbcpconfig.properties"); |
09 |
Properties props = new Properties(); |
11 |
ds = BasicDataSourceFactory.createDataSource(props); |
12 |
} catch (Exception e) { |
13 |
throw new ExceptionInInitializerError(e); |
17 |
public static DataSource getDataSource() { |
21 |
public static Connection getConnection() { |
22 |
Connection conn = tl.get(); // 從ThreadLoacl中獲取,若是沒有再從DataSource中獲取 |
25 |
conn = ds.getConnection(); |
26 |
tl.set(conn); // 存到ThreadLoacl中 |
27 |
} catch (SQLException e) { |
34 |
public static void startTransaction() { |
36 |
Connection conn = tl.get(); |
37 |
if(conn == null) { //若是ThreadLoacl中沒有,就從DataSource中獲取 |
38 |
conn = ds.getConnection(); |
41 |
conn.setAutoCommit(false); |
42 |
} catch(Exception e) { |
47 |
public static void rollback() { <span style="font-family: 'Courier New'; ">//回滾事務,在service層try下dao層,在catch處調用rollbakc方法</span> |
49 |
Connection conn = tl.get(); |
52 |
} catch(Exception e) { |
57 |
public static void commit() { <span style="font-family: 'Courier New'; ">//在finally裏調用提交commint方法</span> |
59 |
Connection conn = tl.get(); |
62 |
} catch(Exception e) { |
67 |
public static void release() { |
69 |
Connection conn = tl.get(); |
74 |
} catch(Exception e) { |