您的位置:首页 > 编程语言 > Java开发

关于jdbc内嵌事务(结合spring的传播属性)

2012-03-15 17:20 405 查看
jdbc内嵌事务略(这里指savepoint相关)不同于pl/sql里写procture的内嵌事务概念(pl/sql里写procture的内嵌事务是完全独立的事务,相当于spring里的PROPAGATION_REQUIRES_NEW),

大家都知道spring的事务的传播属性:

PROPAGATION_REQUIRED -- 支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。

PROPAGATION_SUPPORTS -- 支持当前事务,如果当前没有事务,就以非事务方式执行。

PROPAGATION_MANDATORY -- 支持当前事务,如果当前没有事务,就抛出异常。

PROPAGATION_REQUIRES_NEW -- 新建事务,如果当前存在事务,把当前事务挂起。

PROPAGATION_NOT_SUPPORTED -- 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。

PROPAGATION_NEVER -- 以非事务方式执行,如果当前存在事务,则抛出异常。

PROPAGATION_NESTED -- 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则进行与PROPAGATION_REQUIRED类似的操作。

前六个策略类似于EJB CMT,

第七个(PROPAGATION_NESTED)是Spring所提供的一个特殊变量。

它要求事务管理器或者使用JDBC 3.0 Savepoint API提供嵌套事务行为(如Spring的DataSourceTransactionManager)


现在来讨论大家关心的savepoint相关的PROPAGATION_NESTED,

这涉及到方法的嵌套调用:

假如有两个业务接口 ServiceA 和 ServiceB, 其中 ServiceA 中有一个方法实现如下

/**

* 事务属性配置为 PROPAGATION_REQUIRED

*/

void methodA() {

// 调用 ServiceB 的方法

ServiceB.methodB();

}

那么如果 ServiceB 的 methodB 如果配置了事务, 配置为 PROPAGATION_NESTED 是什么意思呢?

ServiceB#methodB 如果 rollback, 那么内部事务(即 ServiceB#methodB) 将回滚到它执行前的 SavePoint(注意, 这是本文中第一次提到它, 潜套事务中最核心的概念), 而外部事务(即 ServiceA#methodA) 可以有以下处理方式:

. 改写 ServiceA 如下

Java代码







ServiceA {

/**
* 事务属性配置为 PROPAGATION_REQUIRED
*/
void methodA() {
try {
ServiceB.methodB();
} catch (SomeException) {
// 执行其他业务, 如 ServiceC.methodC(); 或者rollback(),或者commit()
}
}

}

以下是我写的例子:

@Transactional(readOnly = false, propagation = Propagation.REQUIRED)

public Session saveDepartment(Department user, User u, UserDao userDao) {

this.getJdbcTemplate().execute("update departments set name='"+user.getName()+"' where id="+user.getId()+"");

try {

userDao.saveUser(u);

} catch (Exception e) {

try {

conn.rollback(); 回滚处理,也可以提交

} catch (SQLException e1) {

// TODO Auto-generated catch block

e1.printStackTrace();

}

}

return null;

}

@Transactional(readOnly = false, propagation = Propagation.NESTED)

public void saveUser(User user) {

ConnectionHolder conHolder = (ConnectionHolder)

this.getJdbcTemplate().execute("update users set first_name='"+user.getName().getFirstName()+"' where id="+user.getId()+" ");

throw new RuntimeException("jimmy throw"); //人为抛出异常

}

调试信息如下:

Connection.getMetaData().supportsSavepoints() true

departments conn hashcode=8287698 departments conn is closed:false

saveUser conn hashcode=8287698 saveUser conn is closed:false

saveUser conn getAutoCommit=false

DataSourceTransactionManager:815 - Rolling back transaction to savepoint

可见:

两个方法用的一个连接,这还可以从oracle的v$session表验证,

并且B方法抛出异常后,事务回滚到保存点。

看连接v$session(这就是数据池里开的连接)

select ss.machine, Ss.Logon_Time from v$session ss; --where sid=143;

第三条就是我的机器的连接,整个测试时只有一条





看事务v$transaction






看被锁的表对象v$lock_object:

select All_Objects.Object_Name, rpad(oracle_username,10) o_name,session_id sid,

decode(locked_mode,0,'None',1,'Null',2,'Row share',

3,'Row Exclusive',4,'Share',5,'Share Row Exclusive',6,'Exclusive') lock_type,

object_name ,xidusn,xidslot,xidsqn

from v$locked_object,all_objects

where v$locked_object.object_id=all_objects.object_id;




看用了什么锁v$lock:

select sid,type,trunc(id1/65536),mod(id1,65536),id2,

decode(lmode,0,'None',1,'Null',2,'Row share',

3,'Row Exclusive',4,'Share',5,'Share Row Exclusive',6,'Exclusive')

lock_type,request,ctime,block

from v$lock where TYPE IN('TX','TM');



结论:

当两个方法嵌套调用时候:,被调用的用NEST时,

用的是一个连接(v$session),一个事务(v$transaction)用三个lock(v$lock)锁两个表对象(v$lock_object)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: