深入了解Spring之事务

告别手动复制粘贴!用Python脚本+pywinauto实现PC微信消息自动发送(附完整源码) 本文详细介绍了如何利用Python和pywinauto实现PC微信消息的自动化发送,告别繁琐的手动操作。从环境搭建、UI控件定位到构建健壮的发送流程,再到高级功能扩展和项目打包部署,全面解析了自动化办公的实现方案,显著提升工作效率。 阅读详情

GitHub:https://github.com/JDawnF/learning_note

目录

1、事务

2、事务的特性

3、列举 Spring 支持的事务管理类型

3.1 声明式事务

a.基于TransactionInterceptor的声明式事务:

b.基于TransactionProxyFactoryBean的声明式事务

c.基于命名空间的声明式事务

d.基于标注(@Transactional)的声明式事务

3.2 编程式事务

4、事务管理接口

4.1 Spring 事务如何和不同的数据持久层框架做集成

4.2 PlatformTransactionManager接口代码如下:

4.3 TransactionDefinition接口介绍

事务属性

4.4 TransactionStatus接口介绍


1、事务

事务就是对一系列的数据库操作(比如插入多条数据)进行统一的提交或回滚操作,如果插入成功,那么一起成功,如果中间有一条出现异常,那么回滚之前的所有操作。

这样可以防止出现脏数据,防止数据库数据出现问题。

2、事务的特性

指的是 ACID ,如下图所示:

  1. 原子性 Atomicity :一个事务(transaction)中的所有操作,或者全部完成,或者全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被恢复(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。即,事务不可分割、不可约简。

  2. 一致性 Consistency :在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这表示写入的资料必须完全符合所有的预设约束、触发器、级联回滚等。

  3. 隔离性 Isolation :数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。事务隔离分为不同级别,包括读未提交(Read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(Serializable)。

  4. 持久性 Durability :事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。

3、列举 Spring 支持的事务管理类型

目前 Spring 提供两种类型的事务管理:

  • 声明式事务:基于AOP,通过使用注解或基于 XML 的配置事务,从而事务管理与业务代码分离。

  • 编程式事务:通过编码的方式实现事务管理,需要在代码中显式的调用事务的获得、提交、回滚,提供极大的灵活性,但维护起来非常困难。

3.1 声明式事务

    Spring的声明式事务管理建立在AOP基础上,其本质是在目标方法执行前进行拦截,在方法开始前创建一个事务,在执行完方法后根据执行情况提交或回滚事务。声明式事务最大的优点就是不需要通过编程的方式管理事务,这样就不用侵入业务代码,只需要在配置文件中做相关的事物声明就可将业务规则应用到业务逻辑中。和编程式事务相比,声明式事务唯一的不足是智能作用到方法级别,无法做到像编程式事务那样到代码块级别。

声明式事务有四种方式:

a.基于TransactionInterceptor的声明式事务;

b.基于TransactionProxyFactoryBean的声明式事务;

c.基于命名空间的声明式事务;

d.基于标注(@Transactional)的声明式事务。

a.基于TransactionInterceptor的声明式事务:

  TransactionInterceptor主要有两个属性,一个是transactionManager,用于指定一个事务管理器;另一个是transactionAttributes,通过键值对的方式指定相应方法的事物属性,其中键值可以使用通配符。在config.xml配置文件中加入TransactionInterceptor配置: 

...
     <bean id="transactionInterceptor"
           class="org.springframework.transaction.interceptor.TransactionInterceptor">
         <property name="transactionManager" ref="transactionManager"/>
         <property name="transactionAttributes">
             <props>
                 <prop key="*">PROPAGATION_REQUIRED</prop>
             </props>
         </property>
     </bean>
     <bean id="userService"
           class="org.springframework.aop.framework.ProxyFactoryBean">
         <property name="target">
             <bean class="com.xiaofan.test.UserService" />
         </property>
         <property name="interceptorNames">
             <list>
                 <idref bean="transactionInterceptor"/>
             </list>
         </property>
     </bean>
 ...
 public class UserService {
     @Resource
     UserDAO userDAO;
     public void addUser3(User user) {
         userDAO.insert(user);
         Integer i = 1;
         if (i.equals(0)) {
         }
     }
 }

b.基于TransactionProxyFactoryBean的声明式事务

  以上基于TransactionInterceptor的方式每个服务bean都需要配置一个ProxyFactoryBean,这会导致配置文件冗长,为了缓解这个问题,Spring提供了基于TransactionProxyFactoryBean的声明式事务配置方式。在config.xml配置文件中加入TransactionProxyFactoryBean配置:

 
...
     <bean id="userService" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
         <property name="target">
             <bean class="com.xiaofan.test.UserService" />
         </property>
         <property name="transactionManager" ref="transactionManager"/>
         <property name="transactionAttributes">
             <props>
                 <prop key="insert*">PROPAGATION_REQUIRED</prop>
                 <prop key="update*">PROPAGATION_REQUIRED</prop>
                 <prop key="*">PROPAGATION_REQUIRED</prop>
             </props>
         </property>
     </bean>
 ...

UserService服务代码如上,不用变更。

c.基于命名空间的声明式事务

  Spring 2.x引入了命名空间,加上命名空间的切点表达式支持,声明式事务变的更加强大,借助于切点表达式,可以不需要为每个业务类创建一个代理。为了使用动态代理,首先需要添加pom依赖:

...
         <dependency>
             <groupId>org.aspectj</groupId>
             <artifactId>aspectjweaver</artifactId>
             <version>1.7.4</version>
         </dependency>
 ...

config.xml文件添加如下配置:

<bean id="userService" class="com.xiaofan.test.UserService">
     </bean>
     <tx:advice id="userAdvice" transaction-manager="transactionManager">
         <tx:attributes>
             <tx:method name="*" propagation="REQUIRED"/>
         </tx:attributes>
     </tx:advice>
     <aop:config>
         <!--匹配模式,匹配对应的方法,参照上面的AOP-->
         <aop:pointcut id="userPointcut" expression="execution (* com.xiaofan.test.*.*(..))"/>
         <aop:advisor advice-ref="userAdvice" pointcut-ref="userPointcut"/>
     </aop:config>

UserService服务代码如上,不用变更。

d.基于标注(@Transactional)的声明式事务

  除了基于命名空间的事务配置方式外,Spring2.x还引入了基于注解的方式,主要涉及@Transactional注解,它可以作用于接口、接口方法、类和类的方法上,当做用于类上时,该类的所有public方法都有该类型的事务属性,可被方法级事务覆盖。在config.xml配置文件中加入注解识别配置:

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

 @Transactional注解应该被应用到public方法上,这是由AOP的本质决定的,如果应用在protected、private的方法上,事务将被忽略。UserService服务代码如下:

public class UserService {
     @Resource
     UserDAO userDAO;
     @Transactional(propagation = Propagation.REQUIRED)
     public void addUser4(User user) {
         userDAO.insert(user);
         Integer i = 1;
         if (i.equals(0)) {
 ​
         }
     }
 }

@Transactional注解的完整属性信息如下表:

基于命名空间和基于注解的事务声明各有优缺点:基于命名空间的方式一个配置可以匹配多个方法,但配置较注解方式复杂;基于注解的方式需要在每个需要使用事务的方法或类上标注,但基于标注的方法学习成本更低。

3.2 编程式事务

一般的使用:

Spring配置文件config.xml如下:

<?xml version="1.0" encoding="UTF-8"?>
 <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns="http://www.springframework.org/schema/beans"
        xmlns:tx="http://www.springframework.org/schema/tx"
        xmlns:context="http://www.springframework.org/schema/context"
        xsi:schemaLocation="
             http://www.springframework.org/schema/beans
                 http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
             http://www.springframework.org/schema/tx
                 http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
             http://www.springframework.org/schema/context
                 http://www.springframework.org/schema/context/spring-context-3.0.xsd">
     <!-- 引入属性文件 -->
     <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
         <property name="locations">
             <list>
                 <value>classpath:config.properties</value>
             </list>
         </property>
     </bean>
     <!-- 配置数据源 -->
     <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
         <property name="driverClassName">
             <value>${driver}</value>
         </property>
         <property name="url">
             <value>${url}</value>
         </property>
         <property name="username">
             <value>${username}</value>
         </property>
         <property name="password">
             <value>${password}</value>
         </property>
     </bean>
 ​
     <!-- 自动扫描了所有的mapper配置文件对应的mapper接口文件 -->
     <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
         <property name="basePackage" value="com.xiaofan.test" />
     </bean>
     <!-- 配置Mybatis的文件 -->
     <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
         <property name="dataSource" ref="dataSource" />
         <property name="mapperLocations" value="classpath:user_mapper.xml"/>
         <property name="configLocation" value="classpath:mybatis_config.xml" />
     </bean>
     <!-- 配置JDBC事务管理器 -->
     <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
         <property name="dataSource" ref="dataSource" />
     </bean>
     <bean id="userService" class="com.xiaofan.test.UserService">
     </bean>
 </beans>

根据PlatformTransactionManager、TransactionDefinition和TransactionStatus三个接口,可以通过编程的方式来进行事务管理, TransactionDefinition实例用于定义一个事务,PlatformTransactionManager实例用语执行事务管理操作,TransactionStatus实例用于跟踪事务的状态。UserService服务中配置如下:

public class UserService {
     @Resource
     UserDAO userDAO;
     @Resource
     DataSource dataSource;
     @Resource
     PlatformTransactionManager transactionManager;
     public void addUser(User user) throws Exception {
         TransactionDefinition def = new DefaultTransactionDefinition();
         TransactionStatus status = transactionManager.getTransaction(def);
         try {
             // [1] 插入纪录
             userDAO.insert(user);
             // [2] 范例抛出异常
             Integer i = null;
             if (i.equals(0)) {
 ​
             }
             transactionManager.commit(status);
         } catch (Exception e) {
             transactionManager.rollback(status);
             throw e;
         }
         return;
     }
 }

Spring测试代码如下:

@ContextConfiguration(locations = {"classpath:config.xml"})
 @RunWith(SpringJUnit4ClassRunner.class)
 public class Test extends AbstractJUnit4SpringContextTests{
 ​
     @Resource
     UserService userService;
 ​
     @org.junit.Test
     public void testAdd() {
         try {
             userService.addUser(new User(null, "LiLei", 25));
         } catch (Exception e) {
         }
     }
 }

如果[2]处抛出异常,则事务执行回滚,如果[2]没有抛出异常,则提交执行纪录插入操作。

另一种编程式事务管理

以上这种事务管理方式容易理解,但事务管理代码散落在业务代码中,破坏了原有代码的条理性,且每个事务方法中都包含了启动事务、提交/回滚事务的功能,基于此,Spring提供了模板方法模式(TransactionTemplate)。

在config.xml配置文件中加入TransactionTemplate bean配置:

<bean id="transactionTemplate"  class="org.springframework.transaction.support.TransactionTemplate">
         <property name="transactionManager" ref="transactionManager"/>
</bean>

TransactionTemplate 的execute()方法有一个TransactionCallback类型的参数,该接口中定义了一个doInTransaction()方法,可通过匿名内部累的方式实现TransactionCallBack接口,将业务代码写在doInTransaction()方法中,业务代码中不需要显示调用任何事物管理API,除了异常回滚外,也可以在业务代码的任意位置通过transactionStatus.setRollbackOnly();执行回滚操作。UserService服务代码变更为:

public class UserService {
     @Resource
     UserDAO userDAO;
     @Resource
     TransactionTemplate transactionTemplate;
     public void addUser(final User user) {
         transactionTemplate.execute(new TransactionCallback() {
             public Object doInTransaction(TransactionStatus transactionStatus) {
                 userDAO.insert(user);
                 // transactionStatus.setRollbackOnly();
                 Integer i = null;
                 if (i.equals(0)) {
 ​
                 }
                 return null;
             }
         });
     }
 }

实际场景下,我们一般使用 Spring Boot + 注解的声明式事务。参照 《Spring Boot 事务注解详解》 。

另外,也推荐看看 《Spring 事务管理 - 编程式事务、声明式事务》 一文。

4、事务管理接口

  • PlatformTransactionManager: (平台)事务管理器

  • TransactionDefinition: 事务定义信息(事务隔离级别、传播行为、超时、只读、回滚规则)

  • TransactionStatus: 事务运行状态

所谓事务管理,其实就是“按照给定的事务规则来执行提交或者回滚操作”。

4.1 Spring 事务如何和不同的数据持久层框架做集成

Spring并不直接管理事务,而是提供了多种事务管理器 ,他们将事务管理的职责委托给Hibernate或者JTA等持久化机制所提供的相关平台框架的事务来实现。 Spring事务管理器的接口是: org.springframework.transaction.PlatformTransactionManager ,通过这个接口,Spring为各个平台如JDBC、Hibernate等都提供了对应的事务管理器,但是具体的实现就是各个平台自己的事情了。

4.2 PlatformTransactionManager接口代码如下:

PlatformTransactionManager接口中定义了三个方法:

// PlatformTransactionManager.java
 ​
 public interface PlatformTransactionManager {
 ​
     // 根据事务定义 TransactionDefinition ,获得 TransactionStatus 。根据指定的传播行为,返回当前活动的事务或创建一个新事务。 
     TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException;
     // 根据情况,提交事务,使用事务目前的状态提交事务
     void commit(TransactionStatus status) throws TransactionException;
     // 根据情况,回滚事务,对执行的事务进行回滚
     void rollback(TransactionStatus status) throws TransactionException; 
 }
  • PlatformTransactionManager 是负责事务管理的接口,一共有三个接口方法,分别负责事务的获得、提交、回滚。

  • getTransaction(TransactionDefinition definition)方法,根据事务定义 TransactionDefinition ,获得 TransactionStatus 。

    • 为什么不是创建事务呢?因为如果当前如果已经有事务,则不会进行创建,一般来说会跟当前线程进行绑定。如果不存在事务,则进行创建。

    • 为什么返回的是 TransactionStatus 对象?在 TransactionStatus 中,不仅仅包含事务属性,还包含事务的其它信息,例如是否只读、是否为新创建的事务等等。

  • commit(TransactionStatus status)方法,根据 TransactionStatus 情况,提交事务。

    • 为什么根据 TransactionStatus 情况,进行提交?例如说,带@Transactional注解的的 A 方法,会调用

      @Transactional注解的的 B 方法。

      • 在 B 方法结束调用后,会执行 PlatformTransactionManager#commit(TransactionStatus status) 方法,此处事务是不能、也不会提交的。

      • 而是在 A 方法结束调用后,执行 PlatformTransactionManager#commit(TransactionStatus status) 方法,提交事务。

  • rollback(TransactionStatus status)方法,根据 TransactionStatus 情况,回滚事务。

    • 为什么根据 TransactionStatus 情况,进行回滚?原因同 commit(TransactionStatus status) 方法。

Spring中PlatformTransactionManager根据不同持久层框架所对应的接口实现类,几个比较常见的如下图所示

org.springframework.transaction.support.AbstractPlatformTransactionManager ,基于 模板方法模式 ,实现事务整体逻辑的骨架,而抽象 doCommit(DefaultTransactionStatus status)、doRollback(DefaultTransactionStatus status) 等等方法,交由子类类来实现。

④ 最后,不同的数据持久层框架,会有其对应的 PlatformTransactionManager 实现类,如下图所示:

  • 所有的实现类,都基于 AbstractPlatformTransactionManager 这个骨架类。

  • HibernateTransactionManager ,和 Hibernate5 的事务管理做集成。

  • DataSourceTransactionManager ,和 JDBC 的事务管理做集成。所以,它也适用于 MyBatis、Spring JDBC 等等。

  • JpaTransactionManager ,和 JPA 的事务管理做集成。

如下,是一个比较常见的 使用JDBC或者iBatis(就是Mybatis)进行数据持久化操作的XML 方式来配置的事务管理器,使用的是 DataSourceTransactionManager 。代码如下:

<!-- 事务管理器 -->
 <bean id="transactionManager"
 class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
     <!-- 数据源 -->
     <property name="dataSource" ref="dataSource" />
 </bean>

4.3 TransactionDefinition接口介绍

事务管理器接口 PlatformTransactionManager 通过 getTransaction(TransactionDefinition definition) 方法来得到一个事务,这个方法里面的参数是 TransactionDefinition类 ,这个类就定义了一些基本的事务属性。

事务属性

事务属性可以理解成事务的一些基本配置,描述了事务策略如何应用到方法上。事务属性包含了5个方面。

TransactionDefinition接口中的方法如下:

TransactionDefinition接口中定义了5个方法以及一些表示事务属性的常量比如隔离级别、传播行为等等的常量。

下面只是列出了TransactionDefinition接口中的方法及常量隔离如下:

public interface TransactionDefinition {
     // 返回事务的传播行为
     int getPropagationBehavior(); 
     // 返回事务的隔离级别,事务管理器根据它来控制另外一个事务可以看到本事务内的哪些数据
     int getIsolationLevel(); 
     String getName();    //返回事务的名字
     int getTimeout();      // 返回事务必须在多少秒内完成
     boolean isReadOnly();    // 返回是否优化为只读事务。
 /**
  * 【Spring 独有】使用后端数据库默认的隔离级别
  * MySQL 默认采用的 REPEATABLE_READ隔离级别
  * Oracle 默认采用的 READ_COMMITTED隔离级别
  */
     int ISOLATION_DEFAULT = -1;
 ​
 /**
  * 最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读
  */
     int ISOLATION_READ_UNCOMMITTED = Connection.TRANSACTION_READ_UNCOMMITTED;
 /**
  * 允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生
  */
     int ISOLATION_READ_COMMITTED = Connection.TRANSACTION_READ_COMMITTED;
 /**
  * 对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。
  */
     int ISOLATION_REPEATABLE_READ = Connection.TRANSACTION_REPEATABLE_READ;
 /**
  * 最高的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。
  * 但是这将严重影响程序的性能。通常情况下也不会用到该级别。
  */
     int ISOLATION_SERIALIZABLE = Connection.TRANSACTION_SERIALIZABLE;
     // ========== 支持当前事务的情况 ========== 
 /**
  * 如果当前存在事务,则使用该事务。
  * 如果当前没有事务,则创建一个新的事务。
  */
     int PROPAGATION_REQUIRED = 0;
 /**
  * 如果当前存在事务,则使用该事务。
  * 如果当前没有事务,则以非事务的方式继续运行。
  */
     int PROPAGATION_SUPPORTS = 1;
 /**
  * 如果当前存在事务,则使用该事务。
  * 如果当前没有事务,则抛出异常。
  */
     int PROPAGATION_MANDATORY = 2;
 ​
 // ========== 不支持当前事务的情况 ========== 
 /**
  * 创建一个新的事务。
  * 如果当前存在事务,则把当前事务挂起。
  */
     int PROPAGATION_REQUIRES_NEW = 3;
 /**
  * 以非事务方式运行。
  * 如果当前存在事务,则把当前事务挂起。
  */
     int PROPAGATION_NOT_SUPPORTED = 4;
 /**
  * 以非事务方式运行。
  * 如果当前存在事务,则抛出异常。
  */
     int PROPAGATION_NEVER = 5;
 ​
 // ========== 其他情况 ========== 
 /**
  * 如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行。
  * 如果当前没有事务,则等价于 {@link TransactionDefinition#PROPAGATION_REQUIRED}
  */
     int PROPAGATION_NESTED = 6;
 } 

(1)事务隔离级别(定义了一个事务可能受其他并发事务影响的程度):

并发事务带来的问题

在典型的应用程序中,多个事务并发运行,经常会操作相同的数据来完成各自的任务(多个用户对统一数据进行操作)。并发虽然是必须的,但可能会导致一下的问题。

  • 脏读(Dirty read): 当一个事务正在访问数据并且对数据进行了修改,而这种修改还没有提交到数据库中,这时另外一个事务也访问了这个数据,然后使用了这个数据。因为这个数据是还没有提交的数据,那么另外一个事务读到的这个数据是“脏数据”,依据“脏数据”所做的操作可能是不正确的。

  • 丢失修改(Lost to modify): 指在一个事务读取一个数据时,另外一个事务也访问了该数据,那么在第一个事务中修改了这个数据后,第二个事务也修改了这个数据。这样第一个事务内的修改结果就被丢失,因此称为丢失修改。

    • 例如:事务1读取某表中的数据A=20,事务2也读取A=20,事务1修改A=A-1,事务2也修改A=A-1,最终结果A=19,事务1的修改被丢失。

  • 不可重复读(Unrepeatableread): 指在一个事务内多次读同一数据。在这个事务还没有结束时,另一个事务也访问该数据。那么,在第一个事务中的两次读数据之间,由于第二个事务的修改导致第一个事务两次读取的数据可能不太一样。这就发生了在一个事务内两次读到的数据是不一样的情况,因此称为不可重复读。

  • 幻读(Phantom read): 幻读与不可重复读类似。它发生在一个事务(T1)读取了几行数据,接着另一个并发事务(T2)插入了一些数据时。在随后的查询中,第一个事务(T1)就会发现多了一些原本不存在的记录,就好像发生了幻觉一样,所以称为幻读。

不可重复度和幻读区别:

不可重复读的重点是修改,幻读的重点在于新增或者删除。

例1(同样的条件, 你读取过的数据, 再次读取出来发现值不一样了 ):事务1中的A先生读取自己的工资为 1000的操作还没完成,事务2中的B先生就修改了A的工资为2000,导致A再读自己的工资时工资变为 2000;这就是不可重复读。

例2(同样的条件, 第1次和第2次读出来的记录数不一样 ):假某工资单表中工资大于3000的有4人,事务1读取了所有工资大于3000的人,共查到4条记录,这时事务2 又插入了一条工资大于3000的记录,事务1再次读取时查到的记录就变为了5条,这样就导致了幻读。

隔离级别

TransactionDefinition 接口中定义了五个表示隔离级别的常量:

  • TransactionDefinition.ISOLATION_DEFAULT: 使用后端数据库默认的隔离级别,Mysql 默认采用的 REPEATABLE_READ隔离级别,Oracle 默认采用的 READ_COMMITTED隔离级别.

  • TransactionDefinition.ISOLATION_READ_UNCOMMITTED: 最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读

  • TransactionDefinition.ISOLATION_READ_COMMITTED: 允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生

  • TransactionDefinition.ISOLATION_REPEATABLE_READ: 对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。

  • TransactionDefinition.ISOLATION_SERIALIZABLE: 最高的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。

(2)事务传播行为(为了解决业务层方法之间互相调用的事务问题):

当事务方法被另一个事务方法调用时,必须指定事务应该如何传播。例如:方法可能继续在现有事务中运行,也可能开启一个新事务,并在自己的事务中运行。在TransactionDefinition定义中包括了如下几个表示传播行为的常量:

支持当前事务的情况:

  • TransactionDefinition.PROPAGATION_REQUIRED: 如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。

  • TransactionDefinition.PROPAGATION_SUPPORTS: 如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。

  • TransactionDefinition.PROPAGATION_MANDATORY: 如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。

不支持当前事务的情况:

  • TransactionDefinition.PROPAGATION_REQUIRES_NEW: 创建一个新的事务,如果当前存在事务,则把当前事务挂起。

  • TransactionDefinition.PROPAGATION_NOT_SUPPORTED: 以非事务方式运行,如果当前存在事务,则把当前事务挂起。

  • TransactionDefinition.PROPAGATION_NEVER: 以非事务方式运行,如果当前存在事务,则抛出异常。 其他情况:

  • TransactionDefinition.PROPAGATION_NESTED: 如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于TransactionDefinition.PROPAGATION_REQUIRED。

这里需要指出的是,前面的六种事务传播行为是 Spring 从 EJB 中引入的,他们共享相同的概念。而 PROPAGATION_NESTED 是 Spring 所特有的。以 PROPAGATION_NESTED 启动的事务内嵌于外部事务中(如果存在外部事务的话),此时,内嵌事务并不是一个独立的事务,它依赖于外部事务的存在,只有通过外部的事务提交,才能引起内部事务的提交,嵌套的子事务不能单独提交。

类似于 JDBC 中的保存点(SavePoint)的概念,其实嵌套的子事务就是保存点的一个应用,一个事务中可以包括多个保存点,每一个嵌套子事务。另外,外部事务的回滚也会导致嵌套子事务的回滚。

(3) 事务超时属性(一个事务允许执行的最长时间)

所谓事务超时,就是指一个事务所允许执行的最长时间,如果超过该时间限制但事务还没有完成,则自动回滚事务。在 TransactionDefinition 中以 int 的值来表示超时时间,其单位是秒。

(4) 事务只读属性(对事物资源是否执行只读操作)

事务的只读属性是指,对事务性资源进行只读操作或者是读写操作。所谓事务性资源就是指那些被事务管理的资源,比如数据源、 JMS 资源,以及自定义的事务性资源等等。如果确定只对事务性资源进行只读操作,那么我们可以将事务标志为只读的,以提高事务处理的性能。在 TransactionDefinition 中以 boolean 类型来表示该事务是否只读。

(5) 回滚规则(定义事务回滚规则)

这些规则定义了哪些异常会导致事务回滚而哪些不会。默认情况下,事务只有遇到运行期异常时才会回滚,而在遇到检查型异常时不会回滚(这一行为与EJB的回滚行为是一致的)。 ​ 但是你可以声明事务在遇到特定的检查型异常时像遇到运行期异常那样回滚。同样,你还可以声明事务遇到特定的异常不回滚,即使这些异常是运行期异常。

4.4 TransactionStatus接口介绍

TransactionStatus接口用来记录事务的状态 该接口定义了一组方法,用来获取或判断事务的相应状态信息。

PlatformTransactionManager.getTransaction(…) 方法返回一个 TransactionStatus 对象。返回的TransactionStatus 对象可能代表一个新的或已经存在的事务(如果在当前调用堆栈有一个符合条件的事务)。

TransactionStatus接口接口内容如下:

public interface TransactionStatus{
     boolean isNewTransaction(); // 是否是新的事物
     boolean hasSavepoint(); // 是否有恢复点,在 {@link TransactionDefinition#PROPAGATION_NESTED} 传播级别使用。
     void setRollbackOnly();  // 设置为只回滚
     boolean isRollbackOnly(); // 是否为只回滚
     boolean isCompleted; // 是否已完成
 } 
  • 为什么没有事务对象呢?在 TransactionStatus 的实现类 DefaultTransactionStatus 中,有个 Object transaction 属性,表示事务对象。

  • isNewTransaction() 方法,表示是否是新创建的事务。作用主要参照上面的 commit(TransactionStatus status) 方法的解释。通过该方法,我们可以判断,当前事务是否当前方法所创建的,只有创建事务的方法,才能且应该真正的提交事务。

 

参照: 可能是最漂亮的Spring事务管理详解

芋道源码

GEE:基于自定义的年度时序数据集进行LandTrendr变化检测 本文介绍了使用年度时序数据进行LandTrendr变化检测的方法,包括核心函数调用、参数设置和结果可视化。通过筛选参数(年份、变化幅度和持续时间)对结果进行过滤,输出变化年份、变化幅度和持续时间。代码提供了完整的处理流程,包括数据输入、LandTrendr算法运行、结果筛选与可视化,并支持结果导出。适用于基于Google Earth Engine平台的地表变化检测分析。 阅读详情

相关推荐

CAN信号定义避坑指南:Kvaser Database Editor里Byteorder和Bitpos设置的那些‘坑’

本文详细解析了在Kvaser Database Editor中配置CAN信号时,字节序(Byteorder)和起始位(Bitpos)设置的常见错误及解决方案。通过实际案例和验证技巧,帮助工程师避免DBC文件配置中的陷阱,确保车载电子系统的稳定通信。

weixin_28678831的博客 360

深入理解 Spring 事务:入门、使用、原理

Spring 事务是复杂一致性业务必备的知识点,掌握好 Spring 事务可以让我们写出更好地代码。这篇文章我们将介绍 Spring 事务的诞生背景,从而让我们可以更清晰地了解 Spring 事务存在的意义。接着,我们会介绍如何快速使用 Spring 事务。接着,我们会介绍 Spring 事务的一些特性,从而帮助我们更好地使用 Spring 事务。最后,我们会总结一些 Spring 事务常见的问题,避免大家踩坑。Spring 事务 - 思维导图。

Candyz7的博客 708

线性分类器(Linear Classifier)

线性分类器 如上图所示,这是二维空间中的一个数据集,如果他正好能够被一条直线分成两类,那么我们称它为线性可分数据集,这条直线就是一个线性分类器。 在三维空间中,如果数据集线性可分,是指能够被一个平面分为两类。 在一维空间中,所有的点都在一条直线上,如果线性可分。可以理解为它们能够被一个点分开。 这里的直线、平面、点被分为决策边界。 一个 m 维空间中的数据集,如果能够被一个超平面一分为二,那么这个数据集就是线性可分的,这个超平面就是决策边界。 例如,这是二维平面上的一条直线, 它可以把平面切分成两

xuechanba的博客 1万+

Spring入门(五)---- Spring中的事务控制

五、Spring中的事务控制 为什么需要事务? 事务是对一系列的数据库操作(比如插入多条数据)进行统一的提交或回滚操作,如果插入成功,那么一起成功,如果中间有一条出现异常,那么回滚之前的所有操作,这样可以防止在脏数据,方式数据库出现问题。 事务的四个特性(ACID) 原子性(Atomicity):事务是一个原子操作,由一系列动作组成。事务的原子性确保动作要么全部完成,要么完全不起作用。...

Simon郎的博客 380

深入解析SSD报错“READ FPDMA QUEUED”:从诊断到修复全流程

本文深入解析了SSD报错“READ FPDMA QUEUED”的含义、成因与全流程解决方案。该错误通常指示硬盘硬件或健康状态问题。文章详细介绍了如何通过系统日志定位错误、解读关键的S.M.A.R.T.健康报告(重点关注重分配扇区计数等指标),并逐步进行硬件排查(如更换SATA数据线)、软件修复与数据抢救,最终指导用户根据诊断结果做出维修或更换SSD的决策。

weixin_29233333的博客 395

多目标跟踪(MOT)中的卡尔曼滤波(Kalman filter)和匈牙利(Hungarian)算法详解

多目标跟踪(MOT)中的卡尔曼滤波(Kalman filter)和匈牙利(Hungarian)算法详解 1. 概览 在开始具体讨论卡尔曼滤波和匈牙利算法之前,首先我们来看一下基于检测的目标跟踪算法的大致流程。 2. 卡尔曼滤波(Kalman filter) 目标跟踪中使用的就是最基础的 Kalman filter 算法。这里也仅仅讨论最基础的 Kalman filter 算法。 卡尔曼滤波算法的过程很简单,如下图所示。最核心的两个步骤就是预测和更新(下图的 correct)。 在目标跟踪任务中,目标的

生命在于折腾! 2万+

Spring声明式事务管理(下)

三.用BeanNameAutoProxyCreator自动创建事务代理 下面介绍一种优秀的事务代理配置策略:采用这种配置策略,完全可以避免增量式配置,所有的事务代理由系统自动创建。容器中的目标bean自动消失,避免需要使用嵌套bean来保证目标bean不可被访问。这种配置方式依赖于Spring提供的bean后处理器,该后处理器用于为每个bean自动创建代理,此处的代理不仅可以是事务代理,也可...

六月 185

R语言:基于Spatstat包的单变量和双变量平面Ripley‘s K函数分析

因为网上查找得到的R语言K函数分析的资料很少,Spatstat包的介绍也很少,所以抛砖引玉。本文简单介绍了使用R语言spatstat包的Kest,Kcross(Lcross)和Kinhom方法进行了单变量和双变量平面Ripley's K函数分析的方法及代码,希望有所帮助。

hsdcmax的博客 1万+

配置DAO代理 一个小错误

在配置DAO代理的时候   &lt;!-- 定义DAO代理 --&gt; &lt;bean id="addressDAOProxy"    class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"&gt;  &lt;property name="transactionManager"&gt; ..

张 作强 BLOG 245

基于Linux的PCIe设备驱动开发入门到精通-- 11.2 锁机制与并发控制 (自旋锁、互斥锁) 11.3 性能瓶颈分析与优化建议

本文探讨Linux驱动开发中的性能优化方法论,重点聚焦并发控制与性能瓶颈分析。从锁机制选择(自旋锁、互斥锁等)到工具使用(ftrace、perf),详细介绍了定位锁竞争和CPU热点的实战步骤,包括ftrace事件跟踪和perf火焰图分析。针对常见性能瓶颈(CPU/内存/I/O/锁竞争),提出了锁粒度优化、无锁结构替换、中断处理优化等解决方案。强调性能优化需要理论结合实践,通过"假设-测量-验证"的循环持续迭代。为开发者提供了一套从问题定位到解决的完整方法论,助力开发高性能工业级驱动。

MHD0815的博客 125

当C#遇见声音魔法:从麦克风到文字的0.1秒奇幻漂流

为什么选300Hz?因为人声基频通常在85-255Hz,但清脆的“啊”可能到2kHz,所以300Hz是安全区!(参考知识库[1])

墨夶的博客 365

如何在Spring Boot中整合持久层框架

在现代软件开发中,数据持久化是一个核心需求。Spring Boot作为一个流行的Java基础框架,提供了一个非常便捷的环境来整合各种持久层框架,如JPA(Java Persistence API)、Hibernate、MyBatis等。本文将指导你如何在Spring Boot项目中整合持久层框架,以实现数据的高效管理和访问。

zzzzltai的博客 618

【LSTM回归预测】attention机制LSTM时间序列回归预测【含Matlab源码 1992期】

attention机制LSTM时间序列回归预测 完整的代码,方可运行;可提供运行操作视频!适合小白!

订阅付费专栏Matlab(奶茶价版),可赠送奶茶价版付费专栏指定代码1份; 2591

Spring 的事务了解吗?

事务是逻辑上的一组操作,要么都执行,要么都不执行。在 MySQL 数据库中只有 InnoDB 引擎才支持事务。事务属性包含了 5 个方面1)隔离级别2)传播行为3)回滚规则4)是否只读5)事务超时。

bxy0806的博客 1042

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

Spring事务基础了解

目录前言一、阅读本文需要的基础知识二、两个不靠谱直觉的例子2.1 第一个例子2.2 第二个例子三、Spring事务传播机制四、多线程问题五、什么是BPP?六、认识Spring事务几个重要的接口最后 前言 Spring事务管理我相信大家都用得很多,但可能仅仅局限于一个@Transactional注解或者在XML中配置事务相关的东西。不管怎么说,日常可能足够我们去用了。但作为程序员,无论是为了面试还是说更好把控自己写的代码,还是应该得多多了解一下Spring事务的一些细节。 这里我抛出几个问题,看大家能不能瞬间

心安成长的码字书房 282

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

Spring事务了解

本文将按照声明式事务的五个特性进行介绍: 事务传播机制 事务隔离机制 只读 事务超时 回滚规则 Spring事务传播机制 事务的特性 原子性(Atomicity):事务是一个原子操作,由一系列动作组成。事务的原子性确保动作要么全部完成,要么完全不起作用。 一致性(Consistency):一旦事务完成(不管成功还是失败),系统必须确保它所建模的业务处于一致的状态,而不会是部分完成部分失败。在现实中的数据不应该被破坏。 隔离性(Isolation):可能有许多事务会同时处理相同的数据,因此每个事务都应该

qq_26866883的博客 235

简单了解Spring事务

spring声明式事务

weixin_43462126的博客 1851

Spring事务需要了解哪些

Spring的事务 Spring的事务分为,声明式事务管理、编程式事务管理两种类型.由三大接口组成:PlatformTransactionManager(事务管理器)、TransactionDefinition(事务定义)、TransactionStatus(事务状态)。不同的事务管理器会对其进行不同的实现。 声明式事务管理 声明式的事务是无侵入式的,基于AOP,本质来说是对于一个方法执行前创建事务,方法执行后提交或者回滚。由于是基于方法级别的,所以声明式事务无法进行更好的细粒度,比如代码块的事务管理

bamboo 225

了解Spring事务

一、事务概念(transaction) 指要做的或所做的事情。指访问并可能更新数据库中各种数据项的一个程序执行单元。 在关系数据库中,一个事务可以是一条SQL语句、一组SQL语句或者整个程序。 事务通常由高级数据库操纵语言/编程语言书写的用户程序的执行所引起,由事务开始(begin transaction)和事务结束(end transaction)之间执行的全体操作组成。 二、特性 事务是恢复和并发控制的基本单位 4个属性ACID 原子性:atomicity。一个事务是一个不可分割的工作单位,要么都做、

Fiona20的博客 3159

我所了解的Spring 事务原理

一、事务的基本原理 Spring事务的本质其实就是数据库对事务的支持,没有数据库的事务支持,spring是无法提供事务功能的。对于纯JDBC操作数据库,想要用到事务,可以按照以下步骤进行: 获取连接 Connection con = DriverManager.getConnection() 开启事务con.setAutoCommit(true/false); 执行CRUD 提交事务/回滚事务 con.commit() / con.rollback(); 关闭连接 conn.close(); 使

weixin_43743125的博客 1021

spring事务,你真的了解了

spring七个事务传播属性: • 1.PROPAGATION_REQUIRED – 支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。 • 2.PROPAGATION_SUPPORTS – 支持当前事务,如果当前没有事务,就以非事务方式执行。 • 3.PROPAGATION_MANDATORY – 支持当前事务,如果当前没有事务,就抛出异常。 • 4.PROPAGATION_REQUIRES_NEW – 新建事务,如果当前存在事务,把当前事务挂起。 • 5.PROPAGATION_NOT.

码上代码的博客 3178

在Spring中了解事务注释

1.简介 Spring为程序性和声明性事务提供支持。 1.1程序化交易 对于程序性事务,需要显式编写事务管理代码,以便在一切成功后提交,并在出现问题时回滚。 在这种情况下,事务管理代码与业务逻辑紧密绑定。 1.2声明式交易 声明式事务将事务管理代码与业务逻辑分开。 Spring通过Spring上下文中的XML配置或@Transactional注释,使用事务建议(使用AOP)来...

最佳 Java 编程 183

spring 事务原理_[Spring] 深入了解事务原理

Spring事务的基本原理Spring事务的本质其实就是数据库对事务的支持,没有数据库的事务支持,spring是无法提供事务功能的。对于纯JDBC操作数据库,想要用到事务,可以按照以下步骤进行:获取连接 Connection con = DriverManager.getConnection()开启事务con.setAutoCommit(true/false);执行CRUD提交事务/回滚事务 co...

weixin_39559079的博客 145

一文了解Spring事务

Spring事务 事务基础知识 什么是事务? 事务是逻辑上的一组操作,要么都执行,要么都不执行。 事务的特性(ACID) 原子性(Atomicity) 事务是最小的执行单位,不允许分割。事务的原子性动作要么全部完成,要么完全不起作用。 一致性(Consistency) 事务必须使数据库从一个一致性状态变换为另一个一致性状态。 一致性是指数据处于一种语义上的有意义且正确的状态。一致性是对数据可见性的约束,保证在一个事务中的多次操作的数据中间状态对其他事务不可见的。因为这些中间状态,是一个过

wenwen1203的博客 345

Spring事务解读,一文让你彻底了解事务

本文主要包括事务简介、如何使用、事务传播机制、事务失效场景、以及事务常见的异常分析。让你一文读懂事务。

笑小枫 1037

一文了解spring事务特性

spring事务介绍,涉及事务隔离级别,事务传播,脏读,不可重复读,幻读的演示,以及事务失效的场景

qq_44462054的博客 671

你有认真了解过spring的事务吗?

事物传播行为介绍: 1 @Transactional(propagation=Propagation.REQUIRED) 如果有事务, 那么加入事务, 没有的话新建一个(默认情况下) 2 @Transactional(propagation=Propagation.NOT_SUPPORTED) 容器不为这个方法开启事务 3 @Transactional(propagation=Propaga...

当时只道是平常 528
上一篇: 深入了解Spring之AOP
下一篇: SpringMVC相关注解
striveb
博客等级 码龄10年 242粉丝 117原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值