事务
定义
摘自 Wiki--database transaction
数据库事务的定义:它象征着在数据库管理系统中运行的一个工作单元(a unit of work),以一种可靠的、一致的方式来相对于其它的事务保持独立。一个事务通常代表数据库中的任何变化(增删改)。数据库环境中的事务有两个主要目的:
提供一个可靠的(reliable)工作单元,使其能从错误中恢复原始状态,保持数据库的一致性,即使是整个(数据库/应用)系统崩溃(部分/全部操作停止,在数据库上的很多操作仍然没有完成,并且当前状态不清楚)
为了在并行访问数据库的程序之间提供隔离性(isolation)。如果没有提供隔离性,那么程序结果可能会错误
在数据库管理系统中,一个事务是单个逻辑或者工作单元,有时它们由多个操作构成。任何在数据库中以一致模式(consistent mode)运行逻辑计算被称为事务。(经典例子:银行转账操作是一个事务,即转出账户扣钱,转入账户加钱,在此过程中起码两条update语句)
事务的定义之下,必须要满足四个特性
atomic,要么完全实现,要么不做事情
consistent,满足数据库中所有的约束(constraint),应用层面的逻辑一致性也应满足(即转账之后账户余额总数不能变)
isolated,即事务之间不能相互影响
durable,即事务造成的变化必须持久化存储
事务隔离级别被定义在了一个事务之中,哪些数据对于当前事务是“可见的”。并发访问数据库时,事务隔离级别定义了多个事务之间对于同一个目标数据源访问时的可交叉程度
可交叉程度
脏读(Dirty Read)
当一个事务可以看到另一个事务未提交的数据,称为脏读,如果该事务回滚,那么另一个事务拿到的数据就是错的
不可重复读(Non-repeatable Read)
事务A读取了一行数据,事务B改了这行数据并提交,事务A再次读了这条数据,数据改变了
幻读(Phantom Read)
事务A读出一个结果集,事务B在这个集中插入了数据,事务A再次读的时候会多一条数据
事务隔离级别
JDBC规范增加了隔离级别。MySQL可以通过select @@global.tx_isolation;查询当前事务隔离级别
TRANSACTION_NONE
这意味着当前的 JDBC 驱动不支持事务,也意味着这个驱动不符合 JDBC 规范
READ_UNCOMMITTED(读未提交)
允许事务看到其它事务修改了但未提交的数据,这意味着有可能是脏读、不可重复读或者幻读
READ_COMMITTED(读提交)
一个事务在未提交之前,所做的修改不会被其它事务所看见。这能避免脏读,但避免不了不可重复读和幻读
REPEATABLE_READ(可重复读取) (MySQL默认的事务隔离级别)
避免了脏读和不可重复读,但幻读依然是有可能发生的
SERIALIZABLE(序列化)(就是顺序执行,高并发场景不适用)
避免了脏读、不可重复读以及幻读
数据库中的锁
数据库中的锁:
1.共享锁(Share locks简记为S锁):也称读锁,事务A对对象T加s锁,其他事务也只能对T加S,多个事务可以同时读,但不能有写操作,直到A释放S锁。
2.排它锁(Exclusivelocks简记为X锁):也称写锁,事务A对对象T加X锁以后,其他事务不能对T加任何锁,只有事务A可以读写对象T直到A释放X锁。
3.更新锁(简记为U锁):用来预定要对此对象施加X锁,它允许其他事务读,但不允许再施加U锁或X锁;当被读取的对象将要被更新时,则升级为X锁,主要是用来防止死锁的。因为使用共享锁时,修改数据的操作分为两步,首先获得一个共享锁,读取数据,然后将共享锁升级为排它锁,然后再执行修改操作。这样如果同时有两个或多个事务同时对一个对象申请了共享锁,在修改数据的时候,这些事务都要将共享锁升级为排它锁。这些事务都不会释放共享锁而是一直等待对方释放,这样就造成了死锁。如果一个数据在修改前直接申请更新锁(这里申请更新锁是排他的),在数据修改的时候再升级为排它锁,就可以避免死锁