1.什么是是事务?
1.1.概念:了解什么是事务
事务是数据库提供的一个特性。
事务:组成各个数据的执行的单元,要么都成功,要么都不成功。
1.2.转账例子
转账的功能,冠希给美美转1000元钱。
使用事务
先给冠希扣除掉1000元
再给美美加上1000元
事务结束了
2.事务的分类
事务分为隐式事务和显式事务两种。我们的DML语句(insert、update、delete)就是隐式事务。
2.1隐式事务:该事务没有明显的开启和结束标记,它们都具有自动提交事务的功能;不妨思考一下,update语句修改数据时,是不是对表中数据进行改变了,它的本质其实就相当于一个事务。
2.2显示事务:该事务具有明显的开启和结束标记;也是本文重点要讲的东西。使用显式事务的前提是你得先把自动提交事务的功能给禁用。禁用自动提交功能就是设置autocommit
变量值为0(0或off:禁用 1:开启)set autocommit = off;
3.事务的使用方式
首先创建一个表
create table t_account(
id int primary key auto_increment,
username varchar(20),
money double
);
insert into t_account values (null,'美美',10000);
insert into t_account values (null,'冠希',10000);
insert into t_account values (null,'小凤',10000);
insert into t_account values (null,'熊大',10000);
insert into t_account values (null,'熊二',10000);
2.在MySQL数据库中使用事务,提供两种方式(重点)
* 模拟转账的例子,冠希给美美转钱
* 第一种方式(使用命令的方式)
* start transaction; ‐‐ 开启事务
* update t_account set money = money ‐ 1000 where username = '冠希';
* update t_account set money = money + 1000 where username = '美美';
* commit; ‐‐ 提供事务(事务已经结束了,数据永久的保存到数据库中了)
* rollback; ‐‐ 回滚事务(事务已经结束了,数据回滚到最初始化的状态)
* 第二种方式(设置MySQL事务不默认提交的方式)
* MySQL数据库的事务是默认提交的。
* update t_account set money = money ‐ 1000 where username = '冠希'; ‐‐ 这一条语句在JDBC中操作事务(掌握)
事务的特性(理解)
* update t_account set money = money ‐ 1000 where username = '冠希'; ‐‐ 这一条语句
默认使用了一个事务。
* 设置让MySQL的数据库的事务不默认提交
* set autocommit = off或者0 ‐‐ 设置MySQL事务的事务不默认提交
* 编写SQL语句(执行完,都没有提交)
* sql1
* sql2
* 需要手动的提交或者回顾
* commit;
* rollback;
* 演示第二种方式
* show variables like '%commit%'; ‐‐ 查看事务的是事务是否是默认提交
* set autocommit = off; ‐‐ 设置不默认提交
* update t_account set money = money ‐ 1000 where username = '冠希';
* update t_account set money = money + 1000 where username = '美美';
* commit;或者rollback;
4.事务的特性
事务的特性:
原子性:原子性对应的英文是Atomicity,即表示事务中所有操作是不可再分割的原子单位。事务中所有操作要么全 部执行成功,要么全部执行失败;
一致性:一致性对应的英文是Consistency,事务执行后,数据库状态与其它业务规则保持一致。例如转账业务,无 论事务执行成功与否,参与转账的两个账号余额之和应该是不变的;
隔离性:隔离性对应的英文是Isolation,是指在并发操作中,不同事务之间应该隔离开来,使每个并发中的事务不 会相互干扰;
持久性:持久性对应的英文是Durability,指的是一旦事务提交成功,事务中所有的数据操作都必须被持久化到数据 库中,即使提交事务后,数据库马上崩溃,在数据库重启时,也必须能保证通过某种机制恢复数据
1.事务的特性 * 原子性 ‐‐ 强调的是事务的不可分割的特性
* 一致性 ‐‐ 强调的是事务执行前后数据需要保证一致
* 隔离性 ‐‐ 强调的是多个事务同时操作一条记录,事务之间不能互相干扰
* 持久性 ‐‐ 强调的是事务一旦结束了,数据将永久的保存到数据库中
5.事务并发是出现的问题:
5.1 脏读:一个事务读取到了另一个事务未提交的数据!
5.2不可重复读:一个事务读取到了另一个事务提交的数据,导致了多次查询的结果不一致。强调的是update,修改记录 的数据。
5.3虚度(幻读):一个事务读取到了另一个事务提交的数据,导致了多次查询的结果不一致。强调是insert,向表中添 加一条数据。
6.设置事务的隔离级别(解决读的问题)
6.1事务的隔离级别(设置数据库的隔离级别,根据级别的不同,解决上述的读的问题)
* Read uncommitted ‐‐ 什么都解决不了
* Read committed ‐‐ 避免脏读,但是不可重复读和虚读有可能产生
* Repeatable read ‐‐ 避免脏读和不可重复读,虚度有可能产生的
* Serializable ‐‐ 避免各种读
6.2 4种隔离级别有安全性和效率
* 安全 Serializable > Repeatable read > Read committed > Read uncommitted
* 效率 Serializable < Repeatable read < Read committed < Read uncommitted
6.3.数据库都有自己默认的隔离级别
* MySQL的数据库,默认的隔离级别是Repeatable read,避免脏读和不可重复读。
7.读问题实验
7.1演示脏读
1.脏读:一个事务读取到了另一个事物未提交的数据。
2.进行测试
* 开启两个窗口,一个A窗口(左),一个B窗口(右)。
* 在A窗口中,查询A窗口的隔离级别:select @@tx_isolation;
* 设置A窗口的隔离级别为最低级别: set session transaction isolation level read uncommitted;
* 在两个窗口中,都开启事物
* start transaction;
* 在B窗口中完成转账的工作。(冠希给美美转1千钱)
* update t_account set money = money ‐ 1000 where username = '冠希';
* update t_account set money = money + 1000 where username = '美美';
* 注意:B窗口的事物未提交。
* 在A窗口中,查询的结果(美美)
* select * from t_account;
* 在B窗口中,回滚的是事物
* rollback;
7.2 避免脏读和演示不可重复读
1.避免脏读的发生,提高的隔离级别。
* set session transaction isolation level read committed;
* 在两个窗口中,都开启事物
* start transaction;
* 在B窗口中完成转账的工作。(冠希给美美转1千钱)
* update t_account set money = money ‐ 1000 where username = '冠希';
* update t_account set money = money + 1000 where username = '美美';
* 注意:事物还是没有提交,但是你需要观察A窗口中是否能读取到B创建未提交的数据。
* 在A窗口中,查询的结果(美美)
* select * from t_account;
* 在B窗口中把事物提交了
* commit;
* 在A窗口中,再查询一次钱。
* 两次查询的结果不一致,发生了不可重复读。
7.3 避免不可重复读
1.设置隔离级别:set session transaction isolation level repeatable read;
* 在两个窗口中,都开启事物
* start transaction;
* 在B窗口中完成转账的工作。(冠希给美美转1千钱)
* update t_account set money = money ‐ 1000 where username = '冠希';
* update t_account set money = money + 1000 where username = '美美';
* 注意:事物还是没有提交,但是你需要观察A窗口中是否能读取到B创建未提交的数据。
* 在A窗口中,查询的结果(美美)
* select * from t_account;
* 在B窗口中把事物提交了
* commit;
* 在A窗口中,再查询一次钱。
* 两次查询的结果一致。
7.4演示幻读
1.设置隔离级别:set session transaction isolation level repeatable read;
* 在两个窗口中,都开启事物
* start transaction;
* 在A窗口中,查询的结果(美美)
* select * from t_account;
*在B窗口中,插入新数据
* insert t_account values(10,"sdsd",1000)
*提交
* commit
* 在A窗口中,再查询一次钱。
* select * from t_account;
* 两次查询的结果不一致,发生了发现出现了插入的新数据,发生幻读问题
*还有可能出现不了,因为innodb引擎在可重复读下可能避免幻读,可以多试几遍。
7.5 避免各种读
1.设置隔离级别:set session transaction isolation level serializable;
* 在两个窗口中,都开启事物
* start transaction;
* 在B窗口中添加一条数据
* insert into t_account values (null,'小苍',10000);
* 注意:没有提交事物
* 在A窗口中查询数据库
* select * from t_account;