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 }
相关文章
相关标签/搜索