Sping 学习笔记8——SSH框架中事务的声明与配置

声明式事务管理

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

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

编程圈子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值