1.为什么要使用事务
保证数据的完整性
例子:
张三向李四转账1000元。----在数据库中修改两个账号的余额。
异常,则出现金庸减钱成功,而张无忌加钱失败。 数据的完整性被破坏。
使用事务保护数据的完整性
此时代码执行后金庸的钱没有减,张无忌的钱也没有加
为何第一条语句已执行成功,没有减钱?
数据库事务的原理
如果不写begin;commit;此时事务默认自动开启,自动提交; 在数据库中 ,事务都是自动提交的。事务的自动提交就是执行sql语句完成之后 就立刻持久化到数据库中。
begin;开始事务
rollback;回滚事务
commit;提交事务
当添加了begin;和commit后事务的提交就从自动变成手动。因为中途出错,所以导致 commit;不执行,也就是说缓冲区中的数据没有持久化 的数据库中 。
用java代码演示
public class Test {
public static void main(String[] args) {
Connection connection =null;
try {
Class.forName("com.mysql.cj.jdbc.Driver");
connection= DriverManager.getConnection(
"jdbc:mysql://localhost:3306/mydb?serverTimezone=Asia/Shanghai",
"root",
"root"
);
connection.setAutoCommit(false);//开启事务的手动提交
String sql = "update tb_emp set
salary=salary-1000 where name='金庸'";
PreparedStatement ps = connection.prepareStatement(sql);
ps.executeUpdate();
String sql1 = "update tb_emp set
salary=salary+1000 where name='张无忌'";
ps = connection.prepareStatement(sql1);
ps.executeUpdate();
connection.commit();//提交事务
}catch (Exception e){
try {
connection.rollback();//事务回滚 最初的状态
} catch (SQLException throwables) {
throwables.printStackTrace();
}
e.printStackTrace();
}finally{
}
}
}
2.什么是事务
从开启到提交为一个事务。 由此可见,一个事务对应一组业务。一个事务中间可以有一条sql,多条sql。 所以一个业务开始之前开启事务一个业务 结束之后 提交事务。我们这个转账案例:需要几个事务?可以写成两个 事务,但是不合适。因为我们的需求让张三减的同时让李四加钱。只能写 成一个事 务。把多条sql语句当作一件事情,要同时都能执行到。
事务(Transaction),一般是指要做的或所做的事情。在计算机术语中是指访问并可能更新数据库中各种数据项的一个程序执行单元 (unit)。事务通常由高级数据库操纵语言或编程语言(如SQL,C++或 Java)书写的用户程序的执行所引起,并用形如begin transaction和end transaction语句(或函数调用)来界定。事务由事务开始 (begin transaction)和事务结束(end transaction)之间执行的全体 操作组成。概括为: 事务是由一些列动作组成,这些动作要么都执行,要么都不执行。
3.事务的特性:ACID
1、原子性(Atomicity): 事务开始后所有操作,要么全部做完,要么全部不做,不可能停滞在中间环节。事务执行过程中 出错,会回滚到事务开始前的状态,所有的操作就像没有发生一样。也就是说事务是一个不可分割的整体,就像化学中学过的原子,是物质构成的基本单位。
2、一致性(Consistency): 事务开始前和结束后,数据库的数据完整性约束没有被破坏,事务前后操作数据是一致的 。比如 A向B转账,不可能A扣了钱,B却没收到。能量守恒。
3、隔离性(Isolation): 一个事务的执行不能被其他事务干扰。即一个事务内部的操作及使用的数 据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。比如A正在从一张银行卡中取钱,在A取钱的过程结束前,B不能向这张卡转账。 两个事务之间是有隔离级别,隔离级别的不同会导致出现不同的问题。此时产生三种读: 脏读 幻读 不可重复读。
4、持久性(Durability):持久性(durability)。持久性也称永久性(permanence),指一个事务一旦提交,它对数据库中数据的改变就应该是永久性的。接下来的其他操作或故障不应该对其有任何影响。
4.事务的并发问题
脏读:
不可重复读:
不可重复读:
事务A 多次读取同一数据,事务B 在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一数据时,结果不一致。
幻读:
小结:
不可重复读与幻读很容易混淆,不可重复读侧重于修改,欢度侧重于新增或删除。解决不可重复读只需锁住满足条件的行,解决幻读需要锁表。不可重复读操作的是同一条数据,而且做的是修改操作。
5.事务的隔离级别
解决事务并发带来的问题
隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
读未提交(READ-UNCOMMITTED) | √ | √ | √ |
读已提交(READ-COMMITTED) | × | √ | √ |
可重复读(REPEATABLE-READ) | × | × | √ |
串行化(SERIALIZABLE) | × | × | × |
级别越高,效率越低;mysql的默认隔离级别是可重复读
mysql如何查看隔离级别以及设置隔离级别:
设置mysql的隔离级别:
6.spring支持事务
业务功能包含多个操作,可以使用事务来管理
spring如何支持事务的呢?---事务管理加在service层
切面、事务依赖
<!--aop 面向切面编程 切面依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.2.15.RELEASE</version>
</dependency>
<!--spring的事务依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.2.15.RELEASE</version>
</dependency>
spring配置事务管理类开启事务注解
<!--创建spring事务管理类-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="DataSource"/>
</bean>
<!--开启事务注解-->
<tx:annotation-driven transaction-manager="transactionManager"/>
在相应的类或方法上添加事务注解@Transactional