如果有的话,对于ERP来说,最好的默认事务隔离级别是什么?

15
我们刚刚开始将一个ERP系统迁移到Java和Hibernate上,并且目标是支持50-100个并发用户。我们使用MS SQL Server作为数据库服务器,对于这个负载来说已经足够好了。
旧系统没有使用事务,而是依赖于手动设置锁(使用标志位)和释放锁来处理关键部分(例如库存变动)。这有点像手动事务管理。但是有时会出现数据不一致的问题。在新系统中,我们希望使用事务来解决这些问题。
对于一个使用约85% OLTP和15% OLAP的ERP系统来说,什么是一个好的/合理的默认事务隔离级别呢?
还是说我应该根据每个任务来决定使用哪个事务级别呢?
这里有四个事务隔离级别:
- 读取未提交(READ UNCOMMITTED) - 读取已提交(READ COMMITTED) - 可重复读取(REPEATABLE READ) - 可串行化(SERIALIZABLE)
5个回答

18
99次中有99次,读提交是正确的答案。这可以确保您只看到其他会话已提交的更改(因此假定您已经正确设计了事务,则结果是一致的)。但是,它不会像可重复读或串行化那样施加锁定开销(特别是在非Oracle数据库中)。
很少情况下,您可能希望运行一个报告,愿意为速度而牺牲准确性,并设置为读未提交隔离级别。虽然这很少是个好主意,但对于锁争用问题,偶尔是一个合理可接受的解决方法。
当您有一个需要看到整个过程中一致数据集的流程时,偶尔会使用串行化和可重复读。例如,如果存在大量过程代码,用户在运行过程中可能会进行更改,并且要求进程始终查看自协调开始时存在的数据,则可能适合将月末对账过程设置为串行化。

1
根据用户数量,我不建议在您的主 OLTP 系统上运行报告。请使用日志传送(或其他复制方式)的辅助服务器进行报告,并使用数据的非规范化版本。 - chadmyers

2

别忘了 SNAPSHOT,它位于 SERIALIZABLE 的下方。

这取决于数据在报告中准确性的重要性。这真的是一个任务逐个任务的事情。


2

这主要取决于您如何设计应用程序,简单的答案是运行READ_COMMITTED。

如果您考虑到它并以此为基础设计系统,您可以认为默认使用READ_UNCOMMITTED,并且仅在需要时增加隔离级别。绝大多数事务都将成功,因此读取未提交的数据不会成为大问题。

隔离级别对查询的影响取决于目标数据库。例如,像Sybase和MSSQL这样的数据库在运行READ_COMMITTED时必须锁定更多资源,而像Oracle这样的数据库则不需要。


1

对于 SQL Server(以及大多数主要的关系型数据库管理系统),我建议使用默认设置。对于 SQL Server,这个设置是 READ COMMITTED。如果设置得太高,会过度消耗数据库资源;如果设置得太低,则会出现一致性问题。


SQL Server 的默认设置可能是 READ COMMITTED,但我认为 ADO.net 的默认设置是 SERIALIZABLE,如果他正在使用 .net,则更重要。 - Robert C. Barth
2
@Robert 这不正确。默认值是SQL Server上的默认值。例如,当您在SqlTransaction上更改隔离级别时,它会在服务器上执行SET TRANSACTION ISOLATION LEVEL XXXX。 - chadmyers

0

读未提交在大多数论坛上肯定处于劣势地位。然而,有一些使用它的原因超越了常见的“速度与准确性”问题。

假设您有:

  • 事务 T1:写入 B,读取 A,(执行更多工作),提交。
  • 事务 T2:写入 A,读取 B,(执行更多工作),提交。

使用“读已提交”的情况下,上述事务不会释放锁直到提交。那么就会遇到这样的情况:T1等待T2释放A,而T2等待T1释放B。这里两个事务发生了锁冲突。

您可以重新编写这些过程以避免这种情况(例如:始终按字母顺序获取资源!)。但是,如果并发用户太多且代码行数达到数万行,这个问题可能变得非常常见和难以诊断和解决。

另一种选择是使用“读未提交”。然后您设计您的事务,假设可能存在脏读。我个人认为,与交错的火车相比,这个问题更容易处理和治疗。

脏读取引起的问题可以被预防。

  • (1) 回滚:不要轻易使用。只有在硬件故障、网络故障或程序崩溃的情况下,才应该作为最后一道防线。

  • (2) 使用应用程序锁创建一个更高级别的锁定机制,其中每个锁更接近于真实世界的资源或操作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接