Fork me on GitHub

Spring 事务配置

注意:所有文章除特别说明外,转载请注明出处.

概念

Spring MVC与Mybatis整合框架的事务管理方式有两种:1.声明式事务管理 2.编程式事务管理。

1.编程式事务管理和声明式事务管理

编程式事务管理使用TransactionTemplate或者直接使用底层的PlatformTransactionManager,对于编程式事务管理,spring推荐使用TransactionTemplate。

声明式事务管理是建立在AOP基础上,本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。该声明式事务最大的优点就是不需要通过编程的方式管理事务,只需要在配置文件中声明,然后通过@Transactionoal注解声明便可以将事务规则应用到业务逻辑中。

2.声明式事务的两种常用方式

1.基于tx和aop名字空间的xml配置文件

<!-- 事物切面配置 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource" />
</bean>

<tx:advice id="advice" transaction-manager="transactionManager">
    <tx:attributes> 
        <tx:method name="update*" propagation="REQUIRED" read-only="false" rollback-for="java.lang.Exception"/>
        <tx:method name="insert" propagation="REQUIRED" read-only="false"/>
    </tx:attributes> 
</tx:advice>

<aop:config>
    <aop:pointcut id="testService" expression="execution (* com.baobao.service.MyBatisService.*(..))"/>
    <aop:advisor advice-ref="advice" pointcut-ref="testService"/>  
</aop:config>

注意:因为springmvc配置文件和spring配置文件不同时加载,如果这边不进行这样的设置,那么,spring就会将所有带@Service注解的类都扫描到容器中,等到加载spring的配置文件的时候,会因为容器已经存在Service类,使得cglib将不对Service进行代理,直接导致的结果就是在spring配置文件中的事务配置不起作用。所以在spring.xml配置文件中添加不扫描controller,然后在springmvc.xml中添加不扫描service。

<!-- 1.在spring.xml配置文件中添加不扫描controller -->
<context:component-scan base-package="cn.edu.xidian.see.*">
    <context:exclude-filter type="annotation"
        expression="org.springframework.stereotype.Controller" />
</context:component-scan>

<!--2.在springmvc.xml配置文件中添加不扫描service 要扫描controller-->
<context:component-scan base-package="cn.edu.xidian.see.controller">
    <context:include-filter type="annotation"
        expression="org.springframework.stereotype.Controller" />
    <context:exclude-filter type="annotation"
        expression="org.springframework.stereotype.Service" />
</context:component-scan>

2.基于@Transactional注解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
1.在配置文件spring.xml中,去掉对controller的扫描
<context:component-scan base-package="com.digitalchina.*">
  <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller" />
  </context:component-scan>
 
  2.在配置文件springmvc.xml中,去掉对service的扫描,加入对controller的扫描
 <context:component-scan base-package="com.digitalchina.*">
 <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" />
 <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service" />
 </context:component-scan>
 
  3.事务的配置只有在spring.xml中才会起作用,即
 
  //该配置必须配置在 spring.xml 中才可以。
  <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
   <property name="dataSource" ref="dataSource" />
  </bean>
  
  4.用事务去控制的service,不能加try-catch去捕获异常,否则不能被spring拦截到,事务就失效了。

  5.在Service实现类中增加@Transactional注解即可控制事务。

3.事务配置

<!-- 配置事务管理 -->
<bean name="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
</bean>

<!-- 拦截器方式配置事物 -->
<tx:advice id="transactionAdvice" transaction-manager="transactionManager">
    <tx:attributes>
        <!-- 必须要有事务,没有则创建 
            事务的传播级别表示事务的控制范围,主要是父子事务之间的相互影响关系
            事务的隔离级别表示事务读写的控制范围,主要是两个事务之间的相互影响关系

            1.REQUIRED 表示当前方法已经在事务中,那么就以父事务执行,不需要创建新事务
        -->
        <tx:method name="insert*" propagation="REQUIRED" />
        <tx:method name="update*" propagation="REQUIRED" />
        <tx:method name="delete*" propagation="REQUIRED" />
        <!-- 可以有可以没有 -->
        <tx:method name="get*" propagation="SUPPORTS" read-only="true" />
        <tx:method name="find*" propagation="SUPPORTS" read-only="true" />
        <tx:method name="select*" propagation="SUPPORTS" read-only="true" />
    </tx:attributes>
</tx:advice>

<!-- Spring aop事务管理 -->
<aop:config>
    <aop:pointcut id="transactionPointcut" expression="execution(* com.sanguo.service.impl..*Impl.*(..))" />
    <aop:advisor pointcut-ref="transactionPointcut" advice-ref="transactionAdvice"/>
</aop:config>

ThreadLocal 知识

ThreadLocal 在Spring中发挥着重要作用,在管理request作用域的bean | 事务管理 | 任务调度 | AOP等。Java 1.2版本提供 java.lang.ThreadLocal为解决多线程程序的并发问题。ThreadLocal不是一个线程,是一个保存线程本地化对象的容器。

ThreadLocal的接口方法

1.void set(Object value) 设置当前线程的线程局部变量的值
2.public Object get() 返回当前线程所对应的线程局部变量
3.public void remove() 将当前线程局部变量的值删除

提示:在ThreadLocal类中有一个Map,用于存储每个线程的变量副本,Map中元素的键为线程对象,值为对应线程的变量副本。

ThreadLocal 与 同步机制的比较

在同步机制中通过对象的锁机制保证同一时间只有一个线程访问变量。ThreadLocal为每一个线程提供一个独立的变量副本,从而隔离了多个线程对访问数据的冲突。因为每一个线程都用有了一个变量副本。

总结:在多线程资源共享的问题上,同步机制采用””以时间换空间”的方式,访问串行化,对象共享化。ThreadLocal采用””以空间换时间”的方式,访问并行化,对象独享化。

本文标题:Spring 事务配置

文章作者:Bangjin-Hu

发布时间:2019年10月15日 - 09:22:26

最后更新:2020年03月30日 - 08:01:13

原始链接:http://bangjinhu.github.io/undefined/Spring - 事务配置/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

Bangjin-Hu wechat
欢迎扫码关注微信公众号,订阅我的微信公众号.
坚持原创技术分享,您的支持是我创作的动力.