一、事务的概念
一组数据库操作要么全部成功,要么全部失败,目的是为了保证数据的最终一致性
二、事务的四大特性(ACID)
- 原子性(Actomicity):当前事务的操作要么成功,要么失败,原子性是由undo log日志来保证
- 一致性(Consistency):使用事务的最终目的,由业务代码正确逻辑保证
- 隔离行(Isolation):在事务并发实验时,他们内部的操作不能互干系扰
- 持久性(Durability):一旦提交了事务,它对数据库的改变就应该是永久性的。持久性是由redo log日志来保证
三、事务的隔离级别
InnoDB引擎中提供了四种隔离级别,级别越高事务的隔离行越好,但性能就越低,而隔离性是由mysql的各种锁以及MVCC机制来实现
- READ UNCOMMITTED(读未提交):一个事务可以读到另一个事务未提交的数据。有脏读的可能
- READ COMMITTED(读已提交):事务只能读取到已经提交的数据。有不可重复读的可能性
- REPEATABLE READ(可重复读,MySQL 默认级别):在一个事务中多次读取同一条数据时,结果始终雷同。有幻读读可能
- SERIALIZABLE(可串行化):最严的隔离级别,事务完全串行实验。无上述问题
三、脏读、不可重复读、幻读都是什么?
- 脏读:是指一个事务读取了另一个事务未提交的事务。
例:开启事务修改id是1的数据,但不提交事务。再开一个事务查询id是1的数据,但是不提交事务。
- set tx_isolation = 'read-uncommitted';
- begin;
- update test_tab set blance = blance + 500 where id =1;
- commit ;
复制代码- set tx_isolation = 'read-uncommitted';
- begin ;
- select * from test_tab where id = 1;
- commit ;
复制代码
在事务修改sql事务未提交的环境下,查询结果是更新后的数据。在修改未提交事务时,被另一个事务读去到结果,可见是错误。脏读也就是写的事务未提交时,被另一个事务读区到结果。
- 不可重复读:不可重复读是指只能读去到已经提交了的事务。
例:
还原表中的数据,
- set tx_isolation = 'read-committed';
- begin;
- update test_tab set blance = blance + 500 where id =1;
- commit ;
复制代码- set tx_isolation = 'read-committed';
- begin ;
- select * from test_tab where id = 1;
- commit ;
复制代码 实验步骤:
1、开启一个事务,在事务中更新数据,不提交事务。再开启一个事务,查询正在更新的那条数据,不提交事务。
2、步骤1更新数据的事务提交,再次查询那条数据,不提交事务。
3、步骤1更新语句再次实验,不提交事务。再次查询那条数据,不提交事务。
4、步骤3的更新事务提交。再次查询那条数据,不提交事务。
5、查询的事务提交。
查询的事务无论是否提交,读到的数据都是已经提交事务的数据。
- set tx_isolation = 'repeatable-read';
- begin;
- update test_tab set blance = blance + 500 where id =1;
- commit ;
复制代码- set tx_isolation = 'repeatable-read';
- begin ;
- select * from test_tab where id = 1;
- select * from test_tab where id = 1;
- commit ;
- select * from test_tab where id = 1;
复制代码 步骤:
1、1、开启一个事务,在事务中更新数据,不提交事务。再开启一个事务,查询正在更新的那条数据,不提交事务。
2、2、步骤1更新数据的事务提交,再次查询那条数据,不提交事务。
3、步骤1更新语句再次实验,不提交事务。再次查询那条数据,不提交事务。
4、步骤3的更新事务提交。再次查询那条数据,不提交事务。
5、查询的事务提交,再次查询。
在一个事务里,只要读过了这条数据,后边再读这条数据都以第一次读到的这条数据为主。
那么如何办理这个问题呢?
第一个办法就是用更更高的隔离级别。
第二个办法用乐观锁机制,加上一个version字段,查询的时候将version字段查出来select 业务字段,version from table,更新的时候每次version字段+1 update table set 业务字段, version = version + 1 where version = 前边查出来的version值,知道影响行数大于0。
第三个办法可以使用数据库的悲观锁,假如字段计划到计算的时候,用业务字段 = 业务字段 + 数量,由于mysql的insert、update会有写锁,每次都会用数据库中的最新的数据进行操作
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |