在POJO中使用ThreadLocal的Java嵌套事务
大多数嵌套事务是使用EJB实现的,现在我们尝试在POJO上实现嵌套事务。 在这里,我们使用了ThreadLocal的功能。
了解嵌套事务
事务可以嵌套在另一个内部。 因此,内部事务或外部事务可以回滚或提交,而不会影响其他事务。
创建新事务后,它将进入外部事务。 一旦内部事务以提交或回滚的方式完成,外部事务就可以执行提交或回滚而与内部事务无关。 首先关闭最里面的事务,然后继续进行最外面的事务。
使用简单POJO实施
创建界面如下:
importjava.sql.Connection; publicinterfaceTransactionManager { Connection getConnection(); voidbeginTransaction(); void commit(); void rollback(); }
创建事务管理器类,如下所示:
importjava.sql.Connection; importjava.sql.DriverManager; importjava.sql.SQLException; importjava.util.Stack; publicclassTransactionManagerStackImplimplementsTransactionManager { private Stack<Connection>connections = new Stack<Connection>(); @Override public Connection getConnection() { if (connections.isEmpty()) { this.addConn(); } returnconnections.peek(); } @Override publicvoidbeginTransaction() { 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(); } } privatevoidaddConn() { 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() { returngetConnection("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); returnDriverManager.getConnection(connection, user, password); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } returnnull; } }
在这里,我们创建了一个堆栈:
private Stack<Connection> connections = new Stack<Connection>();
由于事务创建为LIFO(堆栈),因此我们使用了Java API中的Stack来维护每个事务的连接:
public void beginTransaction()
开始事务以开始新的事务并将连接添加到堆栈。 AutoCommit已设置为false:
public Connection getConnection()
获取当前事务的连接。 如果不存在,它将创建并添加到堆栈中:
public void commit()
提交当前事务并关闭连接,该连接也已从堆栈中删除:
public void rollback()
回滚当前事务并关闭连接,该连接也已从堆栈中删除。
上面的TransactionManagerStackImpl类将为单线程创建嵌套事务。
多线程的嵌套事务
对于多线程应用程序,每个线程都有独立的事务和嵌套事务。
我们提出使用ThreadLocal来管理连接栈。
importjava.sql.Connection; publicclassTransactionManagerThreadLocalimplementsTransactionManager { privatestaticfinalThreadLocal<TransactionManager>tranManager = newThreadLocal<TransactionManager>() { protectedTransactionManagerinitialValue() { System.out.println(this.toString() + "--Thread Local Initialize--"); returnnewTransactionManagerStackImpl(); } }; @Override publicvoidbeginTransaction() { tranManager.get().beginTransaction(); } @Override publicvoid commit() { tranManager.get().commit(); } @Override publicvoid rollback() { tranManager.get().rollback(); } @Override public Connection getConnection() { returntranManager.get().getConnection(); } }
在这里,我们初始化TransactionManagerStackImpl以在线程内部创建嵌套事务。
测试中
为了进行上述测试,请提交内部事务并回滚外部事务。
importjava.sql.Connection; publicclassNestedMainimplements Runnable { privateintv = 0; private String name; NestedMain(int v, String name) { this.v = v; this.name = name; } publicstaticvoid main(String[] args) throws Exception{ for (inti = 0; i< 3; i++) { NestedMain main = newNestedMain(i * 10, "Ravi" + i); new Thread(main).start(); } } @Override publicvoid run() { try { TransactionManagerThreadLocal local = newTransactionManagerThreadLocal(); // 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(); }
结果
[email protected] Local Initialize-- [email protected] Local Initialize-- [email protected] Local Initialize-- [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected]
名称 | emp_id |
---|---|
拉维220 | 220 |
拉维00 | 20 |
拉维110 | 210 |
回滚内部事务并提交外部事务时:
[email protected] Local Initialize-- [email protected] Local Initialize-- [email protected] Local Initialize-- [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected]
名称 | emp_id |
---|---|
拉维00 | 10 |
拉维220 | 120 |
拉维110 | 110 |
资源:
翻译自: https://www.javacodegeeks.com/2013/12/java-nested-transaction-using-threadlocal-in-pojo.html