深入学习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如 它支持声明式事务管理 ...
随机推荐
- nprogress.js 头部进度条使用方法
nprogress.js 头部进度条 引入CSS\JS <link rel="stylesheet" type="text/css" href=" ...
- WPF,通过修改dataGrid的cell的style,改变选中行失去焦点时的颜色 4.0可用
<Style TargetType="{x:Type DataGridCell}"> <Style.Triggers> <Trigger Proper ...
- SQLServer 远程服务器不存在,未被指定为有效的发布服务器,或您无权查看可用的发布服务器
原文:SQLServer 远程服务器不存在,未被指定为有效的发布服务器,或您无权查看可用的发布服务器 创建了事务发布,在初始化时出现错误,查看相关代理信息如下: 日志读取器代理错误: 状态: 0,代码 ...
- 深入解析Windows窗口创建和消息分发(三个核心问题:怎么将不同的窗口过程勾到一起,将不同的hwnd消息分发给对应的CWnd类去处理,CWnd如何简单有效的去处理消息,由浅入深,非常清楚) good
笔记:争取不用看下面的内容,只看自己的笔记,就能记住这个流程,就算明白了: _tWinMain-->AfxWinMain,它调用四个函数: -->AfxWinInit用于做一些框架的初始化 ...
- 窗体图片背景(两种方法:设置Brush.Bitmap指向图片,别的控件也可以这样)
var Bitmap: TBitmap; procedure TForm1.FormCreate(Sender: TObject); begin Bitmap := TBitmap.Creat ...
- Google+团队如何测试移动应用 - from Google Testing Blog
How the Google+ Team Tests Mobile Apps by Eduardo Bravo Ortiz “移动第一”在当下已成为很多公司的口头禅.但是能够用一种合理的方法来测试移动 ...
- Oracle expdp/impdp 使用示例
1. 创建目录 使用数据泵之前,需要创建一个存放文件的目录. 这个目录要写入Oracle的数据字典中才能识别. (1)先查看一下已经存在的目录: SQL> col owner format a5 ...
- cookie,session,用户认证组件
一. 绘画跟踪技术 在客户端与服务端的一次会务中,多次的请求与相应,HTTP协议是无状态协议,也就是说每个请求都是独立的!无法记录前一次请求的状态.会话跟踪技术即能够实现多次回话间信息共享的作用,HT ...
- java中list和Arrylist的区别
List:是一个有序的集合,可以包含重复的元素.提供了按索引访问的方式.它继承 Collection. List有两个重要的实现类:ArrayList 和 LinkedList ArrayList:我 ...
- 【linux杂谈】跟随大牛进行一次服务器间通讯问题的排查
发现应用记录日志内,出现网络访问延迟较大的情况. 此类问题较为常见,特别是之前参与辅助一个朋友项目运维的过程中,经常因为网络访问延迟较大,朋友认为是遭到了ddos攻击或者是cc攻击.网络访问延迟较大常 ...