`
hugang357
  • 浏览: 188496 次
  • 性别: Icon_minigender_2
  • 来自: 深圳
社区版块
存档分类
最新评论

spring 的 AOP 事务

    博客分类:
  • ssh
阅读更多
          今天对 spring 的 AOP 事务有了一个新的认识,所以赶紧把今天的学习记下来,希望在今后的学习中能够起到一些作用,也能对今天的认识做一次总结。


1.同事的 spring 分享

先看一段代码:
    Connection conn = Conn.getConnection();
    conn.setAutoCommit(false);
    ……..
    ……...
    conn.rollback();
    conn.commit();

    数据库的事务是针对 Connection 的。

    接着再看一段代码:( spring 中事务的一段学习代码,这段代码是把 spring 和 hibernate 结合在一起的,增加了理解上的难度,因为我的出发点一开始不要 hibernate ,就光用 jdbc 来进行数据库事务,但是没有其他好的代码,就这样吧)

    public Long addLineItem(Long orderId, LineItem lineItem){

       log("OrderListDAOHibernate.addLineItem : Start...");

       OrderList orderList = (OrderList) getHibernateTemplate().load(OrderList.class, orderId);

       lineItem.setOrderList(orderList);

       getHibernateTemplate().saveOrUpdate(lineItem);

       getHibernateTemplate().saveOrUpdate(orderList);

       log("OrderListDAOHibernate.addLineItem : Ending...");

       return lineItem.getId();

    }

    在这个代码的配置文件中,把 addLineItem 做为一个切入点,进行事务,也就是说,在 addLineItem 的外面,再包上一层事务的外壳。

    但是这个时候,问题出来了,事务是针对 Connection 的,而上面的两个连续的 HibernateTemplate 执行的 saveOrUpdate 中的 Connection 必须是一致才能用事务, spring 怎么做到这一点的呢?(这个问题也就是在找 spring 的事务例子前,我想的 spring 中用 jdbc 来进行事务,怎么样让 Connection 保持一致呢?但是没有 jdbc 的例子,只有整合 hibernate 或者 ibatis 的例子,但是,我想,原理是一样的吧。)



    解决问题的思路: HibernateTemplate 中的 Connection 必定一致。那么就从 HibernateTemplate 入手。

    看 spring 的源代码,既然是 Hibernate ,那么,就没有 Connection 给你看,只有 Session ,由 Session 来管理 Connection ,那么用事务来控制的话,这个 Session 必定在所有该事务中是一致的。于是在 HibernateTemplate 中找到:


protected Session getSession() {

       if (isAlwaysUseNewSession()) {

return SessionFactoryUtils.getNewSession(getSessionFactory(), getEntityInterceptor());

       }

       else if (!isAllowCreate()) {

return SessionFactoryUtils.getSession(getSessionFactory(), false);

       }

       else {

return SessionFactoryUtils.getSession(

                  getSessionFactory(), getEntityInterceptor(), getJdbcExceptionTranslator());

       }

    }



看来在 SessionFactoryUtils 里面,接着在 SessionFactoryUtils.getSession 中找:



这个方法太长了,太复杂了,从简,发现了非常关键的一点:



SessionHolder sessionHolder = (SessionHolder) TransactionSynchronizationManager.getResource(sessionFactory);



假如 sessionHolder 不等于空,说明,在事务中有这样一个还没有 commit 的 session ,那么就返回这个 session ,假如等于空,新建一个 session ,并且在事务里加入这个 session 。这段代码的意思大概是这样,太繁杂了,只能猜,也肯定是如此。



再看 getHibernateTemplate() 方法来自继承 HibernateDaoSupport ,看了电子书《 spring-reference 》的第九章“ Dao 支持”, Dao 的支持类可以有好多,如: JdbcDaoSupport , HibernateDaoSupport , JdoDaoSupport 等等。



既然前面一开始就是从 jdbc 的 spring 事务控制引起的,那么看到了同样的 HibernateDaoSupport---JdbcDaoSupport ,那么 JdbcDaoSupport 也应该有 getJdbcTemplate() 这个方法,并且返回 JdbcTemplate 这个类。



果然如此。



于是剖析 JdbcTemplate 是不是和 HibernateTemplate 一样。果然一样。



注意到:

Connection con = DataSourceUtils.getConnection(getDataSource());



Connection 是从 DataSourceUtils.getConnection() 来的,继续跟踪 DataSourceUtils.getConnection() 。



找到:

ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);



和 Hibernate 中的一模一样,因为没有了 session 的封装,条理在 jdbc 中更加清晰了。



至此, spring 的事务控制 已经全部搞定。

2.Spring 事务管理的配置

看了上面同事学习 spring 的笔记后自己也觉得有新的理解,从什么地方说起呢?就从 spring 的事务配置说起吧。那么我们看看 contextConfig.xml 吧。

<bean id="sessionFactory" class="org.springframework.orm.hibernate.LocalSessionFactoryBean">

       <property name="dataSource">

           <ref bean="dataSource" />

       </property>

       <property name="mappingResources">

           <list>

              <value>mf/org/user/User.hbm.xml</value>

           </list>

       </property>

</bean>

<bean id="transactionManager" class="org.springframework.orm.hibernate.HibernateTransactionManager">

       <property name="sessionFactory">

           <ref local="sessionFactory" />

       </property>

    </bean>

<bean id="txProxyTemplate" abstract="true" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">

       <property name="transactionManager">

           <ref bean="transactionManager" />

       </property>

       <property name="transactionAttributes">

           <props>

<prop key="save*">PROPAGATION_REQUIRED,-Exception</prop>

<prop key="remove*">PROPAGATION_REQUIRED,-Exception </prop>

<prop key="update*">PROPAGATION_REQUIRED,-Exception </prop>

<prop key="incress*">PROPAGATION_REQUIRED,-Exception </prop>

<prop key="*">PROPAGATION_REQUIRED,readOnly</prop>

           </props>

       </property>

    </bean>

<bean id="userManager" parent="txProxyTemplate">

       <property name="target" ref="userManagerTarget" />

</bean>

<bean id="userManagerTarget"

class=" mf.org.hb.user.service.impl.UserManagerImpl">

       <property name="userDAO" ref="userDAO" />

</bean>

<bean id="userDAO" class="mf.org.hb.user.dao.hibernate.UserDAOHibernate">

       <property name="sessionFactory" ref="sessionFactory" />

</bean>

    以上就是一个完整的 spring 配置,是不是很熟悉呢,这里是用的 Appfuse 的框架,呵呵。有那么点味道吧。

    首先我们看看

<bean id="transactionManager" class="org.springframework.orm.hibernate.HibernateTransactionManager">

       <property name="sessionFactory">

           <ref local="sessionFactory" />

       </property>

</bean>

    这一个 bean 让 spring 为我们注入了什么呢?事务,对!我们把 hibernate 的事务注入到了 spring 的 IOC 容器之中了。然后我们再看看:

    <bean id="txProxyTemplate" abstract="true" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">

       <property name="transactionManager">

           <ref bean="transactionManager" />

       </property>

       <property name="transactionAttributes">

           <props>

<prop key="save*">PROPAGATION_REQUIRED,-Exception</prop>

<prop key="remove*">PROPAGATION_REQUIRED,-Exception </prop>

<prop key="update*">PROPAGATION_REQUIRED,-Exception </prop>

<prop key="incress*">PROPAGATION_REQUIRED,-Exception </prop>

<prop key="*">PROPAGATION_REQUIRED,readOnly</prop>

           </props>

       </property>

</bean>

    这个 bean 又是让 spring 为我们注入了了什么呢?事务代理,对了!我们把事务的代理交给一个 txProxyTemplate 的去做了,这样的好处我待会再说,现在我们看看下面的一些配置信息。

<prop key="save*">PROPAGATION_REQUIRED,-Exception</prop>

<prop key="remove*">PROPAGATION_REQUIRED,-Exception </prop>

<prop key="update*">PROPAGATION_REQUIRED,-Exception </prop>

<prop key="incress*">PROPAGATION_REQUIRED,-Exception </prop>

<prop key="*">PROPAGATION_REQUIRED,readOnly</prop>

这里就是事务处理时如果遇到异常信息,或者其他的原因时我们要求 spring 把当前的事务回滚了,这样才能不至于在数据库中产生垃圾啊。我们规定所有的 save,remove,update,incress 这样的方法开头的在出现一些问题后把事务给回滚了,看看我们写的: PROPAGATION_REQUIRED,-Exception 。

有人就会说 PROPAGATION_REQUIRED 就可以回滚事务啊,为什么加上 ,-Exception 呢?其实我以前也时这样想的,但这是不完全正确的,当然我们在处理一个事务时只要有一个 PROPAGATION_REQUIRED 就可以了,但是当我们的业务逻辑中要求我们在一个事务代理中开启两个事务,这两个事务表面上没有联系,但是实际中又有很多联系的,比如我们上传附件和提交文档,这样两个操作我们可以分开,因为他们不是往一个表里插入数据,我们又不希望这两个操作写在一个 service 里,这样我们要是有一个业务只要上传附件呢?那样我们是不是又要再写一个方法啊!所以在开启两个事务时如果有一个抛出异常了,我们就要把上一个提交的事务回滚了,这样做我们就要用的 -Exception 了,这样就完全满足我们的要求了,我也试过如果我写的是 PROPAGATION_REQUIRED,-SQLException 时,这样我们只会在出现 SQLException 时事务回顾,出现其他的异常事务就不回滚了,好在 spring 可以让我们写如异常的基类就可以做到捕获任何异常,这样我们就写 -Exception 好了。特殊情况在特殊处理吧。通用情况下我们还是这样的。

我们再看看:

<bean id="userManager" parent="txProxyTemplate">

       <property name="target" ref="userManagerTarget" />

</bean>

<bean id="userManagerTarget"

class="mf.org.hb.user.service.impl.UserManagerImpl">

       <property name="userDAO" ref="userDAO" />

</bean>

<bean id="userDAO" class="mf.org.hb.user.dao.hibernate.UserDAOHibernate">

       <property name="sessionFactory" ref="sessionFactory" />

</bean>

    当然我们也可以写成:

<bean id="userManager" parent="txProxyTemplate">

       <property name="target">

           <bean class="mf.org.hb.user.service.impl.UserManagerImpl">

              <property name="userDAO">

                  <ref bean="userDao"/>

              </property>

           </bean>

       </property>

</bean>

<bean id="userDAO" class="mf.org.hb.user.dao.hibernate.UserDAOHibernate">

       <property name="sessionFactory" ref="sessionFactory" />

</bean>



这下我们解除以前的疑惑, parent="txProxyTemplate" 知道我们为什么在上面先写了 txProxyTemplate 的 bean 了吧,这样我们就没有必要再写一编了。是不是很方便? spring 的这些技巧还不只这些呢。这样我们就可以轻松利用以上这三个注入的类去做我们的逻辑了。

Spring 就是要我们注入实现类,然后使用接口操作,这样耦合性就不是那么强了,这也体现了 Spring 的工厂模式。而 AOP 的 manager 又象我们熟知的代理模式吧 !

3.注意要点

在写配置的时候注意各个 Manager 和 DAO 之间的关系,以及 <ref= ”” > 之间的关系,清晰里面的关系才能更好的配置。
分享到:
评论

相关推荐

    java springAOP 事务+注释

    Java Spring AOP(面向切面编程)是Spring框架的核心特性之一,它允许开发者在不修改原有代码的情况下,通过代理方式插入额外的功能,如日志、事务管理等。在这个主题中,我们将深入探讨Spring AOP如何处理事务管理...

    无处不在的Spring AOP事务及踩过的坑

    Spring AOP事务管理是Java开发中的重要组成部分,它极大地简化了在分布式系统中对事务的处理。Spring通过AOP(面向切面编程)提供了一种声明式事务管理方式,允许开发者将事务规则与业务逻辑分离,提高了代码的...

    8月31日-无处不在的Spring AOP事务及踩过的坑-张飞.mp4

    8月31日-无处不在的Spring AOP事务及踩过的坑-张飞.mp4

    springAop事务配置

    在Spring框架中,AOP(面向切面编程)被广泛用于实现事务管理,因为它允许我们以声明式的方式处理事务,从而让业务代码更加简洁、易维护。本篇将详细讲解Spring AOP如何进行事务配置,包括注解和非注解两种方式。 1...

    Spring AOP配置事务方法

    Spring AOP 配置事务方法 Spring AOP(Aspect-Oriented Programming,面向方面编程)是一种编程范式,它允许开发者在不修改源代码的情况下,增强和修改应用程序的行为。 Spring AOP 提供了一种灵活的方式来实现事务...

    spring aop jar 包

    在实际开发中,Spring AOP广泛应用于事务管理。例如,我们可以定义一个切面来处理所有数据库操作的事务,这样无需在每个业务方法中显式调用开始和提交事务,只需在切面中配置事务规则即可。 `aop-jar`这个压缩包...

    Spring AOP 16道面试题及答案.docx

    总的来说,Spring AOP通过代理和通知机制,实现了横切关注点的模块化,使得业务逻辑与系统服务(如日志、事务等)解耦,提高了代码的可读性和可维护性。同时,引介功能进一步增强了切面的功能,可以为对象动态地添加...

    简单spring aop 例子

    Spring AOP(面向切面编程)是Spring框架的重要组成部分,它提供了一种模块化和声明式的方式来处理系统中的交叉关注点问题,如日志、事务管理、安全性等。本示例将简要介绍如何在Spring应用中实现AOP,通过实际的...

    Spring AOP完整例子

    总结一下,Spring AOP提供了一种优雅的方式来处理系统的横切关注点,如日志记录、事务管理或性能监控。通过定义切点、创建切面和配置通知,我们可以实现代码的解耦,提高可维护性和复用性。这个例子提供了学习Spring...

    spring aop依赖jar包

    现在,我们回到主题——"springaop依赖的jar包"。在Spring 2.5.6版本中,使用Spring AOP通常需要以下核心jar包: - `spring-aop.jar`:这是Spring AOP的核心库,包含了AOP相关的类和接口。 - `spring-beans.jar`:...

    Spring Aop四个依赖的Jar包

    Spring AOP,全称Aspect-Oriented Programming(面向切面编程),是Spring框架的一个重要模块,它通过提供声明式的方式来实现面向切面编程,从而简化了应用程序的开发和维护。在Spring AOP中,我们无需深入到每个...

    Spring AOP面向方面编程原理:AOP概念

    ### Spring AOP面向方面编程原理:AOP概念详解 #### 一、引言 随着软件系统的日益复杂,传统的面向对象编程(OOP)逐渐暴露出难以应对某些横切关注点(cross-cutting concerns)的问题。为了解决这一挑战,面向方面编程...

    Spring AOP实现机制

    Spring AOP(面向切面编程)是Spring框架的核心特性之一,它允许程序员在不修改源代码的情况下,通过“切面”来插入额外的业务逻辑,如日志、事务管理等。AOP的引入极大地提高了代码的可复用性和可维护性。 ### 1. ...

    spring AOP依赖三个jar包

    Spring AOP,即Spring的面向切面编程模块,是Spring框架的重要组成部分,它允许开发者在不修改源代码的情况下,对程序进行横切关注点的处理,如日志、事务管理等。实现这一功能,主要依赖于三个核心的jar包:aop...

    线程池中使用spring aop事务增强

    本篇文章将深入探讨如何在使用线程池的情况下,利用Spring AOP来增强事务处理。 首先,让我们理解问题的核心。在给定的示例中,一个服务类`AAAService`有一个`doJob`方法,它会将`job`方法提交给线程池执行。由于`...

    spring aop 五个依赖jar

    Spring AOP(面向切面编程)是Spring框架的重要组成部分,它提供了一种模块化和声明式的方式来处理系统中的交叉关注点,如日志、事务管理等。在Java应用中,AOP通过代理模式实现了切面编程,使得我们可以将业务逻辑...

    mybatis 拦截器 + spring aop切面 + spring事务+ 反射工具类

    在IT行业中,MyBatis、Spring AOP、Spring事务管理和反射工具类是常见的技术栈,它们在构建高效、灵活的企业级应用中起着至关重要的作用。以下是对这些知识点的详细阐述: 1. MyBatis拦截器(MyBatis Interceptor)...

    spring AOP 引入jar包,spring IOC 引入Jar包

    Spring AOP 和 Spring IOC 是 Spring 框架的两个核心组件,它们对于任何基于 Java 的企业级应用开发都至关重要。Spring AOP(面向切面编程)允许开发者在不修改源代码的情况下,通过“切面”来插入新的行为或增强已...

    spring aop 学习笔记

    Spring AOP(面向切面编程)是Spring框架的重要组成部分,它提供了一种模块化和抽象化的方法来处理系统中的交叉关注点,如日志、事务管理、安全性等。本学习笔记将深入探讨Spring AOP的核心概念、工作原理以及实际...

    spring-aop实例

    Spring AOP(面向切面编程)是Spring框架的重要组成部分,它提供了一种强大的方式来实现横切关注点,如日志、事务管理、安全性等,从而解耦应用程序的核心业务逻辑。在Spring AOP中,关注点被模块化为独立的“切面”...

Global site tag (gtag.js) - Google Analytics