事务隔离级别与表上的锁相关

Lea*_*ner 96 java transactions isolation-level

我读过大约4级隔离:

Isolation Level       Dirty Read    Nonrepeatable Read  Phantom Read  
READ UNCOMMITTED      Permitted       Permitted           Permitted
READ COMMITTED              --        Permitted           Permitted
REPEATABLE READ             --             --             Permitted
SERIALIZABLE                --             --              --
Run Code Online (Sandbox Code Playgroud)

我想了解每个事务隔离对表的锁定

READ UNCOMMITTED - no lock on table
READ COMMITTED - lock on committed data
REPEATABLE READ - lock on block of sql(which is selected by using select query)
SERIALIZABLE - lock on full table(on which Select query is fired)
Run Code Online (Sandbox Code Playgroud)

下面是事务隔离中可能发生的三种现象
Dirty Read - no lock
Nonrepeatable Read - 没有脏读作为锁定提交数据
Phantom Read - 锁定sql块(通过使用select查询选择)

我想了解我们在哪里定义这些隔离级别:仅在jdbc/hibernate级别或在DB中

PS:我已经浏览了oracle隔离级别的链接,但是它们看起来很笨拙并且在数据库特定方面进行了讨论

Lui*_*oza 144

我想了解每个事务隔离对表的锁定

例如,您有3个并发进程A,B和C.A启动事务,写入数据和提交/回滚(取决于结果).B只执行一个SELECT语句来读取数据.C读取和更新数据.所有这些过程都在同一张桌子上工作.

  • READ UNCOMMITTED - 没有锁在桌子上.您可以在书写时读取表格中的数据.这意味着A写入数据(未提交),B可以读取此未提交的数据并使用它(出于任何目的).如果A执行回滚,B仍然读取数据并使用它.这是处理数据的最快但最不安全的方式,因为这可能导致非物理相关表中的数据漏洞(是的,两个表可以在逻辑上但在实际应用中没有物理相关= \).
  • READ COMMITTED - 锁定已提交的数据.您可以读取仅提交的数据.这意味着A写入数据,B在A执行提交之前无法读取A保存的数据.这里的问题是C可以更新在B上读取和使用的数据,B客户端将没有更新的数据.
  • REPEATABLE READ - 锁定SQL块(使用select查询选择).这意味着B在某些条件下读取数据,即WHERE aField > 10 AND aField < 20A插入aField数值,其中值在10到20之间,然后B再次读取数据并获得不同的结果.
  • SERIALIZABLE - 锁定一个完整的表(在其上触发Select查询).这意味着,B读取数据,没有其他事务可以修改表上的数据.这是处理数据的最安全但最慢的方法.此外,由于简单的读取操作会锁定表格,这可能会导致生产中出现严重问题:假设T表是发票表,用户X想要知道当天的发票而用户Y想要创建新发票,所以当X执行发票的读取时,Y无法添加新发票(当它涉及金钱时,人们会变得非常生气,尤其是老板).

我想了解我们在哪里定义这些隔离级别:仅在JDBC/hibernate级别或在DB中

使用JDBC,您可以使用它来定义它Connection#setTransactionIsolation.

使用Hibernate:

<property name="hibernate.connection.isolation">2</property>
Run Code Online (Sandbox Code Playgroud)

哪里

  • 1:READ UNCOMMITTED
  • 2:READ COMMITTED
  • 4:REPEATABLE READ
  • 8:SERIALIZABLE

Hibernate配置来自这里(抱歉,它是西班牙语).

顺便说一句,您也可以在RDBMS上设置隔离级别:

等等...

  • 关于REPEATABLE READ - 我认为一个更好的例子来演示它如下:B启动一个事务,读取sql块上的数据WHERE aField> 10 AND aField <20,该数据被锁定直到事务结束.A尝试更新该数据但由于锁定而等待.现在,当B将在同一事务中再次读取该数据时,它保证读取相同的数据,因为它已被锁定.如我错了请纠正我. (11认同)
  • @LuiggiMendoza - 我不准确,应该是这样的 - B读取的数据没有改变,但B做出的后续选择可以返回更多的行.那是因为**A无法修改B已经读取的行**,直到A释放它们.然而,A可以**插入符合where条件**的新行(因此,下次A将执行select,它将获得更多行的不同结果 - 幻像读取). (4认同)
  • 此外,为了节省使用SET TRANSACTION语句开始每个事务的网络和处理成本,您可以使用ALTER SESSION语句为所有后续事务设置事务隔离级别:ALTER SESSION SET ISOLATION_LEVEL SERIALIZABLE; ALTER SESSION SET ISOLATION_LEVEL READ COMMITTED; (2认同)

gab*_*ssi 8

正如brb tea所说,取决于他们使用的数据库实现和算法:MVCC或两阶段锁定.

CUBRID(开源RDBMS)解释了这两种算法的想法:

  • 两相锁定(2PL)

第一个是当T2事务尝试更改A记录时,它知道T1事务已经更改了A记录并等待T1事务完成,因为T2事务无法知道T1事务是否将被提交或滚动背部.该方法称为两相锁定(2PL).

  • 多版本并发控制(MVCC)

另一个是允许它们中的每一个(T1和T2事务)拥有自己的更改版本.即使T1事务已将A记录从1更改为2,T1事务仍保留原始值1并写入A记录的T1事务版本为2.然后,以下T2事务更改A记录从1到3,而不是从2到4,并写道A记录的T2事务版本是3.

回滚T1事务时,2事件T1事务版本是否未应用于A记录无关紧要.之后,如果T2事务被提交,则3,T2事务版本将应用于A记录.如果T1事务在T2事务之前提交,则A记录更改为2,然后在提交T2事务时更改为3.最终数据库状态与独立执行每个事务的状态相同,对其他事务没有任何影响.因此,它满足ACID属性.此方法称为多版本并发控制(MVCC).

MVCC允许并发修改,代价是增加内存开销(因为它必须维护相同数据的不同版本)和计算(在REPETEABLE_READ级别,您不能丢失更新,因此必须检查数据的版本,如Hiberate与Optimistick Locking合作).

在2PL 事务隔离级别中,控制以下内容:

  • 是否在读取数据时执行锁定以及请求的锁定类型.

  • 读锁的持有时间.

  • 是否读取操作引用由另一个事务修改的行:

    • 阻止,直到释放行上的独占锁定.

    • 检索语句或事务开始时存在的行的已提交版本.

    • 阅读未提交的数据修改.

选择事务隔离级别不会影响为保护数据修改而获取的锁定.事务总是会对其修改的任何数据进行独占锁定,并在事务完成之前保持该锁定,而不管为该事务设置的隔离级别如何.对于读取操作,事务隔离级别主要定义防止其他事务所做修改的影响的级别.

较低的隔离级别会增加许多用户同时访问数据的能力,但会增加用户可能遇到的并发影响的数量,例如脏读或丢失的更新.

SQL Server中锁和隔离级别之间关系的具体示例(使用2PL,READ_COMMEDED_SNAPSHOT = ON时READ_COMMITED除外)

  • READ_UNCOMMITED:不发出共享锁以防止其他事务修改当前事务读取的数据.READ UNCOMMITTED事务也不会被独占锁阻止,这会阻止当前事务读取已被修改但未被其他事务提交的行.[...]

  • READ_COMMITED:

    • 如果READ_COMMITTED_SNAPSHOT设置为OFF(缺省值):使用共享锁来防止其他事务在当前事务运行读操作时修改行.共享锁还会阻止语句读取由其他事务修改的行,直到另一个事务完成为止.[...]在处理下一行之前释放行锁.[...]
    • 如果READ_COMMITTED_SNAPSHOT设置为ON,则数据库引擎使用行版本控制为每个语句显示事件一致的数据快照,因为它存在于语句的开头.锁不用于保护数据免受其他事务的更新.
  • REPETEABLE_READ:共享锁定放在事务中每个语句读取的所有数据上,并保持到事务完成.

  • SERIALIZABLE:范围锁定位于与事务中执行的每个语句的搜索条件匹配的键值范围内.[...]范围锁保持到事务完成.


Goy*_*cky 5

锁定始终在数据库级别进行:-

Oracle 官方文档:- 为避免事务期间发生冲突,DBMS 使用锁,即阻止其他人访问事务正在访问的数据的机制。(请注意,在自动提交模式下,每个语句都是一个事务,只为一个语句持有锁。)设置锁后,它会一直有效,直到事务提交或回滚。例如,DBMS 可以锁定表的一行,直到提交更新。此锁的作用是防止用户进行脏读,即在值变为永久值之前读取该值。(访问尚未提交的更新值被视为脏读,因为该值可能会回滚到其先前的值。如果您读取一个稍后回滚的值,您将读取一个无效值。 )

如何设置锁取决于所谓的事务隔离级别,其范围可以从根本不支持事务到支持执行非常严格的访问规则的事务。

事务隔离级别的一个示例是 TRANSACTION_READ_COMMITTED,它不允许在提交值之前访问该值。换句话说,如果事务隔离级别设置为 TRANSACTION_READ_COMMITTED,则 DBMS 不允许发生脏读。接口 Connection 包括五个值,代表您可以在 JDBC 中使用的事务隔离级别。