基于XML的事务配置
beans.xml中AOP的配置:
<bean id="serviceAspect" class="com.myspring.app.aop.MyAdvice"/> //切面代码
<!-- 配置事务传播特性 -->
<tx:advice id="TestAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:methodname="save*" propagation="REQUIRED"/>
<tx:methodname="del*" propagation="REQUIRED"/>
<tx:methodname="update*" propagation="REQUIRED"/>
<tx:methodname="add*" propagation="REQUIRED"/>
<tx:methodname="find*" propagation="REQUIRED"/>
<tx:methodname="get*" propagation="REQUIRED"/>
<tx:methodname="apply*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<!-- 配置参与事务的类 -->
<aop:config>
<!--定义向导,引起切点和通知-->
<aop:advisor pointcut-ref="allTestServiceMethod" advice-ref="TestAdvice"/>
</aop:config>
【说明】
(1)<tx> 命名空间用于配置声明式事务。得益于 <aop> 命名空间的切点表达式支持,声明式事务也变得更加强大。
<tx:advice/>标签,该标签会创建一个事务处理通知。结合<aop> 命名空间,就会把begin()、commit()等方法插入到事务的前后,配置变得更加简单和灵活。
不配置tx,它是不会开启事务的。我们调用增删查改,代码里面没有transition.begin(),就是aop帮你调用了。aop就是在你配置的那些方法,帮他们在被调用前,和被调用后,执行相应的逻辑。我们那些执行事务的开启执行的方法,比如commit都是通过aop的方式切入的。它可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术。
(2) tx:attribute标签所配置的是作为事务的方法的命名类型。如<tx:method name="save" propagation="REQUIRED"/>,其中为通配符,即代表以save为开头的所有方法,即表示符合此命名规则的方法作为一个事务。
Spring事务类型详解
- PROPAGATION_REQUIRED--支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。
- PROPAGATION_SUPPORTS--支持当前事务,如果当前没有事务,就以非事务方式执行。
- PROPAGATION_MANDATORY--支持当前事务,如果当前没有事务,就抛出异常。
- PROPAGATION_REQUIRES_NEW--新建事务,如果当前存在事务,把当前事务挂起。
- PROPAGATION_NOT_SUPPORTED--以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
- PROPAGATION_NEVER--以非事务方式执行,如果当前存在事务,则抛出异常。
- PROPAGATION_NESTED--如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则进行与PROPAGATION_REQUIRED类似的操作。
基于@Transactional 的注解式事务
@Transactional简介
@Transactional采用注解式事务,所有标记为这个注解的并且能被spring扫描到的方法都会根据@Transactional的配置来使用事务。
@Transactional 可以作用于接口、接口方法、类以及类方法上。当作用于类上时,该类的所有 public 方法将都具有该类型的事务属性,同时,我们也可以在方法级别使用该标注来覆盖类级别的定义。
@Transactional配置事务
//必须的(默认的)
@Transactional(propagation = Propagation.REQUIRED)
//强制的(必须有transaction)
@Transactional(propagation = Propagation.MANDATORY)
//内嵌的**transaction**
@Transactional(propagation = Propagation.NESTED)
//绝不能有transaction
@Transactional(propagation = Propagation.NEVER)
//方法要执行,遇到的transaction挂起。
@Transactional(propagation = Propagation.NOT_SUPPORTED)
//方法要执行,遇到的transaction挂起,创建新的transaction。
@Transactional(propagation = Propagation.REQUIRES_NEW)
//有没有无所谓
@Transactional(propagation = Propagation.SUPPORTS)
@Transactional使用方法
如果要使用@Transactional,首先要在配置文件中配置如下事务管理器:
<!-- 定义一个数据源 -->
<bean id="dataSource" class="org.apache.tomcat.jdbc.pool.DataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/spring_test" />
<property name="username" value="root" />
<property name="password" value="root" />
</bean>
<!-- 配置事务管理器 -->
<bean id="txManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
p:dataSource-ref="dataSource">
</bean>
<!-- enables scanning for @Transactional annotations -->
<tx:annotation-driven transaction-manager="txManager" />
然后我们就可以代码中使用@Transactional:
public class userService{
@Transactional(readonly=false)
public void addUser(){..}
@Transactional(readonly=true)
public void getUserById(int id){..}
}
@Transactional声明的方法执行时经历的步骤
@Transactional声明的方法执行时,会经历以下步骤:
(1)Spring的TransactionManager会自动Open Sesion,自动开启事务,并且将此Session绑定到SpringSessionContext。
(2)SessionFactory.getCurrentSession()方法执行时,调用SpringSessionContext.currentSession()从TransactionSynchronizationManager的上下文中查找当前的Session。
(3)找到后返回当前的Session,找不到则返回HibernateException("No Session found for current thread")。
@Transactional标注的位置
@Transactional通常应该写在service层,因为service层是业务处理类。在service加@Transactional,声明这个service所有方法需要事务管理,每个业务方法开始时都会打开一个事务。注意,如果@Transactional写在test层,spring是扫描不到的,如:
运行时就会报org.hibernate.HibernateException: Could not obtain transaction-synchronized Session for current thread的错,也就是spring无法扫描到@Transaction。
另外要注意的是,如果把@Transactional 加在整个类上,那么不需要事务的方法也运行在事务中。