spring中的事务管理

Spring对事务的解决办法其实分为2种:编程式实现事务,AOP配置声明式解决方案。 

声明式事物

1)Spring的声明式事务管理在底层是建立在AOP的基础之上的。其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。声明式事务最大的优点就是不需要通过编程的方式管理事务,这样就不需要在业务逻辑代码中掺杂事务管理的代码,只需在配置文件中做相关的事务规则声明(或通过等价的基于标注的方式),便可以将事务规则应用到业务逻辑中。因为事务管理本身就是一个典型的横切逻辑,正是AOP的用武之地。Spring开发团队也意识到了这一点,为声明式事务提供了简单而强大的支持。Spring强大的声明式事务管理功能,这主要得益于Spring依赖注入容器和Spring AOP的支持。依赖注入容器为声明式事务管理提供了基础设施,使得Bean对于Spring框架而言是可管理的;而Spring AOP则是声明式事务管理的直接实现者。和编程式事务相比,声明式事务唯一不足地方是,后者的最细粒度只能作用到方法级别,无法做到像编程式事务那样可以作用到代码块级别。但是即便有这样的需求,也存在很多变通的方法,比如,可以将需要进行事务管理的代码块独立为方法等等。

2)5种配置方式

Spring配置文件中关于事务配置总是由三个组成部分,分别是DataSource、TransactionManager和代理机制这三部分,无论哪种配置方式,一般变化的只是代理机制这部分。

DataSource、TransactionManager这两部分只是会根据数据访问方式有所变化,比如使用Hibernate进行数据访问时,DataSource实际为SessionFactory,TransactionManager的实现为HibernateTransactionManager。

关系图如下:

注意:sessionFactorty和transactionManager是下面5中配置方式的基本配置,

第一种方式:每个Bean都有一个代理

第二种方式:所有Bean共享一个代理基类

第三种方式:使用拦截器

第四种方式:使用tx标签配置的拦截器    

第五种方式:全注解

编程式事务

Spring的编程式事务即在代码中使用编程的方式进行事务处理,可以做到比声明式事务更细粒度。有两种方式一是使用TransactionManager,另外就是TransactionTemplate。

1)TransactionManager使用方式

public class UserDaoImpl extends HibernateDaoSupport implements UserDao {  

private HibernateTransactionManager transactionManager;  

private DefaultTransactionDefinition def;  

public HibernateTransactionManager getTransactionManager() {  

return transactionManager;  

    }  

public void setTransactionManager(HibernateTransactionManager transactionManager) {  

this.transactionManager = transactionManager;  

    }  

public void createTransactionDefinition() {  

def =new DefaultTransactionDefinition();  

        def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);  

        def.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);  

    }  


public void saveOrUpdate(User user) {  

        TransactionStatus status = transactionManager.getTransaction(def);  

try {  

this.getHibernateTemplate().saveOrUpdate(user);  

}catch (DataAccessException ex) {  

            transactionManager.rollback(status);  

throw ex;  

        }  

        transactionManager.commit(status);  

    }  

}  

2)TransactionTemplate方式

ResultDto ret = null;  

ret = (ResultDto)this.transactionTemplate.execute(new TransactionCallback() {  

@Override  

public Object doInTransaction(TransactionStatus status) {  

ResultDto ret =null;  

try {  

            drillTaskDao.deleteByKey(taskid);  

}catch (Exception e) {  

logger.error("delDrillTask:" + e.getMessage(), e);  

ret = ResultBuilder.buildResult(ResultBuilder.FAIL_CODE,null, ErrorCode.COM_DBDELETEERROR);  

return ret;  

        }  

finally {  

            status.setRollbackOnly();  

        }  


ret = cleartaskrelativedata(taskid, appid,true);  

return ret;  

    }  

});  

return ret;  

由于Spring内置AOP默认使用动态代理模式实现,我们就先来分析一下动态代理模式的实现方 法。动态代理模式的核心就在于代码中不出现与具体应用层相关联的接口或者类引用,如上所说,这个代理类适用于任何接口的实现。

public class TxHandler implements InvocationHandler {

private Object originalObject;

public Object bind(Object obj) {

 this.originalObject = obj;

 return Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),this);

    }

public Object invoke(Object proxy, Method method, Object[] args)

throws Throwable {

 Object result = null;

 if (!method.getName().startsWith("save")) {

  UserTransaction tx = null;

  try {

   tx = (UserTransaction) (new InitialContext().lookup("java/tx"));

   result = method.invoke(originalObject, args);

   tx.commit();

  } catch (Exception ex) {

   if (null != tx) {

    try {

     tx.rollback();

    } catch (Exception e) {

   }

  }

 }

    } else {

 result = method.invoke(originalObject, args);

    }

return result;

    }

}

下面我们来分析一下上述代码的关键所在。

首先来看一下这段代码:

return Proxy.newProxyInstance(

 obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),this);


java.lang.reflect.Proxy.newProxyInstance方法根据传入的接口类型 (obj.getClass.getInterfaces())动态构造一个代理类实例返回,这也说明了为什么动态代理实现要求其所代理的对象一定要实现 一个接口。这个代理类实例在内存中是动态构造的,它实现了传入的接口列表中所包含的所有接口。

再来分析以下代码:

public Object invoke(Object proxy, Method method, Object[] args)throws Throwable {

 ……

 result = method.invoke(originalObject, args);

 ……

 return result;

}

InvocationHandler.invoke方法将在被代理类的方法被调用之前触发。通过这个方法,我们可以在被代理类方法调用的前后进行一些处 理,如代码中所示,InvocationHandler.invoke方法的参数中传递了当前被调用的方法(Method),以及被调用方法的参数。同 时,可以通过method.invoke方法调用被代理类的原始方法实现。这样就可以在被代理类的方法调用前后写入任何想要进行的操作。

   Spring的事务管理机制实现的原理,就是通过这样一个动态代理对所有需要事务管理的Bean进行加载,并根据配置在invoke方法中对当前调用的 方法名进行判定,并在method.invoke方法前后为其加上合适的事务管理代码,这样就实现了Spring式的事务管理。Spring中的AOP实 现更为复杂和灵活,不过基本原理是一致的。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,919评论 6 502
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,567评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,316评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,294评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,318评论 6 390
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,245评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,120评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,964评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,376评论 1 313
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,592评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,764评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,460评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,070评论 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,697评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,846评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,819评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,665评论 2 354

推荐阅读更多精彩内容