zoukankan      html  css  js  c++  java
  • [转]POJO中使用ThreadLocal实现Java嵌套事务

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

    理解嵌套事务

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

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

    使用简单的POJO实现

    新建如下接口:

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

    新建如下事务管理类:

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

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

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

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

    public void beginTransaction()

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

    public Connection getConnection()

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

    public void commit()

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

    public void rollback()

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

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

    多线程的嵌套事务

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

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

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

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

    测试

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

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

    结果

    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      

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

    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

    原文链接: javacodegeeks 翻译: ImportNew.com 人晓
    译文链接: http://www.importnew.com/11049.html

  • 相关阅读:
    认识“委托”
    程序员的修炼之道:从小工到专家(一)
    知识的使用 与 知识的内化
    VB.Net中 Module 的前世今生
    memcached
    C#知识
    Android之垂直显示TextView
    Android开发之各个语言
    Android之hint提示字体大小修改,显示完全
    Android 之计算控件颜色透明度
  • 原文地址:https://www.cnblogs.com/GYoungBean/p/3779257.html
Copyright © 2011-2022 走看看