事务是一串不可分割的原子操作,不能只执行部分操作。例如银行转账,从一个账户中扣除资金,转账到另一个账户上。扣款成功却转账失败是不可接受的。事务可以有提交和回滚操作,提交事务后,事务的修改永久生效。而在提交前,可以通过回滚操作返回事务生效前的状态。

自动提交

在PostgreSQL中,执行一个事务时,默认情况下执行后会立刻提交,我们不能去撤回已经执行的语句,这样执行时提交的模式被称为自动提交。

可以用命令\set AUTOCOMMIT off,或者在执行的事务前加入begin;来取消自动提交。取消自动提交后,事务只会被执行,只有当我们运行commit;时,事务才会被提交。在这种模式下,可以通过运行rollback;语句去回滚已经执行的事务。

脏读、不可重复读与幻读

使用SQL数据库的过程中,有多个事务同时使用一个数据库时,可能出现三种影响查阅数据的现象:脏读、不可重复读与幻读。其中脏读在PostgreSQL中不会发生。

脏读(Dirty Read)

脏读是一个事务执行却未提交他的而数据操作,另一个事务查阅数据时,能读到前一个事务的数据操作。而在读取数据后,前一个事务可能取消了它的操作,后一个事务以为操作发生了,实际操作没有发生。

不可重复读 (Nonrepeatable Read)

不可重复读是一个事务查阅数据后,另一个事务修改(update)了数据库中的内容,执行并提交。前一个事务并不知道在他读取后,有事务修改了数据库中的内容。它如果按条件修改数据,但数据可能已被更改,不一定满足它的条件,亦或本不满足条件的数据变成满足条件的数据,但前一个事务都不知道的。如果它再一次查阅数据,就会发现数据已经发生了改变。连续两次数据查阅的结果不同,被称为不可重复读。

幻读(Phantom Read)

幻读是一个事务,另一个事务增加或删减(insert/delete)数据库中的内容,执行并提交。前一个事务并不知道在他读取后,有事务增删了数据库中的内容,前一个事务再次查询时,查询出的内容会发生增删(仿佛出现了幻觉)。

幻读和不可重复读十分相似,他们的区别主要在一个是Update,另一个是是Insert/Delete。

四个事务隔离级别

SQL标准中有4个事务隔离级别,分别规定了禁止哪些现象发生(N)。四个事务隔离级别分别是read uncommitted, read commited, repeatable read和serializable。

SQL 脏读 不可重复读 幻读
read uncommitted
read commited N
repeatable read N N
serializable N N N

而在PostgreSQL中,只有三个隔离级别,可以用set default_transaction_isolation = 'read uncommitted';指定read uncommitted。但是read uncommitted被视为read commited。此外,在PostgreSQL中,隔离级别为repeatable read时,也不会出现幻读现象。

PostgreSQL 脏读 不可重复读 幻读
read commited N
repeatable read N N N
serializable N N N

Read Commited

有多个事务时,Read commited只读取其他事务已经Commited后的数据内容,所以不会读取到uncommited的部分,也就不会发生脏读现象。

Repeatable Read

Repeatable Read要求,一个事务读取数据后,它并不会阻止其他事务修改数据,但是其他的事务修改数据不会影响到它的操作结果。在它读取数据时,对已有数据的状态进行了快照。这样前一个事务对数据的读取和修改结果,只基于快照和自己的修改,不会发生不可重复读现象。虽然在PostgreSQL中该隔离级别不会发生幻读现象,在SQL标准中,并不禁止此隔离级别发生幻读。

Serializable

Serializable要求读写操作相对所在的事务,是串行的。两个事务同时进行,必须找到一个顺序,让两个事务的结果不能发生Serializable禁止的现象,且能够分出先后。

Serializable是怎么防止幻读的,先挖个坑……(没查到能理解的方法我要哭了

参考链接

[1]. Microsoft SQL Docs: Transactions ODBC

[2]. PostgreSQL 9.3.25 Documentation: SET TRANSACTIO