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 写入时锁定整个数据库,但我认为这不是并发问题的理想解决方案.