`

Spring_@Transactional

阅读更多

via: http://www.cnblogs.com/hjwublog/p/5626465.html

 

事务的基本概念

先来回顾一下事务的基本概念和特性。数据库事务(Database Transaction) ,是指作为单个逻辑工作单元执行的一系列操作,要么完全地执行,要么完全地不执行。事务,就必须具备ACID特性,即原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)和持久性(Durability)

编程式事务与声明式事务

Spring与Hibernate的整合实现的事务管理是常用的一种功能。Hibernate 建议所有的数据库访问都应放在事务内进行,即使只进行只读操作。事务又应该尽可能短,因为长事务会导致长时间无法释放表内行级锁,从而降低系统并发的性能。 Spring 同时支持编程式事务声明式事务

 

编程式事务需要在代码中显式调用beginTransaction()、commit()、rollback()等事务管理相关的方法Spring 的声明式事务管理在底层是建立在 AOP 的基础之上的,其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。事务增强也是AOP的一大用武之处。

使用声明式事务

声明式事务最大的优点就是不需要通过编程的方式管理事务,这样就不需要在业务逻辑代码中掺杂事务管理的代码,只需在配置文件中做相关的事务规则声明,很好的分离了业务逻辑和事务管理逻辑。以spring+jpa整合增加声明式事务为例,下面是使用声明式事务的配置方式以及使用。

applicationContext.xml配置

<!-- 配置entityManagerFactory 配置 -->

<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">

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

     <property name="persistenceXmlLocation" value="/WEB-INF/classes/persistence.xml" />

     <property name="loadTimeWeaver">

             <bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver" />

     </property>

</bean>

 

<!-- 配置声明式事务管理,使用JpaTransactionManager作为事务管理器的实现类 –>

<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">

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

</bean>

 

<!--声明业务组件使用注解生成事务代理 -->

<tx:annotation-driven transaction-manager="transactionManager" />

使用@Transactional 配置声明式事务管理

在spirng 的配置文件中配置了事务管理和注解驱动之后,我们就可以在业务层使用@Transactional 配置声明式事务管理了。如下

 

@Service

@Transactional

public class BaseService<T> implements IBaseService<T> {

 

@Autowired

private IBaseDao<T> baseDao;

......

}

@Transactional 深入使用

上面我们已经知道了声明式事务管理的用法了,下面我们将进一步分析@Transactional在各种场景下用法。

事务的传播行为

@Transactional注解支持9个属性的设置,其中Propagation属性用来枚举事务的传播行为。所谓事务传播行为就是多个事务方法相互调用时,事务如何在这些方法间传播。Spring 支持 7 种事务传播行为:

 

wps9181.tmp 

 

REQUIRED 是常用的事务传播行为,如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。其它传播行为大家可另查阅。

多个事务方法的嵌套调用时的事务传播

有三个事务方法调用嵌套关系如下:

 

PayHisInfoService.update()->PayHisInfoService.save()->PayInfoService.update()

 

@Transactional(propagation=Propagation.REQUIRED)

public abstract class BaseService<E>{

          public abstract List<E> findAll();

}

 

@Component

public class PayHisInfoService extends BaseService<PayHisInfo>{

       @Resource

       private PayHisInfoDao payHisInfoDao;

@Resource

private PayInfoService payInfoService;

 

       public  void update(PayHisInfo payHisInfo,PayInfo payInfo){

     save(payHisInfo);

            payInfoService.update(payInfo);

      }

      public int save(PayHisInfo payHisInfo){

         return payHisInfoDao.insert(payHisInfo);

      }

}

 

@Component

public class PayInfoService extends BaseService<PayInfo>{

     @Resource

     private transient PayInfoDao payInfoDao;

 

     @Override

     @Transactional(propagation=Propagation.SUPPORTS, readOnly=true)

     public List<PayInfo> findAll() {

            return payInfoDao.findAll();

     }

 

     public int update(PayInfo payInfo){

            return payInfoDao.update(payInfo);

     }

}

 

 

当我们按照上面的调用嵌套关系执行时,结果如下

 

 

 

 

从日志中我们可以看出,PayHisInfoService.update()执行时开启了一个事务,而PayHisInfoService.save()方法和PayHisInfoService.update()方法处于同一个类中,调用时没有发生事务传播,就像已经处于PayHisInfoService.update()方法的事务当中一样。而当执行PayInfoService.update()时,提示“Participating in existing transaction”,这说明发生了事务传播,即PayInfoService.update()并没有新建一个事务,而是加入到已有的PayHisInfoService.update()事务中。

多线程环境下的事务传播

现在我们将上面例子中的PayHisInfoService.update()用另一个线程来执行,如下

 

@Component

public class PayHisInfoService extends BaseService<PayHisInfo>{

    @Resource

    private PayHisInfoDao payHisInfoDao;

    @Resource

    private PayInfoService payInfoService;

 

    public  void update(PayHisInfo payHisInfo,PayInfo payInfo){

          save(payHisInfo);

           //payInfoService.update(payInfo);

         PayInfoThread pifth = new PayInfoThread(payInfoService,payInfo);

         pifth.start();

     }

 

     public int save(PayHisInfo payHisInfo){

          return payHisInfoDao.insert(payHisInfo);

     }

 

     private class PayInfoThread extends Thread{

        private PayInfoService payInfoService;

        private PayInfo payInfo;

       

        private PayInfoThread(PayInfoService payInfoService,PayInfo payInfo) {

            this.payInfoService = payInfoService;

            this.payInfo = payInfo;

        }

        public void run() {

               System.out.println("PayInfoThread updating payInfo...");

               payInfoService.update(payInfo);

        }

  }

}

 

当我们按照上面的调用嵌套关系执行时,结果如下

 

 

 

从日志结果可以看出,在执行PayHisInfoService.update()和PayInfoService.update()时分别创建了各自的事务。而PayHisInfoService.save()和PayHisInfoService.update()则在同一个线程中执行。所以spring 的事务管理是线程安全的

在相同线程中进行相互嵌套调用的事务方法工作于相同的事务中。如果这些相互嵌套调用的方法工作在不同的线程中,不同线程下的事务方法工作在独立的事务中。

@Transactional的继承关系

或许你已经在上面的例子中看出了,我们只在父类BaseService中声明了@Transactional,子类就自然得到事务增强。注解并没有继承这种说法,但此处用“继承关系”来形容父类@Transactional和子类方法之间的关系最恰当不过了:父类Service声明了@Transactional,子类继承父类,父类的声明的@Transactional会对子类的所有方法进行事务增强。这个还有个很实用的用法,例如测试基类继承

AbstractTransactionalJUnit4SpringContextTests

声明@Transactional可方便进行事务测试

 

@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration("/applicationContext.xml")

@TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true)

@Transactional

public class BaseTest extends AbstractTransactionalJUnit4SpringContextTests {

        public Object getBean(String beanName){

                return applicationContext.getBean(beanName);

         }

}

 

给BaseTest 声明了@Transactional了之后,就会自动给我们自己编写的测试类中的所有测试方法进行事务增强。

@Transactional的优先级

如果子类的方法重写了父类的方法并且声明了@Transactional,那么子类的事务声明会优先于父类的事务声明。

利用springAOP进行事务切面增强

还是上面的列子,把父类声明的@Transactional去掉。在applicationContext.xml中配置事务增强切面,配置如下:

 

<!--②使用aop和tx命名空间语法为PayHisInfoService所有公用方法添加事务增强 -->

    <aop:config proxy-target-class="true">

        <aop:pointcut id="serviceJdbcMethod"

        expression="execution(public * com.xxx.service.PayHisInfoService.*(..))"/>

        <aop:advisor pointcut-ref="serviceJdbcMethod" advice-ref="jdbcAdvice" order="0"/>

    </aop:config>

    <tx:advice id="jdbcAdvice" transaction-manager="transactionManager">

        <tx:attributes>

            <tx:method name="*"/>

        </tx:attributes>

    </tx:advice>

 

运行测试用例,结果如下:

 

 

 

当有一条数据更新失败时,事务会自动回滚,如下:

 

wps9195.tmp 

@Transactional方法的可见度

上面为了测试演示方便,我们把@Transactional都声明在了类上。实际上@Transactional 可以作用于接口、接口方法、类以及类方法上。但是 Spring 小组建议不要在接口或者接口方法上使用该注解,因为这只有在使用基于接口的代理时它才会生效。另外, @Transactional 注解应该只被应用到 public 方法上,这是由 Spring AOP 的本质决定的(从上面的Spring AOP 事务增强可以看出,就是针对方法的)。如果你在 protected、private 或者默认可见性的方法上使用 @Transactional 注解,这将被忽略,也不会抛出任何异常。

总结

(1)声明式事务优于编程式事务

(2)事务方法的嵌套调用会产生事务传播

(3)spring 的事务管理是线程安全的

(4)父类的声明的@Transactional会对子类的所有方法进行事务增强

(5)从Spring AOP本质看,@Transactional 注解应该只被应用到 public 方法上

分享到:
评论

相关推荐

    后端 Java Spring Data Jpa @Transactional 介绍

    在Java后端开发中,Spring框架提供了强大的事务管理能力,特别是在使用Spring Data JPA时,`@Transactional`注解使得事务处理变得简单易用。这个注解是Spring框架中的核心部分,它允许开发者声明性地控制事务边界,...

    spring-@Transactional-jar

    spring事务管理注解jar,spring-tx-3.2.4.RELEASE.jar,导入项目即可

    Spring中@Transactional事务回滚(含实例

    在Spring框架中,`@Transactional`注解是用于标记事务管理的重要工具,它使得开发者能够方便地在代码中声明式地控制事务的边界。本文将深入解析`@Transactional`的事务回滚机制,并通过实例来详细讲解其工作原理,...

    Spring @Transactional工作原理详解

    在Spring框架中,`@Transactional`注解是一个强大的工具,用于声明式地管理事务。它使得开发者无需显式地在代码中控制事务的开始、提交和回滚,从而提高了代码的可读性和可维护性。下面我们将深入探讨`@...

    spring的@Transactional注解详细用法1

    总的来说,Spring的`@Transactional`注解为开发者提供了方便且强大的声明式事务管理能力。它简化了事务控制,让开发者能够专注于业务逻辑,而无需关心事务的细节。尽管编程式事务管理可以提供更细粒度的控制,但声明...

    Spring3事务管理——使用@Transactional 注解.rar

    Spring3引入了基于注解的事务管理,极大地简化了事务配置,使得开发者可以在方法级别声明事务边界,这就是`@Transactional`注解的用处。本文将深入探讨这个注解以及如何在Spring3中有效地使用它。 `@Transactional`...

    springboot中事务管理@Transactional的注意事项与使用场景

    2. 默认回滚机制:Spring 基于注解的声明式事物 @Transactional 默认情况下只会对运行期异常(java.lang.RuntimeException 及其子类)和 Error 进行回滚。 3. 数据库引擎支持:数据库引擎要支持事务,使用 InnoDB。 ...

    浅谈Spring中@Transactional事务回滚及示例(附源码)

    浅谈Spring中@Transactional事务回滚及示例 @Transactional是Spring Framework中的一种事务管理机制,用于管理数据库事务。它可以使得数据库操作更加安全和可靠。本文将详细介绍@Transactional的使用场景、checked...

    Spring声明式事务@Transactional知识点分享

    "Spring声明式事务@Transactional知识点分享" 在 Spring 框架中,@Transactional 注解是实现声明式事务的关键。通过 @Transactional 注解,可以指定事务的传播行为、隔离级别、读写控制等属性。 首先,@...

    spring @Transactional 无效的解决方案

    "Spring @Transactional 无效的解决方案" Spring框架中的@Transactional注解是用来实现事务管理的,但是有时候我们可能会遇到@Transactional注解无效的情况。在这篇文章中,我们将 introducethe 解决方案,并通过...

    test-transactional:关于spring中@Transactional注解传播属性原理的实验

    关于spring中@Transactional注解传播属性原理的实验 具体方法: 主体形式:a方法调用b方法 a插入数据“one” b插入数据“two” a、b方法都可以有不同的传播级别或者不加事务注解(none): required(rd), required_...

    spring的@Transactional注解用法解读

    【Spring的@Transactional注解用法解读】 事务管理是企业级应用程序中的关键部分,它确保了在发生异常时数据的一致性。Spring框架提供了一种统一的方式来处理事务管理,包括对不同事务API(如JTA、JDBC、Hibernate...

    深入学习Spring Boot排查 @Transactional 引起的 NullPointerException问题

    深入学习Spring Boot排查 @Transactional 引起的 NullPointerException问题 在 Spring Boot 应用程序中,@Transactional 注解是非常常用的,它能够帮助我们管理事务,使得数据库操作更加可靠和安全。然而,在某些...

    spring 自定义事务管理器,编程式事务,声明式事务@Transactional使用

    本教程将深入探讨如何在Spring中实现自定义事务管理器、编程式事务处理以及声明式事务`@Transactional`的使用。 首先,让我们了解事务管理的基本概念。事务是一组数据库操作,这些操作要么全部执行,要么全部回滚,...

    Spring中的@Transactional事物回滚实例源码

    在Spring框架中,`@Transactional`注解是事务管理的核心组件,它允许开发者在方法级别声明事务边界。本文将深入探讨这个注解的工作原理、如何配置以及如何在遇到异常时触发事务回滚。 首先,`@Transactional`是...

    Spring @Transactional注解失效解决方案

    Spring @Transactional 注解失效解决方案 在 Spring 框架中,@Transactional 注解是用于管理事务的关键工具之一。但是,在实际开发中,我们经常会遇到 @Transactional 注解失效的问题。本篇文章将详细介绍 @...

    什么情况会导致@Transactional事务失效?

    在Java编程中,`@Transactional`注解是Spring框架提供的一种事务管理机制,它使得开发者能够在方法级别方便地声明事务边界。然而,在某些特定情况下,`@Transactional`可能会失效,导致事务无法正常工作。以下是一些...

    带有@Transactional和@Async的循环依赖问题

    在Spring框架中,`@Transactional` 和 `@Async` 是两个非常重要的注解,它们分别用于声明事务管理和异步执行。然而,当这两个注解同时出现在一个方法上时,可能会引发一些复杂的问题,特别是在存在循环依赖的情况下...

    Spring源码学习十二:@Transactional是如何工作的1

    Spring 框架中 @Transactional 注解的工作原理分析 在 Spring 框架中,@Transactional 注解是一个非常重要的概念,经常用于数据库操作。那么,@Transactional 注解是如何工作的呢?让我们深入源码分析。 首先,从 ...

    Spring中@Transactional用法详细介绍

    Spring中的@Transactional注解是Spring框架提供的一个核心特性,它用于声明式事务管理,使得开发者可以在不直接接触事务API的情况下,实现事务的控制。这个注解可以用在类或方法级别,来指定事务的传播行为、隔离...

Global site tag (gtag.js) - Google Analytics