数据库事务与事务隔离级别

1,219 阅读4分钟

数据库事务

数据库事务可以这么理解,满足数据库ACID特性的一组操作。我们可以使用COMMIT命令提交事务,也可以用ROLLBACK回滚事务。

MySQL 中默认采用自动提交(AUTOCOMMIT)模式。如果不显式使用 START TRANSACTION 语句来开始一个事务,那么每个查询都会被当做一个事务自动提交。

1.png

数据库的acid特性 Atomicity(原子性)

原子性表示该操作不可再被分割,要么全部成功,要么全部失败。回滚可以用日志来实现,日志记录着事务所执行的修改操作,在回滚时反向执行这些修改操作即可。

Consistency(一致性)

一致性表示一个操作必须是从一个一致性状态转换到另外一个一致性状态。

什么是一致性状态呢?就以转账为例子,我转给你钱,那么我的钱就必须减少,而你的增加,不可能我的钱不少,你的钱凭空增加。

Isolation(隔离性)

隔离性是指数据库一个操作不能被其他操作所影响。比如有多个用户同时开启了事务,a用户开启的事务不能被b用户开启的事务所影响。

Durability(持久性)

一旦你的事务提交(commit)之后,则产生的所有修改和数据都会被永久化的记录起来。即使系统发生崩溃,事务执行的结果也不能丢失。除非你的硬盘全损坏了0-0。

并发导致的问题 修改丢失

有两个事务同时一行记录进行修改,其中前面修改的数据被后面修改的数据覆盖了。导致前面修改的数据无效:

2.png 这里T1先将数据修改成50,但是之后被T2覆盖,导致T修改无效。

脏数据读取

与上面差不多。两个并发的事务,A事务和B事务同时操作了同一行数据,A将数据修改之后,此条数据被B事务读取,之后如果A将事务回滚,而B就读到了无效的“脏数据”。

举个例子:小明给我打1000¥,我查余额时发现我多了1000¥,很开心的打算去买衣服。此时因为银行程序错误,刚刚小明打的钱被回滚了。导致我的账户实际并没有这么多钱,后面我选好衣服后发现账户余额不足。。。

不可重复读

是指在一个事务内,多次读同一数据。在这个事务还没有结束时,另外一个事务也访问该同一数据。那么,在第一个事务中的两次读数据之间,由于第二个事务的修改,那么第一个事务两次读到的的数据可能是不一样的。java培训这样在一个事务内两次读到的数据是不一样的,因此称为是不可重复读。(同时操作,事务1分别读取事务2操作时和提交后的数据,读取的记录内容不一致。不可重复读是指在同一个事务内,两个相同的查询返回了不同的结果。 )

3.png

幻读

事务 T1 读取一条指定的 Where 子句所返回的结果集,然后 T2 事务新插入一行记录,这行记录恰好可以满足T1 所使用的查询条件。然后 T1 再次对表进行检索,但又看到了 T2 插入的数据。 (和可重复读类似,但是事务 T2 的数据操作仅仅是插入和删除,不是修改数据,读取的记录数量前后不一致).

幻读的重点在于新增或者删除 (数据条数变化).

4.png

事务隔离级别

Serializable(串行化)

所有事务一个接着一个的执行,这样可以避免幻读 (phantom read)

Repeatded Read(可重复读)

所有被 Select 获取的数据都不能被修改,这样就可以避免一个事务前后读取数据不一致的情况。但是却没有办法控制幻读,因为这个时候其他事务不能更改所选的数据,但是可以增加数据,即前一个事务有读锁但是没有范围锁,为什么叫做可重复读等级呢?那是因为该等级解决了下面的不可重复读问题。

Read Committed(读已提交)

被读取的数据可以被其他事务修改,这样可能导致不可重复读。也就是说,事务读取的时候获取读锁,但是在读完之后立即释放(不需要等事务结束),而写锁则是事务提交之后才释放,释放读锁之后,就可能被其他事务修改数据。

Read uncommited(读未提交)

最低的隔离等级,允许其他事务看到没有提交的数据,会导致脏读。

总结

四个级别逐渐增强,每个级别解决一个问题,每个级别解决一个问题,事务级别遇到,性能越差,大多数环境(Read committed 就可以用了)