声明式事务管理
Spring的声明式事务管理,是通过Spring AOP实现的。
Spring事务类型:
名称 | 说明 |
---|---|
PROPAGATION_REQUIRED | 支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择 |
PROPAGATION_SUPPORTS | 支持当前事务,如果当前没有事务,就以非事务方式执行。 |
PROPAGATION_MANDATORY | 支持当前事务,如果当前没有事务,就抛出异常。 |
PROPAGATION_REQUIRES_NEW | 新建事务,如果当前存在事务,把当前事务挂起。 |
PROPAGATION_NOT_SUPPORTED | 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。 |
PROPAGATION_NEVER | 以非事务方式执行,如果当前存在事务,则抛出异常。 |
PROPAGATION_NESTED | 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则进行与PROPAGATION_REQUIRED类似的操作。 |
配置
Spring关于事务配置包含3部分:
- DataSource
- TransactionManager
- 代理机制
在使用Hibernate时:
DataSource的实现为SessionFactory,
TransactionManager的实现为HibernateTransactionManager。
公共配置
<!-- 配置sessionFactory -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="configLocation">
<value>classpath:config/hibernate.cfg.xml</value>
</property>
<property name="packagesToScan">
<list>
<value>com.entity</value>
</list>
</property>
</bean>
<!-- 配置事务管理器(声明式的事务) -->
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>
<!-- 配置DAO -->
<bean id="userDao" class="com.dao.UserDaoImpl">
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>
方法1 使用tx标签
<!-- 第一种配置事务的方式 ,tx-->
<tx:advice id="txadvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="add*" propagation="REQUIRED" rollback-for="Exception" />
<tx:method name="modify*" propagation="REQUIRED" rollback-for="Exception" />
<tx:method name="del*" propagation="REQUIRED" rollback-for="Exception"/>
<tx:method name="*" propagation="REQUIRED" read-only="true"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="daoMethod" expression="execution(* com.dao.*.*(..))"/>
<aop:advisor pointcut-ref="daoMethod" advice-ref="txadvice"/>
</aop:config>
方法2 使用代理方式
<!-- 第二种配置事务的方式 ,代理-->
<bean id="transactionProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" abstract="true">
<property name="transactionManager" ref="transactionManager"></property>
<property name="transactionAttributes">
<props>
<prop key="add*">PROPAGATION_REQUIRED, -Exception</prop>
<prop key="modify*">PROPAGATION_REQUIRED, -Exception</prop>
<prop key="del*">PROPAGATION_REQUIRED, -Exception</prop>
<prop key="*">PROPAGATION_REQUIRED, readOnly</prop>
</props>
</property>
</bean>
<bean id="userDao" parent="transactionProxy">
<property name="target">
<!-- 用bean代替ref的方式-->
<bean class="com.dao.UserDaoImpl">
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>
</property>
</bean>
将transactionProxy的abstract属性设置为”true”,然后将具体的Dao的parent属性设置为”transactionProxy”,可以精简代码。
方法3 使用拦截器
<!-- 第三种配置事务的方式,拦截器 (比较老的方式,不常用)-->
<bean id="transactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor">
<property name="transactionManager" ref="transactionManager"></property>
<property name="transactionAttributes">
<props>
<prop key="add*">PROPAGATION_REQUIRED, -Exception</prop>
<prop key="modify*">PROPAGATION_REQUIRED, -Exception</prop>
<prop key="del*">PROPAGATION_REQUIRED, -Exception</prop>
<prop key="*">PROPAGATION_REQUIRED, readOnly</prop>
</props>
</property>
</bean>
<bean id="proxyFactory" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="interceptorNames">
<list>
<value>transactionInterceptor</value>
</list>
</property>
<property name="beanNames">
<list>
<value>*Dao</value>
</list>
</property>
</bean>
方法4 注解方式,不适合较大的项目
<!--开启注解方式,必须的-->
<context:annotation-config />
<!--注解扫描-->
<context:component-scan base-package="com.bluesky" />
<tx:annotation-driven transaction-manager="transactionManager"/>
<!-- 配置sessionFactory -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="configLocation">
<value>classpath:config/hibernate.cfg.xml</value>
</property>
<!-- 扫描包位置配置在bean属性内
<property name="packagesToScan">
<list>
<value>com.entity</value>
</list>
</property>
-->
</bean>
<!-- 配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>
下面要在dao上加下@Transactional注解(同时在继承过来父类的baseDao也要注解)。
注解文件示例
package com.dao;
import org.springframework.orm.hibernate3.HibernateTemplate;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import com.entity.User;
@Transactional
public class UserDaoImpl_BAK extends HibernateTemplate {
@Transactional(propagation=Propagation.REQUIRED,rollbackForClassName="Exception")
public void addUser(User user) throws Exception {
this.save(user);
}
@Transactional(propagation=Propagation.REQUIRED,rollbackForClassName="Exception")
public void modifyUser(User user) {
this.update(user);
}
@Transactional(propagation=Propagation.REQUIRED,rollbackForClassName="Exception")
public void delUser(String username) {
this.delete(this.load(User.class, username));
}
@Transactional(readOnly=true)
public void selectUser() {
}
}
使用注解时,可能编译器会提示:
advised by
org.springframework.transaction.interceptor.TransactionInterceptor.invoke(org.aopalliance.intercept.MethodInvocation)
可修改如下:
<context:component-scan base-package="我的包名" use-default-filters="false"></context:component-scan>
说明
如下方式可以成功扫描到@Controller注解的Bean,不会扫描@Service/@Repository的Bean。
<context:component-scan base-package="org.bdp.system.test.controller">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
如下方式,不仅仅扫描@Controller,还扫描@Service/@Repository的Bean:
<context:component-scan base-package="org.bdp">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
这个尤其在springmvc+spring+hibernate等集成时最容易出问题的地,最典型的错误就是:事务不起作用。
参考:
http://blog.csdn.net/liushuijinger/article/details/17364413
http://jinnianshilongnian.iteye.com/blog/1762632