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

理解嵌套事务

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

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

使用简单的POJO实现

新建如下接口:

 importjava.sql.Connection;

 public interface TransactionManager {

     Connection getConnection();
void beginTransaction();
void commit();
void rollback();
}

新建如下事务管理类:

 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)

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

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

public void beginTransaction()

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

public Connection getConnection()

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

public void commit()

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

public void rollback()

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

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

多线程的嵌套事务

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

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

 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,在线程中创建嵌套的事务。

测试

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

 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();
}

结果

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

[转]POJO中使用ThreadLocal实现Java嵌套事务的更多相关文章

  1. Java中的ThreadLocal深入理解

    提到ThreadLocal,有些Android或者Java程序员可能有所陌生,可能会提出种种问题,它是做什么的,是不是和线程有关,怎么使用呢?等等问题,本文将总结一下我对ThreadLocal的理解和 ...

  2. 理解Java中的ThreadLocal

    提到ThreadLocal,有些Android或者Java程序员可能有所陌生,可能会提出种种问题,它是做什么的,是不是和线程有关,怎么使用呢?等等问题,本文将总结一下我对ThreadLocal的理解和 ...

  3. Java中的ThreadLocal详解

    一.ThreadLocal简介 多线程访问同一个共享变量的时候容易出现并发问题,特别是多个线程对一个变量进行写入的时候,为了保证线程安全,一般使用者在访问共享变量的时候需要进行额外的同步措施才能保证线 ...

  4. java POJO中 Integer 和 int 的不同,用int还是用Integer

    https://www.jianshu.com/p/ff535284916f [int和Integer的区别] int是java提供的8种原始类型之一,java为每个原始类型提供了封装类,Intege ...

  5. Java ThreadLocal Example(java中的ThreadLocal例子)

    Java ThreadLocal is used to create thread local variables. We know that all threads of an Object sha ...

  6. Java ThreadLocal (Java代码实战-006)

    ThreadLocal解决什么问题 由于 ThreadLocal 支持范型,如 ThreadLocal< StringBuilder >,为表述方便,后文用 变量 代表 ThreadLoc ...

  7. 在MySql中如何定义像Java中类型的Boolean类型

    在MySql中如何定义像Java中类型的Boolean类型数据..其实,mysql中 是没有直接定义成Boolean这种数据类型.它只能定义成 tinyint(1) ;如果长度是1,tinyint(1 ...

  8. 关于Mybatis中表中字段名和POJO中字段名不同的解决方法

    项目结构: POJO中: package com.domain; /** * @author mzy * 定义orders表对应的实体类 */ public class Order { /** * C ...

  9. Kotlin中变量不同于Java: var 对val(KAD 02)

    原文标题:Variables in Kotlin, differences with Java. var vs val (KAD 02) 作者:Antonio Leiva 时间:Nov 28, 201 ...

随机推荐

  1. hdu 4163 Stock Prices 水

    #include<bits/stdc++.h> using namespace std; #define ll long long #define pi (4*atan(1.0)) #de ...

  2. table布局注意点

    1.同行等高. 2.宽度自动调节(table-layout:fixed;). 3.处理垂直居中又是神器 参考链接: http://www.blueidea.com/tech/web/2008/6257 ...

  3. Spring AOP执行方法

      execution(* springinaction.springidol.Instrument.play(..)) * 代表返回为任意类型 springinaction.springidol.I ...

  4. (四)主控板改IP,升级app,boot,mac

    给主控板升级boot要在boot界面进行,进入boot后,要先查看boot下ip和掩码是否和电脑ip(severip)在一个网段,不在的话要使用setenv命令设置ip地址和掩码.之后再输入upboo ...

  5. Android开发面试经——2.常见Android基础笔试题

     标签: androidAndroid基础Android面试题Android笔试题 2015-03-12 15:04 3361人阅读 评论(3) 收藏 举报  分类: Android开发(29)  版 ...

  6. Android_进化史和平台架构介绍

    一.Android平台发展史  2008年9月,谷歌正式发布了Android 1.0系统,全球第一台Android设备HTC (G1)  2009年4月,谷歌正式推出了Android 1.5      ...

  7. android用shape给linearLayout设置边框,怎样只保留底部或顶部的边框,把其它三个方向的边框去掉呢?

    http://bbs.csdn.net/topics/390485215 这种方法只是两个颜色块相减而已 <?xml version="1.0" encoding=" ...

  8. Unity5中叹为观止的实时GI效果

    http://www.manew.com/thread-43970-1-1.html 今天为大家分享unity与Alex Lovett共同使用unity5制作的Shrine Arch-viz Demo ...

  9. 【OpenCV入门指南】第一篇 安装OpenCV

    http://blog.csdn.net/morewindows/article/details/8225783/ win10下vs2015配置Opencv3.1.0过程详解(转) http://ww ...

  10. EF Core » 关系

    对初学者理解关系很有用,先留下来,有时间边看边翻译. Caution 注意 This documentation is for EF Core. For EF6.x and earlier relea ...