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

 

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代码 复制代码  收藏代码
  1. ServiceA {   
  2.        
  3.     /**  
  4.      * 事务属性配置为 PROPAGATION_REQUIRED  
  5.      */  
  6.     void methodA() {   
  7.         try {   
  8.             ServiceB.methodB();   
  9.         } catch (SomeException) {   
  10.             // 执行其他业务, 如 ServiceC.methodC();   或者rollback(),或者commit()
  11.         }   
  12.     }   
  13.   
  14. }   

以下是我写的例子:

@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)



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值