Odoo 后端数据库postgreSQL事务级别
Posted Odoo things
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Odoo 后端数据库postgreSQL事务级别相关的知识,希望对你有一定的参考价值。
Table of Contents
事务的特性
事务4个特性,简写未ACID
- 原子性(Atomicity):
事务是数据库的逻辑工作单位,它对数据库的修改要么全部执行,要么全部不执行。
- 一致性(Consistemcy):
事务前后,数据库的状态都满足所有的完整性约束。
- 隔离性(Isolation):
并发执行的事务是隔离的,一个不影响一个。如果有两个事务,运行在相同的时间内,执行相同的功能,事务的隔离性将确保每一事务在系统中认为只有该事务在使用系统。这种属性有时称为串行化,为了防止事务操作间的混淆,必须串行化或序列化请求,使得在同一时间仅有一个请求用于同一数据。通过设置数据库的隔离级别,可以达到不同的隔离效果。
- 持久性(Durability):
在事务完成以后,该事务所对数据库所作的更改便持久的保存在数据库之中,并不会被回滚。
并行事务的问题
并行事务可能造成以下问题
Dirty Read【脏读】:
脏读又称无效数据读出。一个事务读取另外一个事务还没有提交的数据叫脏读。
例如:事务T1修改了一行数据,但是还没有提交,这时候事务T2读取了被事务T1修改后的数据,之后事务T1因为某种原因Rollback了,那么事务T2读取的数据就是脏的。
Nonrepeatable Read【不可重复读】:
不可重复读是指在同一个事务内,两个相同的查询返回了不同的结果。
例如:事务T1读取某一数据,事务T2读取并修改了该数据,T1为了对读取值进行检验而再次读取该数据,便得到了不同的结果。
Phantom Read【幻读】:
事务在操作过程中进行两次查询,第二次查询的结果包含了第一次查询中未出现的数据或者缺少了第一次查询中出现的数据
例如:系统管理员A将数据库中所有学生的成绩从具体分数改为ABCDE等级,但是系统管理员B就在这个时候插入了一条具体分数的记录,当系统管理员A改结束后发现还有一条记录没有改过来,就好像发生了幻觉一样。这就叫幻读。
备注:
不可重复读,在 update 语句时 可能发生
幻读,在 insert , delete 语句时 可能发生
事务隔离级别
标准SQL支持 4种 事务隔离级别
Transaction Isolation Levels
Isolation Level | Dirty Read 【脏读】 | Nonrepeatable Read【不可重复读】 | Phantom Read【幻读】 |
Read uncommitted 【未提交读】 | Allowed, but not in PG | Possible | Possible |
Read committed 【提交读】 | Not possible | Possible | Possible |
Repeatable read【可重复读】 | Not possible | Not possible | Allowed, but not in PG |
Serializable【串行化】 | Not possible | Not possible | Not possible |
Odoo事务隔离级别
odoo使用psycopg2 连接 postgreSQL进行数据库操作,并且自己实现了一个 connection pool,根据 config 指定的 db_maxconn 设置 连接池的 大小
在对Pg 进行连接的时候,默认使用 的事务隔离级别为 可重复读, 代码为
@check
def autocommit(self, on):
if on:
isolation_level = ISOLATION_LEVEL_AUTOCOMMIT
else:
# If a serializable cursor was requested, we
# use the appropriate PotsgreSQL isolation level
# that maps to snaphsot isolation.
# For all supported PostgreSQL versions (8.3-9.x),
# this is currently the ISOLATION_REPEATABLE_READ.
# See also the docstring of this class.
# NOTE: up to psycopg 2.4.2, repeatable read
# is remapped to serializable before being
# sent to the database, so it is in fact
# unavailable for use with pg 9.1.
isolation_level = \\
ISOLATION_LEVEL_REPEATABLE_READ \\
if self._serialized \\
else ISOLATION_LEVEL_READ_COMMITTED
self._cnx.set_isolation_level(isolation_level)
可以看出 只要 connection 建立的时候, autocommit(False) 并且 self._serialized = True, 那么 事务隔离级别就是 ISOLATION_LEVEL_REPEATABLE_READ【可重复读】
实际上, psycopg2 在往 pg 传递事务 隔离级别时, 会根据 pg的版本进行 调整
当 pg_version < 8 时, 事务隔离级别会 提升
/* Promote an isolation level to one of the levels supported by the server */
if (self->server_version < 80000) {
if (isolevel == ISOLATION_LEVEL_READ_UNCOMMITTED) {
isolevel = ISOLATION_LEVEL_READ_COMMITTED;
}
else if (isolevel == ISOLATION_LEVEL_REPEATABLE_READ) {
isolevel = ISOLATION_LEVEL_SERIALIZABLE;
}
}
所以, 当 pg 版本 低于 8 时, odoo的事务级别实际上设置为了 Serializable【串行化】; 当 使用新版的 pg 时, odoo的事务隔离级别为 Repeatable read【可重复读】,这个事务隔离级别会发生 表行锁。对于并发并行同一行数据, 会造成"could not serialize access due to concurrent update" 错误。
odoo事务控制
尽管Odoo Model方法是内建事务的,但是在需要的时候,可以使用 savepoint 进行现场保护,然后,对事务进行控制, 回滚,或者 释放
在需要 记录还原点的时候 使用 cursor.savepoint() , 例如
以上是关于Odoo 后端数据库postgreSQL事务级别的主要内容,如果未能解决你的问题,请参考以下文章
使用Django和PostgreSQL进行事务(@atomic)的默认隔离级别