事务

事务:
事务指的是逻辑上的一组操作,组成这组操作的各个单元要么全都成功,要么全都失败。
作用:保证在一个事务中多次操作数据库表中数据时,要么全部成功,要么全部失败。
事务的特性(ACID)
数据库的事务必须具备ACID特性,ACID是指 Atomic(原子性)、Consistensy(一致性)、Isolation(隔离型)和Durability(持久性)的英文缩写。
1、原子性(Atomicity)
事务包装的一组sql,要么都执行成功,要么都失败。这些操作是不可分割的。
2、一致性(Consistency)
数据库的数据状态是一致的。
事务的成功与失败,最终数据库的数据都是符合实际生活的业务逻辑。一致性绝大多数依赖业务逻辑和原子性。
3、持久性:(Durability)
事务成功提交之后,对于数据库的改变是永久的。哪怕数据库发生异常,重启之后数据亦然存在。
4、隔离性(Isolation)
一个事务的成功或者失败对于其他的事务是没有影响。2个事务应该相互独立。

事务问题:
脏读:读正在编辑中的数据(不能容忍)
脏数据(正在编辑中的数据) dirty data
Clean data : 编辑完成的数据(保存,撤销)

幻读(虚读):事务A首先根据条件索引得到N条数据,然后事务B改变了这N条数据之外的M条或者增添了M条符合事务A搜索条件的数据,导致事务A再次搜索发现有N+M条数据了,就产生了幻读。
也就是说,当前事务读第一次取到的数据比后来读取到数据条目少。

不可重复读:同一事务中,前后多次读到的数据不一样
在金融/银行类机构,这个问题一定要解决

幻读与不可重复读的区别:
两者有些相似,但是前者针对的是insert,后者针对的update或delete。
spring(数据库)事务隔离级别分为四种(级别递减):
1、Serializable (串行化):最严格的级别,事务串行执行,资源消耗最大;

2、REPEATABLE READ(重复读) :保证了一个事务不会修改已经由另一个事务读取但未提交(回滚)的数据。避免了“脏读取”和“不可重复读取”的情况,但不能避免“幻读”,但是带来了更多的性能损失。

3、READ COMMITTED (提交读):大多数主流数据库的默认事务等级,保证了一个事务不会读到另一个并行事务已修改但未提交的数据,避免了“脏读取”,但不能避免“幻读”和“不可重复读取”。该级别适用于大多数系统。

4、Read Uncommitted(未提交读) :事务中的修改,即使没有提交,其他事务也可以看得到,会导致“脏读”、“幻读”和“不可重复读取”。

隔离级别与解决问题
数据库规范规定了4种隔离级别,分别用于描述两个事务并发的所有情况。

read uncommitted 读未提交,一个事务读到另一个事务没有提交的数据。
a) 存在:3个问题(脏读、不可重复读、虚读)。
b) 解决:0个问题
read committed 读已提交,一个事务读到另一个事务已经提交的数据。
a) 存在:2个问题(不可重复读、虚读)。
b) 解决:1个问题(脏读)
repeatable read(): 可重复读,在一个事务中读到的数据始终保持一致,无论另一个事务是否提交。
a) 存在:1个问题(虚读)。
b) 解决:2个问题(脏读、不可重复读)
serializable 串行化,同时只能执行一个事务,相当于事务中的单线程。
a) 存在:0个问题。
b) 解决:3个问题(脏读、不可重复读、虚读)
安全和性能对比
安全性:serializable > repeatable read > read committed > read uncommitted
性能 : serializable < repeatable read < read committed < read uncommitted
常见数据库的默认隔离级别:
MySql:repeatable read
Oracle:read committed
事务在解决生活中的问题时,逻辑是这样的:
————————————————
ySQL事务操作
sql语句 ——描述
start transaction; ——开启事务 (禁止了自动提交)
commit; ——提交事务 (手动)
rollback; ——回滚事务

准备数据:
create table account(
	id int primary key auto_increment,
	name varchar(20),
	money double
);
**# 初始化数据**
insert into account values (null,'a',1000);
insert into account values (null,'b',1000);

操作:MySQL中可以有两种方式进行事务管理

手动提交:先开启,再提交
自动提交:MySQL默认自动提交。即执行一条sql语句提交一次事务。

在这里插入图片描述
(事务提交之后,sql语句对数据库产生的操作才会被永久的保存)

事务是如何处理异常的?
a=1000 b=1000
开启事务(start transaction;)
update t_account set money = money -100 where name=‘a’; a=900
出现异常
update t_account set money = money +100 where name=‘b’;
事务的回滚(rollback;)(撤销已经成功执行的sql语句,回到开启事务之前的状态)
a=1000 b=1000;
注意:只要提交事务,那么数据就会长久保存了,就不能回滚事务了。即提交或者回滚事务都是代表结束当前事务的操作。

方式二、自动提交,通过修改mysql全局变量“autocommit”进行控制。
通过以下命令可以查看当前autocommit模式:
show variables like ‘%commit%’;
————————————————
set autocommit = 0; – 0:OFF 1:ON

说明:

1)MySql默认自动提交。即执行一条sql语句提交一次事务。
2)设置autocommit为off状态,只是临时性的,下次重新启动mysql,autocommit依然变为on状态。
3)如果设置autocommit为off状态,那么当我们执行一条sql语句,就不会自动提交事务,重新启动可视化工具,数据并没有改变。
4)如果设置autocommit为on状态,如果我们先执行 start transaction; 然后在执行修改数据库的语句:
update account set money = money-100 where name=‘a’;
update account set money = money+100 where name=‘b’;
那么此时就表示上述修改数据库的sql语句都在同一个事务中,此时必须手动提交事务,即commit;
换句话说,如果我们手动开启事务 start transaction; 那么此时mysql就不会自动提交事务,必须手动提交事务。
5)如果设置autocommit为on状态,如果我们不执行 start transaction; 直接执行修改数据库的语句:
update account set money = money-100 where name=‘a’;
update account set money = money+100 where name=‘b’;
那么此时mysql就会自动提交事务。即上述每条sql语句就是一个事务。

JDBC事务操作

Connection对象的方法名 ——描述
conn.setAutoCommit(false) ——开启事务(禁止自动提交)
conn.commit() ——提交事务
conn.rollback() ——回滚事务

注意:在jdbc事务操作中,事务的控制都是通过Connection对象完成的,当一个完整的业务操作前,我们首先使用conn.setAutoCommit(false)来开启事务。默认情况下是true的,表示关闭事务,那么一条sql语句就是一个事务,默认提交事务。如果设置为false,那么表示开启事务,所有的sql语句就会都在一个事务中。
当业务操作完成之后,如果整个操作没有问题,我们需要使用conn.commit()来提交事务。当然了,如果出现了异常,我们需要使用conn.rollback()撤销所有的操作,所以出现异常,需要进行事务的回滚。

常见事务问题之详解
脏读:只一个事务读取了另外一个事务未提交的数据
set session transaction isolation level read uncommitted;

不可重复读:在一个事务内多次读取表中数据,多次读取的结果不同。(和脏读的区别:不可重复读是读取已提交的数据)
set session transaction isolation level read committed;

幻读(虚读):
set session transaction isolation level repeatable read;

指在一个事务中 读取 另一个事务 插入或删除 数据记录,导致当前事务 读取数据前后不一致。
存款100元但未提交,这时银行做报表 统计总额为500元,丙将事务提交,银行再统计就变成了 600元,两次统计结果不一致,银行便会不知所措。
一个事务 读取 另一个事务 已经提交的数据,强调的是 记录数 的变化,常有sql类型为 insertdelete

注意: 在mysql数据库中,底层对于幻读做了优化,演示不了。

serializable串行化
可以避免所有的问题。数据库执行这个事务,其他事务必须等待当前事务执行完毕,才能被执行。
串行为什么可以解决所有问题?因为上述问题都是由并行执行引起的,所以改成所有事务一次执行(串行),就可以解决所有问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值