Mysql中的事务

事务的定义:

事物就是一组数据库操作的集合

事物的特性:

A:atomic原子性:一个事务里面的所有操作要么全部完成,要么全部失败,回滚到事物执行前的状态
C:Consistent一致性:事务前后数据库的完整性必须保持一致
I:Isolation隔离性:一个事务的执行的不会被其它事务的执行影响,多个并发的事务之间相互隔离,互不影响
D:Durability永久性:一旦一个事务提交后,其对数据库的改变就是永久的

事物的隔离性的影响

  • 脏读:事务A读取到事务B未提交的数据
  • 不可重复读:事务A两次读取的数据不一致(事物B执行了update)
  • 虚读(幻读):事务A两次读取的数据不一致(事物B执行了insert)
  • 丢失更新:两个事务对同一个数据进行更新,后提交的事务,将先提交的事务的修改的数据覆盖了

事物没有隔离性产生的问题的解决

设置事物的隔离级别
1. read uncommited:不能解决任何隔离性产生的问题
2. read commited:可以避免脏读
3. repeatable read:可以避免脏读和不可重复读,不可避免虚读
4. serializable :可以避免任何问题(串行化)

实验

mysql默认的情况下,是自动提交事务:

show variables like '%commit%' +--------------------------------+-------+ | Variable_name | Value | +--------------------------------+-------+ | autocommit | ON | | innodb_commit_concurrency | 0 | | innodb_flush_log_at_trx_commit | 1 | +--------------------------------+-------+ 更改mysql数据库为手动事务 set autocommit = false

读脏数据(事务A读取到事务B的未提交的数据)

事物A:

+----+------+-------+
| id | name | money |
+----+------+-------+
|  1 | aaa  |  1010 |
|  2 | bbb  |  1000 |
|  3 | ccc  |  1000 |
+----+------+-------+

//A窗口的事物:
set session transaction isolation level read committed;
start transaction;
update account set money = money + 10 where id = 1;

//B窗口
set session transaction isolation level read committed;
start transaction;
select * from account;
得到的结果是:
+----+------+-------+
| id | name | money |
+----+------+-------+
|  1 | aaa  |  1000 |
|  2 | bbb  |  1000 |
|  3 | ccc  |  1000 |
+----+------+-------+
A:执行commit B:select * from account;//得到的结果为:
+----+------+-------+
| id | name | money |
+----+------+-------+
|  1 | aaa  |  1010 |
|  2 | bbb  |  1000 |
|  3 | ccc  |  1000 |
+----+------+-------+
证明read committed确实解决了读脏数据的错误,但是又带来了另一个问题,即B两次读取同一个数据的时候,出现了不一致的情况。
repetable read
A事务:
set session transaction isolation level repeatable readstart transactionupdate account set money = money + 100 where id = 1; B事务: set session transaction isolation level repeatable readstart transactionselect * from account;
+----+------+-------+
| id | name | money |
+----+------+-------+
|  1 | aaa  |  1000 |
|  2 | bbb  |  1000 |
|  3 | ccc  |  1000 |
+----+------+-------+

事物A:commit; 事务B:select * from account;
+----+------+-------+
| id | name | money |
+----+------+-------+
|  1 | aaa  |  1000 |
|  2 | bbb  |  1000 |
|  3 | ccc  |  1000 |
+----+------+-------+
证明得到的结果是一样的,那么repeatable read这个隔离级别是可以避免脏数据和不可重复读的

解决丢失更新

丢失更新的产生的情况

解决方案

悲观锁 (假设丢失更新一定会发生 ) —– 利用数据库内部锁机制,管理事务提供的锁机制(不需要我们进行任何的操作,数据库内部会帮我们维护)
1.共享锁
select * from table lock in share mode(读锁、共享锁)
2.排它锁
select * from table for update (写锁、排它锁)
update语句默认添加排它锁

乐观锁 (假设丢失更新不会发生)——- 采用程序中添加版本字段解决丢失更新问题

create table product ( id int, name varchar(20), updatetime timestamp );

insert into product values(1,'冰箱',null);
update product set name='洗衣机' where id = 1;

解决丢失更新:在数据表添加版本字段,每次修改过记录后,版本字段都会更新,如果读取是版本字段,与修改时版本字段不一致,说明别人进行修改过数据 (重改)

你可能感兴趣的:(mysql,数据库,事务)