13 Spring 的事务控制
1.事务的概念
理解事务之前,先讲一个你日常生活中最常干的事:取钱。
比如你去ATM机取1000块钱,大体有两个步骤:首先输入密码金额,银行卡扣掉1000元钱;然后ATM出1000元钱。这两个步骤必须是要么都执行要么都不执行。如果银行卡扣除了1000块但是ATM出钱失败的话,你将会损失1000元;如果银行卡扣钱失败但是ATM却出了1000块,那么银行将损失1000元。所以,如果一个步骤成功另一个步骤失败对双方都不是好事,如果不管哪一个步骤失败了以后,整个取钱过程都能回滚,也就是完全取消所有操作的话,这对双方都是极好的。
事务就是用来解决类似问题的。事务是一系列的动作,它们综合在一起才是一个完整的工作单元,这些动作必须全部完成,如果有一个失败的话,那么事务就会回滚到最开始的状态,仿佛什么都没发生过一样。
在企业级应用程序开发中,事务管理必不可少的技术,用来确保数据的完整性和一致性。
事务有四个特性:ACID
原子性(Atomicity):事务是一个原子操作,由一系列动作组成。事务的原子性确保动作要么全部完成,要么完全不起作用。
一致性(Consistency):一旦事务完成(不管成功还是失败),系统必须确保它所建模的业务处于一致的状态,而不会是部分完成部分失败。在现实中的数据不应该被破坏。
隔离性(Isolation):可能有许多事务会同时处理相同的数据,因此每个事务都应该与其他事务隔离开来,防止数据损坏。
持久性(Durability):一旦事务完成,无论发生什么系统错误,它的结果都不应该受到影响,这样就能从任何系统崩溃中恢复过来。通常情况下,事务的结果被写到持久化存储器中。
2.Spring 的事务管理
spring 的事务控制都是基于 AOP 的,它既可以使用编程的方式实现,也可以使用配置的方式实现。我们学习的重点是使用配置的方式实现。
Spring事务管理涉及的接口的联系如下:

PlatformTransactionManager中真正管理事务的对象:
org.springframework.jdbc.datasource.DataSourceTransactionManager JDBC 或 iBatis 进行持久化数据时使用
org.springframework.orm.hibernate5.HibernateTransactionManager Hibernate 版本进行持久化数据时使用
<1>事务的传播行为
REQUIRED:如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。一般的选择(默认值)
SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行(没有事务)
MANDATORY:使用当前的事务,如果当前没有事务,就抛出异常
REQUERS_NEW:新建事务,如果当前在事务中,把当前事务挂起。
NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起
NEVER:以非事务方式运行,如果当前存在事务,抛出异常
NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行 REQUIRED 类似的操作。
3.基于XML的声明式事务控制
项目搭建
<1>数据库表account表对应的账户实体类
package domain; import java.io.Serializable; /**
* 账户实体类
*/
public class Account implements Serializable {
private Integer id;
private String name;
private Float money; public Integer getId() {
return id;
} public void setId(Integer id) {
this.id = id;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public Float getMoney() {
return money;
} public void setMoney(Float money) {
this.money = money;
} @Override
public String toString() {
return "Account{" +
"id=" + id +
", name='" + name + '\'' +
", money=" + money +
'}';
}
}
<2>账户的持久层接口及其实现类
接口
package dao;
import domain.Account; /**
* 账户的持久层接口
*/
public interface IAccountDao { /**
* 根据Id查询账户
* @param accountId
* @return
*/
Account findAccountById(Integer accountId); /**
* 根据名称查询账户
* @param accountName
* @return
*/
Account findAccountByName(String accountName); /**
* 更新账户
* @param account
*/
void updateAccount(Account account);
}
实现类
package dao.impl;
import dao.IAccountDao;
import domain.Account;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.support.JdbcDaoSupport; import java.util.List; /**
* 账户的持久层实现类
*/
public class AccountDaoImpl extends JdbcDaoSupport implements IAccountDao { public Account findAccountById(Integer accountId) {
List<Account> accounts = super.getJdbcTemplate().query("select * from account where id = ?",new BeanPropertyRowMapper<Account>(Account.class),accountId);
return accounts.isEmpty()?null:accounts.get(0);
} public Account findAccountByName(String accountName) {
List<Account> accounts = super.getJdbcTemplate().query("select * from account where name = ?",new BeanPropertyRowMapper<Account>(Account.class),accountName);
if(accounts.isEmpty()){
return null;
}
if(accounts.size()>1){
throw new RuntimeException("结果集不唯一");
}
return accounts.get(0);
} public void updateAccount(Account account) {
super.getJdbcTemplate().update("update account set name=?,money=? where id=?",account.getName(),account.getMoney(),account.getId());
}
}
<3>账户的业务层接口及其实现类
接口
package service; import domain.Account; /**
* 账户的业务层接口
*/
public interface IAccountService {
/**
* 根据id查询账户信息
* @param accountId
* @return
*/
Account findAccountById(Integer accountId); /**
* 转账
* @param sourceName 转成账户名称
* @param targetName 转入账户名称
* @param money 转账金额
*/
void transfer(String sourceName,String targetName,Float money);
}
实现类
package service.impl; import dao.IAccountDao;
import domain.Account;
import service.IAccountService; /**
* 账户的业务层实现类
*
* 事务控制应该都是在业务层
*/
public class AccountServiceImpl implements IAccountService { private IAccountDao accountDao; public void setAccountDao(IAccountDao accountDao) {
this.accountDao = accountDao;
} public Account findAccountById(Integer accountId) {
return accountDao.findAccountById(accountId); } public void transfer(String sourceName, String targetName, Float money) {
System.out.println("transfer....");
//2.1根据名称查询转出账户
Account source = accountDao.findAccountByName(sourceName);
//2.2根据名称查询转入账户
Account target = accountDao.findAccountByName(targetName);
//2.3转出账户减钱
source.setMoney(source.getMoney()-money);
//2.4转入账户加钱
target.setMoney(target.getMoney()+money);
//2.5更新转出账户
accountDao.updateAccount(source); //int i=1/0; //2.6更新转入账户
accountDao.updateAccount(target);
}
}
<4>spring中基于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: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/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- 配置业务层,利用set方法进行依赖注入-->
<bean id="accountService" class="service.impl.AccountServiceImpl">
<property name="accountDao" ref="accountDao"></property>
</bean> <!--配置账户的持久层-->
<bean id="accountDao" class="dao.impl.AccountDaoImpl">
<property name="dataSource" ref="dataSource"></property>
</bean> <!--配置数据源-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/spring"></property>
<property name="username" value="root"></property>
<property name="password" value="plj824"></property>
</bean> <!-- spring中基于XML的声明式事务控制配置步骤
1、配置事务管理器
2、配置事务的通知
此时我们需要导入事务的约束 tx名称空间和约束,同时也需要aop的
使用tx:advice标签配置事务通知
属性:
id:给事务通知起一个唯一标识
transaction-manager:给事务通知提供一个事务管理器引用
3、配置AOP中的通用切入点表达式
4、建立事务通知和切入点表达式的对应关系
5、配置事务的属性
是在事务的通知tx:advice标签的内部 -->
<!-- 配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean> <!-- 配置事务的通知-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<!-- 配置事务的属性
isolation:用于指定事务的隔离级别。默认值是DEFAULT,表示使用数据库的默认隔离级别。
propagation:用于指定事务的传播行为。默认值是REQUIRED,表示一定会有事务,增删改的选择。查询方法可以选择SUPPORTS。
read-only:用于指定事务是否只读。只有查询方法才能设置为true。默认值是false,表示读写。
timeout:用于指定事务的超时时间,默认值是-1,表示永不超时。如果指定了数值,以秒为单位。
rollback-for:用于指定一个异常,当产生该异常时,事务回滚,产生其他异常时,事务不回滚。没有默认值。表示任何异常都回滚。
no-rollback-for:用于指定一个异常,当产生该异常时,事务不回滚,产生其他异常时事务回滚。没有默认值。表示任何异常都回滚。
-->
<tx:attributes>
<tx:method name="*" propagation="REQUIRED" read-only="false"/>
<tx:method name="find*" propagation="SUPPORTS" read-only="true"></tx:method>
</tx:attributes>
</tx:advice> <!-- 配置aop-->
<aop:config>
<!-- 配置切入点表达式-->
<aop:pointcut id="pt1" expression="execution(* service.impl.*.*(..))"></aop:pointcut>
<!--建立切入点表达式和事务通知的对应关系 -->
<aop:advisor advice-ref="txAdvice" pointcut-ref="pt1"></aop:advisor>
</aop:config>
</beans>
13 Spring 的事务控制的更多相关文章
- 04 Spring:01.Spring框架简介&&02.程序间耦合&&03.Spring的 IOC 和 DI&&08.面向切面编程 AOP&&10.Spring中事务控制
spring共四天 第一天:spring框架的概述以及spring中基于XML的IOC配置 第二天:spring中基于注解的IOC和ioc的案例 第三天:spring中的aop和基于XML以及注解的A ...
- spring的事务控制
1.事务介绍 (1)特性:ACID Atomicity(原子性):事务中的所有操作要么全做要么全不做 Consistency(一致性):事务执行的结果使得数据库从一个一致性状态转移到另一个一致性状态 ...
- 阶段3 2.Spring_10.Spring中事务控制_9 spring编程式事务控制1-了解
编程式的事物控制,使用的情况非常少,主要作为了解 新建项目 首先导入包坐标 复制代码 这里默认值配置了Service.dao和连接池其他的内容都没有配置 也就说现在是没有事物支持的.运行测试文件 有错 ...
- 阶段3 2.Spring_10.Spring中事务控制_8 spring基于纯注解的声明式事务控制
新建项目 把之前项目src下的内容全部复制过来 pom.xml内复制过来 开始配置 新建一个config的包,然后再新建配置文件类SpringConfiguration @Configuration这 ...
- 阶段3 2.Spring_10.Spring中事务控制_5 spring事务控制的代码准备
创建一个工程,只搭建环境不做配置.等配置的时候把这个项目相关的代码再复制到新项目里面 jar包的打包方式 导入包 事务控制也是基于AOP的.所以这里导入aspectjweaver 复制jdbcTemp ...
- 阶段3 2.Spring_10.Spring中事务控制_4 spring中事务控制的一组API
分析aop的 xml 的代码.更直观一些 事务提交和回滚就是我们重复的代码 spring业余事务管理器,我们拿过来直接用就可以 提交和回滚的后面直接调用释放.所以释放资源之类就是多余的 在绑定连接到线 ...
- 阶段3 2.Spring_10.Spring中事务控制_1 基于XML的AOP实现事务控制
新建项目 首先把依赖复制进来 aop必须引入.aspectjweaver 复制src下的所有内容 复制到我们的新项目里面 factory文件夹删掉 删除后测试类必然就报错 配置文件 beanFacto ...
- Spring的事务控制-基于注解的方式
模拟转账操作,即Jone减少500,tom增加500 如果有疑问请访问spring事务控制-基于xml方式 1.创建数据表 2.创建Account实体类 public class Account { ...
- Spring 中事务控制的API介绍
1.PlatformTransactionManager Spring所有事务代理类都是基于PlatformTransactionManager接口的实现. 此接口是spring的事务管理器,它里面提 ...
随机推荐
- 《OKR工作法》–让所有人承担自己的职责
<OKR工作法>中提到了一个创业故事,TeaBee,创业的目标是让喜欢喝茶的人喝到好茶. 创业初期作为首席执行官的汉娜和作为总裁的杰克就在将茶叶提供给餐厅还是餐厅供应商上产生了分歧,随后他 ...
- WinDbg的工作空间---Work Space
一.什么是工作空间 Windbg把和调试相关的所有配置称为workspace.WinDbg使用工作空间来描述和存储调试项目的属性.参数及调试器设置等信息.工作空间与vc中的项目文件很相似.退出wind ...
- [RN] React Native 使用 FlatList 实现九宫格布局 GridList
React Native 使用 FlatList 实现九宫格布局 先看图片演示实例: 本文以图片列表为例,实现九宫格布局! 主要有两种方法: 1)方法一: 利用FlatList的 numColumns ...
- [USACO06FEB] Stall Reservations 贪心
[USACO06FEB] Stall Reservations 贪心 \(n\)头牛,每头牛占用时间区间\([l_i,r_i]\),一个牛棚每个时间点只能被一头牛占用,问最少新建多少个牛棚,并且每头牛 ...
- SQL基础-过滤数据
一.过滤数据 1.使用WHERE子句 过滤数据:关键字WHERE SELECT 字段列表 FROM 表名 WHERE 过滤条件; 过滤条件一般由要过滤的字段.操作符.限定值三部分组成: 如: SELE ...
- OpenFOAM——三角腔驱流
本算例来自<ANSYS Fluid Dynamics Verification Manual>中的VMFL011: Laminar Flow in a Triangular Cavity ...
- Kubernetes Pod概述
Pod简介 Pod是Kubernetes创建或部署的最小/最简单的基本单位,一个Pod代表集群上正在运行的一个进程. 一个Pod封装一个应用容器,Pod代表部署的一个单位. Pods提供两种共享资源: ...
- maven 私服上有jar包但是却下载不下来
解决办法: 在parent中执行deploy命令就解决了. 原因:第一次建项目,上传jar包的时候直接进入到该项目中进行deploy到私服.最终发现私服仓库有,但是别人引用的时候无法下载.是因为别人下 ...
- 集成了SSM框架的系统怎么做测试?
1.首先在测试文件夹下新建一个测试基类BaseTest BaseTest中的代码如下: package wbl_ssm_blog.mapper; import org.junit.Test; impo ...
- MySQL事务部分回滚-回滚到指定保存点
我们可以在mysql事务处理过程中定义保存点(SAVEPOINT),然后回滚到指定的保存点前的状态. 定义保存点,以及回滚到指定保存点前状态的语法如下. 定义保存点---SAVEPOINT 保存点名; ...