大多数嵌套事务是使用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();
}
结果
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---
名称 | emp_id |
---|---|
拉维220 | 220 |
拉维00 | 20 |
拉维110 | 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---
名称 | emp_id |
---|---|
拉维00 | 10 |
拉维220 | 120 |
拉维110 | 110 |
资源:
翻译自: https://www.javacodegeeks.com/2013/12/java-nested-transaction-using-threadlocal-in-pojo.html