JDBC 事務控制

摘抄至網絡,記下來。 java

1、簡介: mysql

前面一遍提到了jdbc事務相關的概念。從中瞭解到事務應具備ACID特性。因此對於javaweb開發來講,某一個service層的方法,應該是一個事務,應該是具備原子性的。特別是當一個service方法中須要調用屢次dao層的方法。應該必需要保證,這些屢次調用的dao方法必須是要不所有執行成功。要不所有執行失敗。好比說銀行業務的service方法的轉帳方法,須要經過dao調用對源轉帳戶信息進行更新減小指定金額,而後調用dao對目標帳戶信息進行更新增長指定金額。 web

那麼以下保證在跨dao層調用時,必須事務的acid特性呢? sql

2、解決方法思路: 數據庫

保證事務的ACID特性,默認狀況下對用jdbc對數據庫進行操做事務都是自動的commit狀態的。必須必需要將事務提交改爲手動提交。由程序來控制什麼一塊兒向數據庫提交。通常來講mysqlsql serveroracle默認的隔離級別是repeatable read級別。能夠避免髒讀與不可重複讀。因此須要重點控制的是事務的提交與回滾。 網絡

那麼一個service方法跨多個dao方法調用,如何保證是一個事務呢?首先要保證是同一鏈接Connection纔有可能保證是同一事務。接着須要關注的是如何在多個dao層中獲取是同一Connection。讓整個應用只有個Connection雖然能夠解決同一Connection,可是應用就變成了單線程了。確定不能夠。那麼多線程狀況下,如何保證同一線程內獲取的Connection都是同一對象呢?ThreadLocal類來幫忙,它能夠提供線程局部變量。放入到此ThreadLocal中的對象,在同一線程都保證都到的對象都是一致的。 多線程

解決方法:只須要編寫一個TransactionUtils類,此類有一個private staticThreadLocal tl對象。而且靜態的getConnction方法體中,先判斷tl對象中是否存在Connection對象,存在直接返回tl中的Connection。不存在則先用數據源獲取個Connection對象而後放入到tl中,再返回Connection對象。此外TransactionUtils類還須要提供openTransaction方法、Commit方法、rollback方法,openTransactioncommitrollback須要的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;
04  
05     static {
06         try {
07             InputStream in = DbcpUtil.class.getClassLoader()
08                     .getResourceAsStream("dbcpconfig.properties");
09             Properties props = new Properties();
10             props.load(in);
11             ds = BasicDataSourceFactory.createDataSource(props);
12         } catch (Exception e) {
13             throw new ExceptionInInitializerError(e);
14         }
15     }
16  
17     public static DataSource getDataSource() {
18         return ds;
19     }
20  
21     public static Connection getConnection() {
22         Connection conn = tl.get(); // 從ThreadLoacl中獲取,若是沒有再從DataSource中獲取
23         if (conn == null) {
24             try {
25                 conn = ds.getConnection();
26                 tl.set(conn); // 存到ThreadLoacl中
27             } catch (SQLException e) {
28                 e.printStackTrace();
29             }
30         }
31         return conn;
32     }
33  
34     public static void startTransaction() {
35         try {
36             Connection conn = tl.get();
37             if(conn == null) {      //若是ThreadLoacl中沒有,就從DataSource中獲取
38                 conn = ds.getConnection();
39                 tl.set(conn);       //存入
40             }
41             conn.setAutoCommit(false);
42         } catch(Exception e) {
43             e.printStackTrace();
44         }
45     }
46  
47     public static void rollback() { <span style="font-family: 'Courier New'; ">//回滾事務,在service層try下dao層,在catch處調用rollbakc方法</span>
48         try {
49             Connection conn = tl.get();
50             if(conn != null)
51                 conn.rollback();
52         } catch(Exception e) {
53             e.printStackTrace();
54         }
55     }
56  
57     public static void commit() {        <span style="font-family: 'Courier New'; ">//在finally裏調用提交commint方法</span>
58         try {
59             Connection conn = tl.get();
60             if(conn != null)
61                 conn.commit();
62         } catch(Exception e) {
63             e.printStackTrace();
64         }
65     }
66      
67     public static void release() {
68         try {
69             Connection conn = tl.get();
70             if(conn != null) {
71                 conn.close();
72                 tl.remove();
73             }
74         } catch(Exception e) {
75             e.printStackTrace();
76         }
77     }
78      
79 }
相關文章
相關標籤/搜索