深入学习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如 它支持声明式事务管理 ...
随机推荐
- c# SQLHelper总汇
/// <summary> /// The SqlHelper class is intended to encapsulate high performance, /// scalabl ...
- List集合去重方式及效率对比
List集合相信大家在开发过程中几乎都会用到.有时候难免会遇到集合里的数据是重复的,需要进行去除.然而,去重方式有好几种方式,你用的是哪种方式呢?去重方式效率是否是最高效.最优的呢?今天就给大家讲解一 ...
- java设计模式(2)
工厂模式定义 在面向对象程序设计中,工厂通常是用来创建其他对象的对象,工产模式根据不同的参数来实现不同的分配方案和创建对象. 在工产模式中,我们创建对象时不会对客户端暴露创建逻辑,而且是通过使用一个共 ...
- System.Exception: ORA-12541: TNS: 无监听程序
今天在一个服务器上发布一个web服务(数据库也装在这台机器上):开发工具 Visual Studio 2008 Oracle但是部署好,浏览的时候报错了:System.Web.Services.Pro ...
- 内存可用性判断 IsBadCodePtr IsBadReadPtr 等等
程序异常崩溃,多数是有内存访问异常引起.为定位崩溃位置通常考虑加强内存访问控制,如此有必要进行内存可用性判断,从<Windows核心编程>中看到内存指针的可用性判断方法,感觉还不错,此处记 ...
- sql语句查询重复值
select * from user where name in (select name from user group by name having count(*)>1)
- SignalR的简单使用(二)
原文:SignalR的简单使用(二) 之前提到SignalR代理在网页,通过生成的Js来完成相关的功能.但我不禁想一个问题, 难到SignalR的服务端就能寄存在web端吗,通过访问网页能方式才能启动 ...
- Android应用开机自启动问题
本文主要介绍Android应用如何实现开机自启动.自启动失败的原因以及通过ADB命令模拟发送BOOT_COMPLETED开机广播. 1.Android应用如何实现开机自启动 (1) 实现一个广播类,接 ...
- delphi 实现微信开发(1) (使用kbmmw web server)
原文地址:delphi 实现微信开发(1)作者:红鱼儿 大体思路: 1.用户向服务号发消息,(这里可以是个菜单项,也可以是一个关键词,如:注册会员.) 2.kbmmw web server收到消息,生 ...
- 《C++ Primer》读书笔记 第二章
1.在算数表达式中最好不要使用char或bool,只有在存放字符或布尔值时才使用他们,因为char在有些机器上是有符号的,在一些机器上是无符号的,所以特别容易出问题,如果只表示一个不大的整数,那么明确 ...