spring的事务管理详解编程语言

Spring事务管理高层抽象主要包括3个接口:
PlatformTransactionManager 事务管理器
TransactionDefinition 事务定义信息(隔离、传播、超时、只读)
TransactionStatus 事务具体运行状态

1.PlatformTransactionManager 接口 (平台相关事务管理器 ),由这个接口提供事务管理 API
方法:
commit 提交事务
rollback 回顾事务
TransactionStatus getTransaction(TransactionDefinition) 获取当时时刻事务状态
不同持久层技术,事务管理代码是不同
JDBC 通过Connection 接口 提供 的setAutoCommit(true|false) 来管理事务,setAutoCommit(false) ; 关闭自动提交,开启事务
Hibernate通过Session 接口提供 beginTransaction()的方法来开启事务

JDBC事务管理 : Spring 提供 DataSourceTransactionManager
Hibernate 事务管理: Spring 提供 HibernateTransactionManager

2.TransactionDefinition 接口 (事务定义参数 )
提供了大量常量信息 ISOLATION_* 事务隔离级别 PROPAGATION_* 事务传播行为 TIMEOUT_DEFAULT 事务超时时间
用户可以通过Spring配置文件,指定事务 隔离级别、传播行为、超时时间、 是否只读等

隔离级别:
隔离级别 来源于 事务隔离性引发并发问题 (脏读、 不可重复读、 幻读)

脏读:一个事务读取了另一个事务改写但还未提交的数据,如果这些数据被回滚,则读到的数据是无效的。
不可重复读:在同一事务中,多次读取同一数据返回的结果有所不同。换句话说就是,后续读取可以读到另一事务已提交的更新数据。相反,“可重复读”在同一事务中多次读取数据时,能够保证所读数据一样,也就是,后续读取不能读到另一事务已提交的更新数据。
幻读:一个事务读取了几行记录后,另一个事务插入一些记录,幻读就发生了。再后来的查询中,第一个事务就会发现有些原来没有的记录。

隔离级别,是数据库内部一个机制, JDBC 和 Spring 事务管理,都提供对应支持
这里写图片描述

事务传播行为 :
事务传播行为,并不是数据库内部支持特性,而是Spring 为了解决企业开发中实际事务管理问题,提供了 七种 事务的传播行为
这里写图片描述

REQUIRED 、SUPPORTS 、MANDATORY 三个行为,都是支持当前事务,被调用方法和原来方法可以处于同一个事务中 (例如: 删除客户、删除订单 )
REQUIRES_NEW、NOT_SUPPORT 、NEVER 三个行为,都是不支持当前事务,被调用方法和原来方法 一定不会处于同一个事务 (例如: ATM取钱 、打印凭条 )
NESTED 是最特殊的一种 ,嵌套事务执行 ,原理就是SavePoint 回滚点技术
—- 嵌套事务,仍然使用是同一个事务 ,可以在事务执行过程中 设置回滚点,如果被调用方法出错后,可以选择将程序 回滚到 回滚点 (只对DataSourceTransactionManager有效 )

重点区别: REQUIRED、 REQUIRES_NEW 、NESTED
REQUIRED : 两个操作,处于同一个事务中,要么都成功,要么都失败
REQUIRES_NEW : 两个操作 分别处于两个不同事务,彼此之间不会互相影响
NESTED : 两个操作,处于同一个事务,但是内部采用 SavePoint机制,在一个操作出现问题时,回滚到保存点,继续操作

3.TransactionStatus 接口 (事务状态 )
每个时刻 事务的状态是不同的 , 该对象数据可以表示某个时刻的事务状态信息

3个接口之间的的关系: PlatformTransactionManager 是真正用来进行事务管理对象, TransactionDefinition是用户事务定义信息, PlatformTransactionManager根据 TransactionDefinition 信息来进行事务管理, 在管理事务过程中,每个时间点都可以获取事务状态 (TransactionStatus )

Spring 事务管理,
Spring的事务管理支持编程式事务管理 (通过代码进行事务管理) 和 声明式事务管理 (通过配置进行事务管理,不需要编写格外的代码 ),推荐使用 声明式事务管理, 声明式事务管理底层实现 就是 AOP 编程。

代码示例:
数据库准备

CREATE TABLE `account` ( 
  `id` int(11) NOT NULL AUTO_INCREMENT, 
  `name` varchar(20) NOT NULL, 
  `money` double DEFAULT NULL, 
  PRIMARY KEY (`id`) 
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8; 
 
INSERT INTO `account` VALUES ('1', 'aaa', '1000'); 
INSERT INTO `account` VALUES ('2', 'bbb', '1000'); 

AccountService.java

package com.my.service; 
 
public interface AccountService { 
 
    public void transfer(String outAccount, String inAccount, double money); 
 
} 

AccountServiceImpl.java

package com.my.service; 
 
import com.my.dao.AccountDao; 
 
public class AccountServiceImpl implements AccountService { 
 
    private AccountDao accountDao; 
 
    public void setAccountDao(AccountDao accountDao) { 
        this.accountDao = accountDao; 
    } 
 
 
    @Override 
    public void transfer(String outAccount, String inAccount, double money) { 
        accountDao.out(outAccount, money); 
        //int d = 1/0; 
        accountDao.in(inAccount, money); 
    } 
 
} 

AccountDao.java

package com.my.dao; 
 
public interface AccountDao { 
 
    public void out(String outAccount, double money); 
    public void in(String inAccount , double money); 
 
} 

AccountDaoImpl.java

package com.my.dao; 
 
import org.springframework.jdbc.core.support.JdbcDaoSupport; 
 
public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao { 
 
    @Override 
    public void out(String outAccount, double money) { 
        String sql = "update account set money = money - ? where name = ?"; 
        this.getJdbcTemplate().update(sql, money, outAccount); 
    } 
 
    @Override 
    public void in(String inAccount, double money) { 
        String sql = "update account set money = money + ? where name = ?"; 
        this.getJdbcTemplate().update(sql, money, inAccount); 
    } 
 
} 

applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?> 
<beans xmlns="http://www.springframework.org/schema/beans" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xmlns:context="http://www.springframework.org/schema/context" 
xmlns:aop="http://www.springframework.org/schema/aop" 
xmlns:tx="http://www.springframework.org/schema/tx" 
xsi:schemaLocation=" 
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd 
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd 
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd 
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> 
<!-- 引入外部properties 属性文件  -->  
<context:property-placeholder location="classpath:jdbc.properties"/>     
<!-- C3P0连接池  --> 
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> 
<property name="driverClass" value="${jdbc.driver}"></property> 
<property name="jdbcUrl" value="${jdbc.url}"></property> 
<property name="user" value="${jdbc.username}"></property> 
<property name="password" value="${jdbc.password}"></property> 
</bean> 
<!-- 将连接池交给JdbcTemplate 构造模板对象 --> 
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> 
<property name="dataSource" ref="dataSource"></property> 
</bean> 
<bean id="accountDao" class="com.my.dao.AccountDaoImpl"> 
<property name="jdbcTemplate" ref="jdbcTemplate"></property> 
</bean> 
<!-- 目标  --> 
<bean id="accountService" class="com.my.service.AccountServiceImpl"> 
<property name="accountDao" ref="accountDao"></property> 
</bean> 
<!-- 增强  --> 
<!-- 事务管理器  --> 
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> 
<property name="dataSource" ref="dataSource"></property> 
</bean> 
<!-- 就是事务管理增强   
isolation 隔离级别 
no-rollback-for 发生哪些异常,事务不进行回滚 
propagation 传播行为 
read-only 事务是否只读  
rollback-for  发生哪些异常,事务回滚  
timeout 超时时间 -1 使用数据库内部默认超时时间  
read-only 只读 和 no-rollback-for 发生异常事务不回滚 
--> 
<tx:advice id="mytxAdvice" transaction-manager="transactionManager"> 
<!-- 事务管理属性配置  --> 
<tx:attributes> 
<!-- 对哪些方法 ,进行事务事务配置  --> 
<tx:method name="transfer" /> <!-- 使用默认事务管理属性 --> 
<tx:method name="get*" read-only="true"/> <!-- 将查询的方法设置为 只读  --> 
</tx:attributes> 
</tx:advice> 
<!-- 配置advisor --> 
<aop:config> 
<!-- 定义切点 --> 
<aop:pointcut expression="execution(* com.my.service.AccountServiceImpl.*(..))" id="mypointcut"/> 
<!-- 定义切面 --> 
<aop:advisor advice-ref="mytxAdvice" pointcut-ref="mypointcut"/> 
</aop:config> 
</beans>

使用注解实现 声明式事务管理
第一步 : 在需要管理事务 方法上 ,添加 @Transactional
该注解可以用于类或者方法上,如果用于类上,对对象中所有方法开启事务管理 ,[email protected] 注解中配置事务的属性

@Transactional 
public class AccountServiceImpl implements IAccountService{

第二步 : 在配置文件中 ,配置使用注解进行声明式事务管理

<!-- 使用注解进行声明式事务管理  --> 
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> 
<property name="dataSource" ref="dataSource"></property> 
</bean> 
<tx:annotation-driven transaction-manager="transactionManager"/>

原创文章,作者:Maggie-Hunter,如若转载,请注明出处:https://blog.ytso.com/12093.html

(0)
上一篇 2021年7月19日
下一篇 2021年7月19日

相关推荐

发表回复

登录后才能评论