我不完全清楚数据库系统中的事务是做什么的.我知道它们可以用来完全回滚更新列表(例如,在一个账户上扣钱,然后添加到另一个账户),但这就是它们能做的全部吗?具体地说,它们可以用来防止竞争条件吗?例如:

// Java/JPA example
em.getTransaction().begin();
User u = em.find(User.class, 123);
u.credits += 10;
em.persist(u); // Note added in 2016: this line is actually not needed
em.getTransaction().commit();

(我知道这可能是一个单一的更新查询,但情况并非总是如此)

该代码是否受种族条件保护?

我主要对MySQL5+InnoDB感兴趣,但也欢迎给出一般性的答案.

推荐答案

TL/DR:事务执行not本质上阻止所有争用条件.在所有实际数据库实现中,您仍然需要锁定、中止并重试处理或其他保护措施.Transactions are not a secret sauce you can add to your queries to make them safe from all concurrency effects美元.

隔离

你的问题是ACID-isolation中的I.学术上纯粹的 idea 是,事务应该提供完美的隔离,这样的结果就好像每个事务都是串行执行的一样.实际上,在真正的RDBMS实现中,这种情况很少出现;功能因实现而异,规则可以通过使用较弱的isolation level(如READ COMMITTED)来削弱.实际上是you cannot assume that transactions prevent all race conditions,即使是在SERIALIZABLE隔离.

一些RDBMS的能力比其他RDBMS更强.例如,PostgreSQL9.2和更新版本具有相当好的SERIALIZABLE隔离,可以检测most(但不是所有)事务和aborts all but one of the conflicting transactions之间可能的交互.所以它可以相当安全地并行运行事务.

很少(如果有的话)3系统具有真正完美的SERIALIZABLE隔离,可以防止所有可能的竞争和异常,包括锁升级和锁排序死锁等问题.

即使有很强的隔离,一些系统(如PostgreSQL)也会中止冲突事务,而不是让它们等待并连续运行.你的应用程序必须记住它在做什么,然后重新try 交易.因此,虽然事务阻止了与并发相关的异常被存储到数据库中,但它的存储方式对应用程序来说是不透明的.

原子性

可以说,数据库事务的主要目的是提供atomic commit.在提交事务之前,更改不会生效.提交时,就其他事务而言,所有更改都会在同一时刻生效.没有一个事务可以只看到一个事务所做的some个更改1,2.类似地,如果您 Select ROLLBACK,那么该事务的任何更改都不会被任何其他事务看到;就好像你的交易从未存在过.

这是ACID号房的A号.

耐久性

另一个是耐用性-ACID中的D.它指定当您提交事务时,必须真正将其保存到能够在断电或突然重启等故障中幸存下来的存储.

一致性:

wikipedia

乐观并发控制

对于Hibernate、EclipseLink等ORM来说,通常使用optimistic concurrency control(通常称为"乐观锁定")来克服较弱隔离级别的限制,同时保持性能,而不是使用锁定和/或高隔离级别.

此方法的一个关键特性是,它允许您跨多个事务工作,这对于用户数较高且与任何给定用户的交互之间可能有较长延迟的系统来说是一个很大的优势.

参考文献

除文本链接外,请参见the PostgreSQL documentation chapter on locking, isolation and concurrency.即使您使用的是不同的RDBMS,您也会从它解释的概念中学到很多东西.


1为了简单起见,我忽略了这里很少实现的READ UNCOMMITTED隔离级别;它允许肮脏的阅读.

2正如@Meriton指出的那样,推论不一定是真的.Phantom reads发生在SERIALIZABLE以下的任何地方.正在进行的事务的一个部分没有看到一些改变(通过尚未提交的事务),则正在进行的事务does的下一部分在另一个事务提交时看到这些改变.

3嗯,IIRC SQLite2可以在try 写入时锁定整个数据库,但我认为这不是并发问题的理想解决方案.

Database相关问答推荐

如何在Ballina中的事务失败时回滚缓存插入操作

MongoDB根据嵌套文档中的值匹配数组

获取总和列的比率

是否有一个简单的工具可以将 mysql 转换为 postgresql 语法?

为什么 COUNT() 只显示一行表格?

NOSQL 非规范化数据模型

类似 Hibernate 的 C++ 框架

NoSql DB 和 OO Db 有什么区别?

主键、唯一键和外键约束以及索引之间有什么区别?

在 Slick 3 的事务中执行非数据库操作

如何在 MySQL 中强制执行唯一约束?

friendship数据库模式

MySQL 数据库中列名中的连字符

如何将sqlite表从磁盘数据库复制到python中的内存数据库?

如何将纬度/经度对转换为 PostGIS 地理类型?

SQL - 如何使用 MS SQL 2008 R2 备份数据库并导出为 MDF 文件

Django + PostgreSQL:如何重置主键?

将查询限制为一条记录会提高性能吗

如何更正此 sql 连接上的相关名称?

SqlParameterCollection only accepts non-null SqlParameter type objects, not String objects