深入学习Spring框架(四)- 事务管理
1.什么是事务?
事务(Transaction)是一个操作序列。这些操作要么都做,要么都不做,是一个不可分割的工作单位,是数据库环境中的逻辑工作单位。事务是为了保证数据库的完整性。例如:A给B转账,需要先减掉A的账户余额再加到B的账户上,这两个操作是一个整体,不可能扣掉A的钱不给B加上,或者只给B加没有扣掉A的钱。也就是,一个事务每项任务都必须正确执行。如果有任一任务执行失败,则整个事务就会被终止。此前对数据所作的任何修改都将被撤销。
2.Spring事务控制
JDBC默认有进行事务的处理,但它是在持久层(dao层)处理的,一般情况我们需要把事务处理放到业务层(service层)。因为项目中有可能是几个功能为一个完整的事务,如转账的A余额减少和B余额增加为一个事务,而这在持久层是两个操作。
spring框架为我们提供了一组事务控制的应用程序接口(API)。使用Spring是事务代理,可以配置一次,不用重复编写事务处理代码。spring的事务控制都是基于AOP的,它既可以使用编程的方式实现,也可以使用配置的方式实现。我们学习的重点是使用配置的方式实现。
3.数据库并发问题(C)
数据库的并发问题即多个客户端同时同时访问数据库中某一条数据引发的问题,例如:秒杀抢购。这些问题归结为5类,包括3类数据读问题(脏读,不可重复读,幻读)和2类数据更新问题(第一类丢失更新,第二类丢失更新)。
第一类更新丢失:
两个事务更新相同数据,如果一个事务提交,另一个事务回滚,第一个事务的更新会被回滚
第二类丢失更新:
多个事务同时读取相同数据,并完成各自的事务提交,导致最后一个事务提交会覆盖前面所有事务对数据的改变
脏读
第二个事务查询到第一个事务未提交的更新数据,第二个事务根据该数据执行,但第一个事务回滚,第二个事务操作脏数据
幻读:
一个事务查询到了另一个事务已经提交的新数据,导致多次查询数据不一致
不可重复读:
一个事务查询到另一个事务已经修改的数据,导致多次查询数据不一致
4.数据库事务的隔离级别(C)
针对上述的事务并发问题,数据库提供了不同的事务隔离级别来处理不同的事务并发问题,事务隔离级别定义如下:
针对不同隔离级别可以解决的的如下五类问题:
5.解决丢失更新的方案
要解决丢失更新问题可以给数据库表数据加锁:
1.悲观锁
在操作当前数据的事务开启事务就使用for update 锁住当前数据(在Hibernate和MyBatis中都有悲观锁对应的解决方案)
2.乐观锁
为表添加一个version字段。当前事务操作的时候都会比对当前事务情况的多次操作的版本号是否一致,如果不一致认为数据已经被更新(在Hibernate和MyBatis中都有乐观锁对应的解决方案)
6.Spring对事务的支持
Spring的事务管理主要包括3个接口:
TransactionDefinition:
该接口主要定义了:事务的传播行为(规则),事务的隔离级别,获得事务信息的方法。所以在配置事务的传播行为,事务的隔离级别已经需要获得事务信息时,可以通过查阅该类的代码获得相关信息。
TransactionDefinition源码:
public interface TransactionDefinition { //事务的传播行为
int PROPAGATION_REQUIRED = ; int PROPAGATION_SUPPORTS = ; int PROPAGATION_MANDATORY = ; int PROPAGATION_REQUIRES_NEW = ; int PROPAGATION_NOT_SUPPORTED = ;
int PROPAGATION_NEVER = ;
int PROPAGATION_NESTED = ;
//事务的隔离级别
int ISOLATION_DEFAULT = -; int ISOLATION_READ_UNCOMMITTED = Connection.TRANSACTION_READ_UNCOMMITTED; int ISOLATION_READ_COMMITTED = Connection.TRANSACTION_READ_COMMITTED; int ISOLATION_REPEATABLE_READ = Connection.TRANSACTION_REPEATABLE_READ; int ISOLATION_SERIALIZABLE = Connection.TRANSACTION_SERIALIZABLE;
//事务超时管理
int TIMEOUT_DEFAULT = -; //获得事务信息
int getPropagationBehavior(); int getIsolationLevel(); int getTimeout(); boolean isReadOnly(); String getName(); }
事务传播规则
PlatformTransactionManager事务管理器
PlatformTransactionManager:接口统一抽象处理事务操作相关的方法;
1:TransactionStatus getTransaction(TransactionDefinition definition):
根据事务定义信息从事务环境中返回一个已存在的事务,或者创建一个新的事务,并用TransactionStatus描述该事务的状态。
2:void commit(TransactionStatus status):
根据事务的状态提交事务,如果事务状态已经标识为rollback-only,该方法执行回滚事务的操作。
3:void rollback(TransactionStatus status):
将事务回滚,当commit方法抛出异常时,rollback会被隐式调用
在使用spring管理事务的时候,首先得告诉spring使用哪一个事务管理器,使用不同的框架(JdbcTemplate,MyBatis,Hibernate/JPA )使用事务管理器都不同
7.Spring事务的配置
Spring支持编程式事务管理和声明式事务管理。
编程式事务管理:事务和业务代码耦合度太高。
声明式事务管理:侵入性小,把事务从业务代码中抽离出来,使用AOP配置到配置文件中,提高维护性。
7.1声明式事务管理xml方式配置
1.导入jar包
2.创建配置文件并引入约束和命名空间
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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
">
配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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
">
<!-- 配置注解包扫描 -->
<context:component-scan base-package="com.gjs"/> <!-- 读取db.properties 配置文件 -->
<context:property-placeholder location="classpath:db.properties"/> <!-- 创建druid连接池 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close"> <!-- 属性注入 setter方法注入 -->
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<property name="maxActive" value="${jdbc.maxActive}"/>
</bean> <!-- 配置 JdbcTemplate 模板类 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<!-- 使用构造器注入,注入 dataSource 连接池 -->
<constructor-arg name="dataSource" ref="dataSource"/>
</bean> <!-- . 配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- 注入数据源(连接池) -->
<property name="dataSource" ref="dataSource"></property>
</bean> <!-- .事务相关配置:使用tx标签 -->
<!-- 配置事务通知
id:通知唯一标识
transaction-manager:依赖的事务管理器
-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!--
<tx:method name=""/>
需要被事务管理的方法 ,一般是都是service层的方法
name : 被事务管理的方法名
isolation :事务的隔离级别(REPEATABLE_READ)
propagation : 事务的传播规则 (REQUIRED)
read-only :是否是只读事务,默认false(DML 非只读事务,DQL :只读事务-效率相对高一些)
timeout:配置事务超时时间 -->
<!-- 事务方法配置细节
在实际开发中service的方法必须遵循一定编写规则
DQL最好指定 前缀规则 : selectXxx,queryXxx, findXxx,getXxx
我们可以使用 * 来配置指定规则的所有方法 DQL 一般配 只读事务
read-only="true"
DML 一般配 非只读事务
read-only="false"
-->
<!-- DQL -->
<tx:method name="select*" read-only="true" isolation="REPEATABLE_READ" propagation="REQUIRED"/>
<tx:method name="query*" read-only="true" isolation="REPEATABLE_READ" propagation="REQUIRED"/>
<tx:method name="find*" read-only="true" isolation="REPEATABLE_READ" propagation="REQUIRED"/>
<tx:method name="get*" read-only="true" isolation="REPEATABLE_READ" propagation="REQUIRED"/>
<!-- 非DQL -->
<tx:method name="*" read-only="false" isolation="REPEATABLE_READ" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice> <!-- .配置AOP把事务切到service层 -->
<aop:config proxy-target-class="true">
<!-- 配置切入点 -->
<aop:pointcut expression="execution(* com.gjs.service..*.*(..))" id="pt"/>
<!-- 配置切面:切入点+通知
<aop:aspect></aop:aspect> :使用自定义事务管理器进行aop配置事务
<aop:advisor advice-ref="" pointcut-ref=""/>:使用spring的事务管理器
advice-ref="":通知引用
pointcut-ref="":切入点引用
-->
<aop:advisor advice-ref="txAdvice" pointcut-ref="pt"/>
</aop:config> </beans>
7.2声明式事务管理注解方式配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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
">
<!-- 配置注解包扫描 -->
<context:component-scan base-package="com.gjs"/> <!-- 读取db.properties 配置文件 -->
<context:property-placeholder location="classpath:db.properties"/> <!-- 创建druid连接池 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close"> <!-- 属性注入 setter方法注入 -->
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<property name="maxActive" value="${jdbc.maxActive}"/>
</bean> <!-- 配置 JdbcTemplate 模板类 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<!-- 使用构造器注入,注入 dataSource 连接池 -->
<constructor-arg name="dataSource" ref="dataSource"/>
</bean> <!-- 配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- 注入数据源(连接池) -->
<property name="dataSource" ref="dataSource"></property>
</bean> <!-- 开启 事务处理的注解驱动
transaction-manager:引用的事务管理器
-->
<tx:annotation-driven transaction-manager="transactionManager"/> </beans>
@Service
/* @Transactional
* 贴上此当前类已经被Spring事务管理
* 注意: @Transactional 只能对当前贴的Service类有效
* 常用属性 :
* isolation=Isolation.REPEATABLE_READ, 隔离级别
propagation=Propagation.REQUIRED,传播规则
readOnly=true 是否只读事务
*
*/@Transactional(isolation=Isolation.DEFAULT,propagation=Propagation.REQUIRED)
public class AccountServiceImpl implements AccountService{
@Autowired
private AccountDao dao; public void trans(Integer transOutId,
Integer transInId, Integer money) {
dao.tranOut(transOutId, money);
System.out.println(1 / 0);// 模拟断电
dao.tranIn(transInId, money);
}
//单独为某一个方法配置具体的事物细节:如查询方法,事物是只读的
@Transactional(readOnly=true)
public Object getUser() {
//查询操作
return null;
}
@Transactional(readOnly=true)
public List<Object> getUsers() {
//查询操作
return null;
}
}
深入学习Spring框架(四)- 事务管理的更多相关文章
- Spring框架之事务管理
Spring框架之事务管理 一.事务的作用 将若干的数据库操作作为一个整体控制,一起成功或一起失败. 原子性:指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生. 一致性:指事务前后 ...
- Spring 框架的事务管理
1. Spring 框架的事务管理相关的类和API PlateformTransactionManager 接口: 平台事务管理器(真正管理事务的类); TransactionDefinition 接 ...
- 框架应用:Spring framework (四) - 事务管理
事务控制 事务是什么?事务控制? 事务这个词最早是在数据库中进行应用,讲的用户定义的一个数据库操作序列,这些操作要么全做要么全不做,是一个不可分割的工作单位. 事务的管理是指一个事务的开启,内容添加, ...
- Spring框架的事务管理之编程式的事务管理(了解)
1. 说明:Spring为了简化事务管理的代码:提供了模板类 TransactionTemplate,所以手动编程的方式来管理事务,只需要使用该模板类即可!!2.手动编程方式的具体步骤如下: 1.步骤 ...
- Spring框架的事务管理之基于AspectJ的XML方式(重点掌握)
1. 步骤一:恢复转账开发环境(转账开发环境见“https://www.cnblogs.com/wyhluckdog/p/10137283.html”) 2.步骤二:引入AOP的开发包3.步骤三:引入 ...
- Spring框架的事务管理相关的类和API
1. PlatformTransactionManager接口 -- 平台事务管理器.(真正管理事务的类).该接口有具体的实现类,根据不同的持久层框架,需要选择不同的实现类! 2. Transacti ...
- (三)Spring框架之事务管理
一.编程式事务管理 Spring事务管理器的接口是org.springframework.transaction.PlatformTransactionManager,事务管理器接口PlatformT ...
- Spring框架的事务管理之基于AspectJ的注解方式(重点掌握,最简单的方式)
1. 步骤一:恢复转账的开发环境(具体开发环境实现见:https://www.cnblogs.com/wyhluckdog/p/10137283.html)2. 步骤二:applicationCont ...
- Spring框架的事务管理的分类
1. Spring的事务管理的分类 1. Spring的编程式事务管理(不推荐使用) * 通过手动编写代码的方式完成事务的管理(不推荐) 2. Spring的声明式事务管理(底层采用AOP的技术) * ...
- Spring框架的事务管理有哪些优点?
它为不同的事务API 如 JTA,JDBC,Hibernate,JPA 和JDO,提供一个不变的编程模式. 它为编程式事务管理提供了一套简单的API而不是一些复杂的事务API如 它支持声明式事务管理 ...
随机推荐
- Win8 Metro(C#) 数字图像处理--1 图像打开,保存
原文:Win8 Metro(C#) 数字图像处理--1 图像打开,保存 作为本专栏的第一篇,必不可少的需要介绍一下图像的打开与保存,一便大家后面DEMO的制作. Win8Metro编程中,图像相关 ...
- SqlServer 监控发布中未分发的命令数
原文:SqlServer 监控发布中未分发的命令数 对于查看未分发的命令数,我们通常这样查看. 然而当服务器有很多发布时,一个个打开查看就很麻烦 当然,如果想用脚本查看就更方便了,运行下面的语句 -- ...
- Qt 5.9对Mac的图形显示有许多改进
We have some platform specific improvements as well as support for new platforms and compilers comin ...
- LINQ查询表达式---------from子句
LINQ查询表达式---------from子句 LINQ的查询由3基本部分组成:获取数据源,创建查询,执行查询. //1.获取数据源 List<, , , , , }; //创建查询 var ...
- Windows 10 UWP 部署
原文 http://youthlin.com/20151105.html 我们知道VS连接手机可以直接部署到手机里,但平板貌似无法这样干,平板与电脑连接没有丝毫反应……那么想看VS里写的uwp应 ...
- HUSTOJ的Windows版评判内核(限制内存使用)
HUSTOJ的Windows版评判内核(一) 作者:游蓝海 个人主页:http://blog.csdn.net/you_lan_hai 2013.4.9 注:最新版本项目地址:https://gith ...
- EnterpriseLibrary 6.0 AOP 使用问题
因为EnterPrise Library 6.0改动了模块的功能类不再自动从Unity创建了,也就是引导也不依赖Unity容器组件,需要先使用静态方法注册一下 private static void ...
- Qt在Windows下如何创建无CMD窗口控制台程序
默认情况下,用Qt新建一个控制台程序,运行时会弹出CMD窗口.如何把窗口去掉呢? *.pro文件默认是这样的: TEMPLATE = app CONFIG += console CONFIG -= a ...
- 一次C#和C++的实际应用性能比较(C++允许我们使用任何手段来提高效率,只要愿意做出足够的努力)
05年时,在微软的Rico Mariani做了一次实际应用的C#和C++的性能比较.事情起源于微软著名的元老Raymond Chen(在下敬仰的超级牛人)用C++写了一个英汉词典程序,来描述讲解优化C ...
- Spring Boot从入门到实战:集成AOPLog来记录接口访问日志
日志是一个Web项目中必不可少的部分,借助它我们可以做许多事情,比如问题排查.访问统计.监控告警等.一般通过引入slf4j的一些实现框架来做日志功能,如log4j,logback,log4j2,其性能 ...