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

来源:互联网 发布:python获取昨天的日期 编辑:程序博客网 时间:2024/05/08 11:09

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

理解嵌套事务

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

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

使用简单的POJO实现

新建如下接口:

1
2
3
4
5
6
7
8
9
importjava.sql.Connection;
 
public interface TransactionManager {
 
    Connection getConnection();
    voidbeginTransaction();
    voidcommit();
    voidrollback();
}

新建如下事务管理类:

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 implementsTransactionManager {
     
    privateStack<Connection>connections = newStack<Connection>();
 
    @Override
    publicConnection getConnection() {
 
        if(connections.isEmpty()) {
            this.addConn();
        }
 
        returnconnections.peek();
    }
 
    @Override
    publicvoid beginTransaction() {
        this.addConn();
    }
 
    @Override
    publicvoid 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
    publicvoid 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();
        }
 
    }
 
    privatevoid addConn() {
        try{
            Connection con =this.getMysqlConnection();
            con.setAutoCommit(false);
            connections.push(con);
            System.out.println(con.toString() +"--Conection---");
        }catch (SQLException e) {
            e.printStackTrace();
        }
         
    }
 
    privateConnection getMysqlConnection() {
        returngetConnection("com.mysql.jdbc.Driver","jdbc:mysql://localhost:3306/testdb","test", "test12345");
    }
 
    privateConnection getConnection(String driver, String connection,
            String user, String password) {
 
        try{
            Class.forName(driver);
            returnDriverManager.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 {
     
    privatestatic final ThreadLocal<TransactionManager>tranManager = newThreadLocal<TransactionManager>() {
         
    protectedTransactionManager initialValue() {
        System.out.println(this.toString() +"--Thread Local Initialize--");
    returnnew TransactionManagerStackImpl();
        }
      };
 
    @Override
    publicvoid beginTransaction() {
        tranManager.get().beginTransaction();
    }
 
    @Override
    publicvoid commit() {
        tranManager.get().commit();
    }
 
    @Override
    publicvoid rollback() {
        tranManager.get().rollback();
    }
 
    @Override
    publicConnection 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 implementsRunnable {
     
    privateint v = 0;
    privateString name;
     
    NestedMain(intv, String name) {
        this.v = v;
        this.name = name;
    }
 
    publicstatic void main(String[] args) throws Exception{
         
        for(inti = 0; i<3; i++) {
            NestedMain main = newNestedMain(i *10, "Ravi"+ i);
            newThread(main).start();
        }
    }
 
    @Override
    publicvoid 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

0 0
原创粉丝点击