事物

Posted by 麦子 on Sunday, 2020年06月07日

[TOC]

spring事物

转载地址:https://blog.csdn.net/T2080305/article/details/82662650

概念

首先程序向数据库获得Connection连接,默认情况下,这个连接是默认开启事物提交的,即执行完一条更新sql就向数据库提交一次事物。如果想多条更新sql语句处于同一个事物之中,即所有的更新sql语句执行完成,最后再向数据库提交事物,那么我们需要手动的关闭数据库的自动开启事物提交属性。

  1. 手动关闭数据库的自动开启提交功能

  2. Connection.setAutoCommit(false)
    
  3. 提交事物

  4. Connection.commit()
    
  5. 回滚事物

  6. Connection.rollback()
    

传统jdbc对事物的处理,如果我们有多个方法需要做事物处理,那么代码中就会包含大量的上面重复代码,导致代码的冗余,也给代码的维护带来了很大的问题。有了spring之后,我们就不用再去写那些底层的代码(获取连接,事物提交,事物回滚,连接释放)。其实spring 并不是直接管理事物,而是提供了多种事物管理器,真正管理事物的任务则是交给了Jpa或者Hibernate等持久化框架的事物处理器。

spring 中对事物的处理

20180913102727109

从上面的图中,可以看到spring提供了一个spring-tx依赖包,这个包主要提供了事物的处理,并且提供了一个核心接口,PlatformTransactionManager,这个接口提供了三个核心的方法,根据指定的传播行为返回当前活动的事务或创建一个新的事务getTransaction(其中的参数是TransactionDefinition),事物的提交commit,事物的回滚rollback。

Spring中的7个事务传播行为

20180913104140880

上图中的TransactionDefinition定义了事物的传播行为和隔离级别,除了这两个属性,还提供了几个方法。

int getPropagationBehavior(); //返回当前事物的传播行为
int getIsolationLevel(); //返回当前事物的隔离级别
int getTimeout(); //返回当前事物必须在多少秒内完成
boolean isReadOnly(); //返回当前事物是否是只读,事物管理器可以根据这个值进行优化,确保事物是只读的
String getName(); //返回当前事物的名称
事务行为 说明
PROPAGATION_REQUIRED 支持当前事务,假设当前没有事务。就新建一个事务(这是最常见的选择,也是Spring默认的事务的传播。)
PROPAGATION_SUPPORTS 支持当前事务,假设当前没有事务,就以非事务方式运行
PROPAGATION_MANDATORY 支持当前事务,假设当前没有事务,就抛出异常
PROPAGATION_REQUIRES_NEW 新建事务,假设当前存在事务。把当前事务挂起
PROPAGATION_NOT_SUPPORTED 以非事务方式运行操作。假设当前存在事务,就把当前事务挂起
PROPAGATION_NEVER 以非事务方式运行,假设当前存在事务,则抛出异常
PROPAGATION_NESTED 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。

编程式事物管理和声明式事物管理

spring中支持的事物管理:spring支持的事物管理有编程式事物管理和声明式事物管理

编程式事物管理:就是在具体的业务代码中嵌入事物管理的代码,也就是说在每个需要处理事物管理的业务代码中都必须额外添加事物管理的代码,整个代码显得很冗余。

声明式事物管理:它将事务管理代码从业务方法中剥离开来,以声明的方式来实现事务管理的功能。事务管理作为一种横切关注点,可以通过AOP方法模块化。Spring通过Spring AOP框架支持声明式事务管理。

其实spring 并不是直接管理事物,而是提供了多种事物管理器,真正管理事物的任务则是交给了Jpa或者Hibernate等持久化框架的事物处理器

Spring提供了许多内置事务管理器实现(这里只列举几个常见常用的):

  1. DataSourceTransactionManager:位于org.springframework.jdbc.datasource包中,数据源事务管理器,提供对单个javax.sql.DataSource事务管理,用于Spring JDBC抽象框架、iBATIS或MyBatis框架的事务管理

  2. JpaTransactionManager:位于org.springframework.orm.jpa包中,提供对单个javax.persistence.EntityManagerFactory事务支持,用于集成JPA实现框架时的事务管理

  3. HibernateTransactionManager:位于org.springframework.orm.hibernate3包中,提供对单个org.hibernate.SessionFactory事务支持,用于集成Hibernate框架时的事务管理;该事务管理器只支持Hibernate3+版本,且Spring3.0+版本只支持Hibernate 3.2+版本

  4. JtaTransactionManager:位于org.springframework.transaction.jta包中,提供对分布式事务管理的支持,并将事务管理委托给Java EE应用服务器事务管理器

spring中定义事物管理器

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> 
   <property name="dataSource" ref="dataSource" /> 
</bean> //这里是声明jdbc的事物管理器

<bean name="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
    <property name="url" value="${jdbc.url}" />
    <property name="username" value="${jdbc.username}" />
    <property name="password" value="${jdbc.password}" />
    <!-- 初始化连接大小 -->
    <property name="initialSize" value="${jdbc.initialSize}" />
    <!-- 连接池最大使用连接数量 -->
    <property name="maxActive" value="${jdbc.maxActive}" />
    <!-- 连接池最小空闲 -->
    <property name="minIdle" value="${jdbc.minIdle}" />
    <!-- 获取连接最大等待时间 -->
    <property name="maxWait" value="${jdbc.maxWait}" />
    <!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
    <property name="timeBetweenEvictionRunsMillis" value="${jdbc.timeBetweenEvictionRunsMillis}" />
    <!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
    <property name="minEvictableIdleTimeMillis" value="${jdbc.minEvictableIdleTimeMillis}" />
    <property name="testWhileIdle" value="${jdbc.testWhileIdle}" />
    <property name="testOnBorrow" value="${jdbc.testOnBorrow}" />
    <property name="testOnReturn" value="${jdbc.testOnReturn}" />
</bean> //这里是声明了jdbc的数据源
<!-- 使用annotation注解方式配置事务 当注释中发现@Transactional时,使用id为transactionManager的事务管理器-->
<!-- 如果没有设置transaction-manager的值,则spring以缺省默认的事务管理器来处理事务,默认事务管理器为第一个加载的事务管理器 -->
<tx:annotation-driven transaction-manager="transactionManager"/>


<!-- spring和MyBatis完美整合,不需要mybatis的配置映射文件 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <property name="configLocation" value="classpath:jdbc/mybatis-config.xml" />
    <!-- 自动扫描各个dao下面的Mapper.xml文件 -->
    <property name="mapperLocations">
        <array>
            <value>classpath*:user.map/*.xml</value>
            <value>classpath*:log.map/*.xml</value>
        </array>
    </property>
</bean>

<!-- mybatis 映射dao 和 mybatis sql id ,由于这里使用到了MapperScanner,所以dao不要使用注解扫描-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    <!-- 使用,号配置多个dao -->
    <!--<property name="basePackage" value="com.peop.user.dao,com.peop.question.dao,com.peop.exam.dao" />-->
    <property name="basePackage" value="com.ctp.ghub.dao" />
    <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
</bean>

MyBatis自动参与到spring事务管理中,无需额外配置,只要org.mybatis.spring.SqlSessionFactoryBean引用的数据源与DataSourceTransactionManager引用的数据源一致即可,否则事务管理会不起作用。

通过dataSource属性指定需要事务管理的单个javax.sql.DataSource对象。在幕后DataSourceTransactionManager通过调用java.sql.Connection来管理事务,而后者是通过DataSource获取到的。通过调用连接的commit()方法来提交事务。同样,事务失败时通过调用rollback()方法进行回滚。

注解的方式

// 如果有事务, 那么加入事务, 没有的话新建一个(默认情况下)
@Transactional(propagation=Propagation.REQUIRED)

// 容器不为这个方法开启事务
@Transactional(propagation=Propagation.NOT_SUPPORTED)

// 不管是否存在事务,都创建一个新的事务,原来的挂起,新的执行完毕,继续执行老的事务
@Transactional(propagation=Propagation.REQUIRES_NEW)

// 必须在一个已有的事务中执行,否则抛出异常
@Transactional(propagation=Propagation.MANDATORY)

// 必须在一个没有的事务中执行,否则抛出异常(与Propagation.MANDATORY相反)
@Transactional(propagation=Propagation.NEVER)

// 如果其他bean调用这个方法,在其他bean中声明事务,那就用事务.如果其他bean没有声明事务,那就不用事务.
@Transactional(propagation=Propagation.SUPPORTS)

配置文件的方式

<tx:advice id="txAdvice" transaction-manager="txManager"> 
      <tx:attributes>  
      <!--设置所有匹配的方法,然后设置传播级别和事务隔离-->
           <tx:method name="save*" propagation="REQUIRED" /> 
           <tx:method name="add*" propagation="REQUIRED" /> 
           <tx:method name="create*" propagation="REQUIRED" /> 
           <tx:method name="insert*" propagation="REQUIRED" /> 
           <tx:method name="update*" propagation="REQUIRED" /> 
           <tx:method name="merge*" propagation="REQUIRED" /> 
           <tx:method name="del*" propagation="REQUIRED" /> 
           <tx:method name="remove*" propagation="REQUIRED" /> 
           <tx:method name="put*" propagation="REQUIRED" /> 
           <tx:method name="get*" propagation="SUPPORTS" read-only="true" /> 
           <tx:method name="count*" propagation="SUPPORTS" read-only="true" /> 
          <tx:method name="find*" propagation="SUPPORTS" read-only="true" /> 
          <tx:method name="list*" propagation="SUPPORTS" read-only="true" /> 
          <tx:method name="*" propagation="SUPPORTS" read-only="true" /> 
     </tx:attributes> 
</tx:advice> 

#redis事物管理 redis通过mulit,exec,watch等命令来实现事物功能,他将多个命令请求打包,然后一次性按顺序去执行,注意事物执行期间,服务器不会中断事物而去执行其他客户端请求命令,要等事物中的所有命令执行完毕后,才去执行其他客户端的请求命令。

#事物开启
#执行 mulit命令
.....................//你操作的命令放入队列
#执行提交事物 exec

MongoDB事物

mongodb 的事务是依靠 mongodb 连接的客户端 session 实现,事务执行的流程大致是 建立 session,通过 session startTransaction 启动事务,如果一系列事务都完成,那么 commitTransaction 完成事务操作,并结束当前事务 session;如果一系列事务中有任意事件失败, 那么  abortTransaction 中止事务,内部将已完成的任务回退到修改之前,并结束当前事务 session。

「真诚赞赏,手留余香」

真诚赞赏,手留余香

使用微信扫描二维码完成支付