POJO中使用ThreadLocal实现Java嵌套事务

大多嵌套事务都是通过EJB实现的,现在我们尝试实现对POJO的嵌套事务。这里我们使用了ThreadLocal的功能。

理解嵌套事务

事务是可以嵌套的。所以内层事务或外层事务可以在不影响其他事务的条件下进行回滚或提交。

新建的事务嵌套在外层事务中。如果内层事务完成(不论是回滚或是提交),外层的事务就可以进行回滚或提交,这样的操作并不会影响内层事务。首先关闭最内层的事务,并逐步移动到外层事务。

使用简单的POJO实现

新建如下接口:

1
2
3
4
5
6
7
8
9
importjava.sql.Connection;
 
public interface TransactionManager {
 
     Connection getConnection();
     void beginTransaction();
     void commit();
     void rollback();
}

新建如下事务管理类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
importjava.sql.Connection;
importjava.sql.DriverManager;
importjava.sql.SQLException;
importjava.util.Stack;
 
public class TransactionManagerStackImpl implements TransactionManager {
     
     private Stack<Connection>connections = new Stack<Connection>();
 
     @Override
     public Connection getConnection() {
 
         if (connections.isEmpty()) {
             this .addConn();
         }
 
         return connections.peek();
     }
 
     @Override
     public void beginTransaction() {
         this .addConn();
     }
 
     @Override
     public void commit() {
         try {
             if (connections.peek() != null && !connections.peek().isClosed()) {
                 System.out.println(connections.peek().toString() + "--Commit---" );
                 connections.peek().commit();
                 connections.pop().close();
             }
 
         } catch (SQLException e) {
             e.printStackTrace();
         }
 
     }
 
     @Override
     public void rollback() {
         try {
 
             if (connections.peek() != null && !connections.peek().isClosed()) {
                 System.out.println(connections.peek().toString() + "--Rollback---" );
                 connections.peek().rollback();
                 connections.pop().close();
             }
         } catch (SQLException e) {
             e.printStackTrace();
         }
 
     }
 
     private void addConn() {
         try {
             Connection con = this .getMysqlConnection();
             con.setAutoCommit( false );
             connections.push(con);
             System.out.println(con.toString() + "--Conection---" );
         } catch (SQLException e) {
             e.printStackTrace();
         }
         
     }
 
     private Connection getMysqlConnection() {
         return getConnection( "com.mysql.jdbc.Driver" , "jdbc:mysql://localhost:3306/testdb" , "test" , "test12345" );
     }
 
     private Connection getConnection(String driver, String connection,
             String user, String password) {
 
         try {
             Class.forName(driver);
             return DriverManager.getConnection(connection, user, password);
         } catch (ClassNotFoundException e) {
             e.printStackTrace();
         } catch (SQLException e) {
             e.printStackTrace();
         }
 
         returnnull;
 
     }
}

到这里,我们创建了一个栈(Stack)

1
private Stack<Connection> connections = new Stack<Connection>();

事务遵循栈“先进后出”的原则,通过栈存储事务的连接:

1
public void beginTransaction()

beginTransaction()用于开启一个新的事务,并将连接加入到栈中。自动提交设置为否:

1
public Connection getConnection()

getConnection()获得当前事务的连接。如果连接为空,则创建新的连接并将其加入到栈:

1
public void commit()

提交当前的事务,之后关闭连接,并将其从栈中移除:

1
public void rollback()

回滚当前的事务,之后关闭连接,并将其从栈中移除。

上面的TransactionManagerStackImpl类为单线程创建了嵌套事务。

多线程的嵌套事务

在多线程的应用中,每个线程都有其独立的事务和嵌套事务。

我们使用ThreadLocal管理栈的连接。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
importjava.sql.Connection;
 
public class TransactionManagerThreadLocalimplementsTransactionManager {
     
     private static final ThreadLocal<TransactionManager>tranManager = newThreadLocal<TransactionManager>() {
         
     protected TransactionManager initialValue() {
         System.out.println( this .toString() + "--Thread Local Initialize--" );
     return new TransactionManagerStackImpl();
         }
       };
 
     @Override
     public void beginTransaction() {
         tranManager.get().beginTransaction();
     }
 
     @Override
     public void commit() {
         tranManager.get().commit();
     }
 
     @Override
     public void rollback() {
         tranManager.get().rollback();
     }
 
     @Override
     public Connection getConnection() {
         returntranManager.get().getConnection();
     }
}

这里初始化TransactionManagerStackImpl,在线程中创建嵌套的事务。

测试

测试上面的方法,提交内层事务,回滚外层事务。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
importjava.sql.Connection;
 
public class NestedMain implements Runnable {
     
     private int v = 0 ;
     private String name;
     
     NestedMain( int v, String name) {
         this .v = v;
         this .name = name;
     }
 
     public static void main(String[] args) throws Exception{
         
         for (inti = 0 ; i< 3 ; i++) {
             NestedMain main = newNestedMain(i * 10 , "Ravi" + i);
             new Thread(main).start();
         }
     }
 
     @Override
     public void run() {
         
         try {
             TransactionManagerThreadLocal local = new TransactionManagerThreadLocal();
             
             // Transaction 1 ( outer )
             local.beginTransaction();
             Connection con = local.getConnection();
             String sql = "INSERT INTO test_tran (emp_id, name) VALUES ('1" +v+ "', '" + name+v+ "')" ;
             this .insert(con, sql);
     
                 // Transaction 2 ( Inner )
                 local.beginTransaction();
                 con = local.getConnection();
                 sql = "INSERT INTO test_tran (emp_id, name) VALUES ('2" +v+ "', '" + name+v+ "')" ;
                 this .insert(con, sql);
                 local.commit(); // Committing 2
 
             local.rollback(); // Rollback 1 Outer
 
         } catch (Exception e) {
             e.printStackTrace();
         }

结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
com.ttit.TransactionManagerThreadLocal$1@1270b73--Thread Local Initialize--
com.ttit.TransactionManagerThreadLocal$1@1270b73--Thread Local Initialize--
com.ttit.TransactionManagerThreadLocal$1@1270b73--Thread Local Initialize--
com.mysql.jdbc.JDBC4Connection@10dd1f7--Conection---
com.mysql.jdbc.JDBC4Connection@1813fac--Conection---
com.mysql.jdbc.JDBC4Connection@136228--Conection---
com.mysql.jdbc.JDBC4Connection@1855af5--Conection---
com.mysql.jdbc.JDBC4Connection@e39a3e--Conection---
com.mysql.jdbc.JDBC4Connection@1855af5--Commit---
com.mysql.jdbc.JDBC4Connection@e39a3e--Commit---
com.mysql.jdbc.JDBC4Connection@9fbe93--Conection---
com.mysql.jdbc.JDBC4Connection@9fbe93--Commit---
com.mysql.jdbc.JDBC4Connection@10dd1f7--Rollback---
com.mysql.jdbc.JDBC4Connection@1813fac--Rollback---
com.mysql.jdbc.JDBC4Connection@136228--Rollback---
 
|  name       | emp_id          
| ------------- |:-------------:
| Ravi220        | 220
| Ravi00      | 20     
|Ravi110 | 210     

内层事务回滚,外层事务提交的情况:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
com.ttit.TransactionManagerThreadLocal$ 1 @1270b73 --Thread Local Initialize--
com.ttit.TransactionManagerThreadLocal$ 1 @1270b73 --Thread Local Initialize--
com.ttit.TransactionManagerThreadLocal$ 1 @1270b73 --Thread Local Initialize--
com.mysql.jdbc.JDBC4Connection @9f2a0b --Conection---
com.mysql.jdbc.JDBC4Connection @136228 --Conection---
com.mysql.jdbc.JDBC4Connection @1c672d0 --Conection---
com.mysql.jdbc.JDBC4Connection @9fbe93 --Conection---
com.mysql.jdbc.JDBC4Connection @1858610 --Conection---
com.mysql.jdbc.JDBC4Connection @9fbe93 --Rollback---
com.mysql.jdbc.JDBC4Connection @1858610 --Rollback---
com.mysql.jdbc.JDBC4Connection @1a5ab41 --Conection---
com.mysql.jdbc.JDBC4Connection @1a5ab41 --Rollback---
com.mysql.jdbc.JDBC4Connection @9f2a0b --Commit---
com.mysql.jdbc.JDBC4Connection @136228 --Commit---
com.mysql.jdbc.JDBC4Connection @1c672d0 --Commit---
...
|  name       | emp_id          
| ------------- |:-------------:
| Ravi00         | 10
| Ravi220      | 120     
|Ravi110 | 110


来源:http://www.importnew.com/11049.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值