深入学习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如 它支持声明式事务管理 ...
随机推荐
- vxworks下libpcap的移植
linux下的libpcap应用能够成熟的使用在第三方的应用中,但基于vxworks开发的项目中需要使用libpcap的部分功能则无相应的实现. 研究了下libpcap向vxworks的移植,并且小有 ...
- Android 9.0 Dialog不显示
Tester报了一个bug,大概如下: 页面:Activity1 dialog1(半透明遮罩样式) Activity2 dialog2 场景:Activity1弹出dialog1,dialog1弹出a ...
- GIS基础软件及操作(七)
原文 GIS基础软件及操作(七) 练习七.地形分析 地形分析:TIN及DEM的生成及应用 加深对TIN建立过程的原理.方法的认识: 熟练掌握ArcGIS中建立DEM.TIN的技术方法: 结合实际,掌握 ...
- 朱晔的互联网架构实践心得S2E6:浅谈高并发架构设计的16招
朱晔的互联网架构实践心得S2E6:浅谈高并发架构设计的16招 概览 标题中的高并发架构设计是指设计一套比较合适的架构来应对请求.并发量很大的系统,使系统的稳定性.响应时间符合预期并且能在极端的情况下自 ...
- C++实现半透明按钮控件(PNG,GDI+)
http://blog.csdn.net/witch_soya/article/details/6889904
- 30+ 强大的Buddypress主题–开始您的社区站点吧
BuddyPress起源于2008年,当时设计者设想添加社交网络功能到WordPress多用户版本中.第一个正式稳定版本的发布是在2009年的5月.自从那时起.BuddyPress开始快速的成长和演变 ...
- 确认过眼神,看清HTTP协议
导读:什么是 HTTP?它有什么属性?我们常用的是什么呢?快来阅读本文,将会为你一一道来. 什么是 HTTP 协议? 在了解HTTP之前,我们需要了解什么是网络通信模型(也就是我们常说的 OSI 模型 ...
- ABP开发框架前后端开发系列---(13)高级查询功能及界面的处理
在一般的检索界面中,基于界面易用和美观方便的考虑,我们往往只提供一些常用的条件查询进行列表数据的查询,但是有时候一些业务表字段很多,一些不常见的条件可能在某些场景下也需要用到.因此我们在通用的查询条件 ...
- 【IDE】idea在debug模式启动非常慢,debug模式一直在启动中状态
现象:一直处于启动中状态,日志刷的很慢,非debug模式正常启动: 最终解决方式:下图按钮,取消所有打过的断点,问题解决
- bower工具
1.安装bower npm install bower -g 2.安装软件 borwer install jquery 3.安装指定版本 borwer install jquery#1.7 4.卸载软 ...