[转]POJO中使用ThreadLocal实现Java嵌套事务
大多嵌套事务都是通过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嵌套事务的更多相关文章
- Java中的ThreadLocal深入理解
提到ThreadLocal,有些Android或者Java程序员可能有所陌生,可能会提出种种问题,它是做什么的,是不是和线程有关,怎么使用呢?等等问题,本文将总结一下我对ThreadLocal的理解和 ...
- 理解Java中的ThreadLocal
提到ThreadLocal,有些Android或者Java程序员可能有所陌生,可能会提出种种问题,它是做什么的,是不是和线程有关,怎么使用呢?等等问题,本文将总结一下我对ThreadLocal的理解和 ...
- Java中的ThreadLocal详解
一.ThreadLocal简介 多线程访问同一个共享变量的时候容易出现并发问题,特别是多个线程对一个变量进行写入的时候,为了保证线程安全,一般使用者在访问共享变量的时候需要进行额外的同步措施才能保证线 ...
- java POJO中 Integer 和 int 的不同,用int还是用Integer
https://www.jianshu.com/p/ff535284916f [int和Integer的区别] int是java提供的8种原始类型之一,java为每个原始类型提供了封装类,Intege ...
- Java ThreadLocal Example(java中的ThreadLocal例子)
Java ThreadLocal is used to create thread local variables. We know that all threads of an Object sha ...
- Java ThreadLocal (Java代码实战-006)
ThreadLocal解决什么问题 由于 ThreadLocal 支持范型,如 ThreadLocal< StringBuilder >,为表述方便,后文用 变量 代表 ThreadLoc ...
- 在MySql中如何定义像Java中类型的Boolean类型
在MySql中如何定义像Java中类型的Boolean类型数据..其实,mysql中 是没有直接定义成Boolean这种数据类型.它只能定义成 tinyint(1) ;如果长度是1,tinyint(1 ...
- 关于Mybatis中表中字段名和POJO中字段名不同的解决方法
项目结构: POJO中: package com.domain; /** * @author mzy * 定义orders表对应的实体类 */ public class Order { /** * C ...
- Kotlin中变量不同于Java: var 对val(KAD 02)
原文标题:Variables in Kotlin, differences with Java. var vs val (KAD 02) 作者:Antonio Leiva 时间:Nov 28, 201 ...
随机推荐
- Android——GridLayout
转载自http://www.cnblogs.com/over140/archive/2011/12/08/2280224.html 欢迎大家转载 前言 本章内容android.widget.GridL ...
- Object-C中的排序和Compare陷阱
来源:http://m.blog.csdn.net/blog/u011883764/38868097 Date : 2015-12-24 一.Compare陷阱 NSString有多个compare相 ...
- SublimeText2 快捷键
前端神器Sublime Text3使用说明:http://www.jianshu.com/p/1f2463261ded SublimeText2 快捷键,与对应功能一览表: 快捷键 功能 ctrl+s ...
- iOS - PassData
前言 页面传值: 复合传值 单例传值 userDefaults 传值 代理传值 Block/闭包传值 1.复合传值 复合 - 正向传值 1.接收方,头文件中创建可存放传递值的属性变量 2.发送方,包含 ...
- 笔记本_thinkpad_e40_FN
1. 开机时按F10进入bios 然后在 bios 中选择 system configuration,看一下其中的 action keys mode .如果此选项后面为 enable 的话,是不需要按 ...
- 转 git使用命令, 特别:git checkout -b a 与 git branch a区别
创建分支: $ git branch mybranch 切换分支: $ git checkout mybranch 创建并切换分支: $ git checkout -b mybranch 更新mast ...
- 正则的小效果:-------> 过滤敏感词
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
- GO数据库
Golang 数据库操作 Golang 数据库 MySQL Golang支持DB操作位于database包下,支持基本CRUD操作.事务和Prepared Statement,本文以MySQL为例. ...
- pdmreader支持读取xml格式的pdm文件,无法读取二进制格式的pdm文件。
您的Pdm数据字典文件可能不被PDMReader读取,可能是因为pdm文件版本的问题.但 您可以通过PowerDesigner12(下载PowerDesigner12)进行转换 后进行读取. 您要做的 ...
- Freemarker 入门示例(zhuan)
http://cuisuqiang.iteye.com/blog/2031768 ************************************ 初步学习freemarker ,先做一个简单 ...