时间:2021-07-01 10:21:17 帮助过:41人阅读
2). MySQL事务隔离级别修改
在MySQL数据库中,我们可以分别通过以下两种方式设置事务的隔离级别,分别为:
set [glogal | session] transaction isolation level 隔离级别名称;
或
set tx_isolation=‘隔离级别名称‘;
3). 使用JDBC对设置数据库事务的隔离级别
设置数据库的隔离级别一定要是在开启事务之前。特别地,使用JDBC对数据库的事务设置隔离级别时,我们应该在调用Connection对象的setAutoCommit(false)方法之前调用Connection对象的setTransactionIsolation(level)去设置当前链接的隔离级别如下所示:
至于参数level,可以使用Connection接口的字段,如以下代码所示:
特别地,通过这种方式设置事务隔离级别只对当前链接有效。对于使用MySQL命令窗口而言,一个窗口就相当于一个链接,当前窗口设置的隔离级别只对当前窗口中的事务有效;对于JDBC操作数据库来说,一个Connection对象相当于一个链接,而对于Connection对象设置的隔离级别只对该Connection对象有效,与其他链接Connection对象无关。
也许大家已经听说过,锁分两种,一个叫 悲观锁,一种称之为 乐观锁。事实上,无论是悲观锁还是乐观锁,都是人们定义出来的概念,是一种解决问题的思想。因此,不仅仅在数据库系统中有乐观锁和悲观锁的概念,像memcache、hibernate、tair等都有类似的概念。比如,在线程并发处理中, Synchronized内置锁 就是悲观锁的一种,也称之为 独占锁,加了synchronized关键字的代码基本上就只能以单线程的形式去执行了,它会导致其他需要该资源的线程挂起,直到前面的线程执行完毕释放所资源;而 乐观锁是一种更高效的机制,它的原理就是每次不加锁去执行某项操作,如果发生冲突则失败并重试,直到成功为止,其实本质上不算锁,所以很多地方也称之为 自旋。
在解决数据库的事务并发访问问题时,虽然将事务串形化可以保证数据在多事务并发处理下不存在数据不一致的问题,但串行执行使得数据库的处理性能大幅度地下降,常常是我们接受不了的。所以,一般来说,我们常常结合事务隔离级别和其它并发机制来保证事务的并发,以此来兼顾事务并发的效率与安全性。事实上,大多数数据库的隔离级别都会设置为 Read Committed(只能读取其他事务已提交的数据),然后由应用程序使用乐观锁/悲观锁机制来解决其他事务并发问题,比如不可重复读问题。特别地,乐观并发控制(乐观锁)和悲观并发控制(悲观锁)是并发控制主要采用的技术手段。
特别地,乐观锁的理念是:假设不会发生并发冲突,只在提交操作时检查是否违反数据完整性;而悲观锁的理念是假定会发生并发冲突,屏蔽一切可能违反数据完整性的操作。针对于不同的业务场景,应该选用不同的并发控制方式。所以,不要把乐观并发控制和悲观并发控制狭义的理解为DBMS中的概念,更不要把他们和数据中提供的锁机制(行锁、表锁、排他锁、共享锁)混为一谈。需要指出的是,在DBMS中,悲观锁正是利用数据库本身提供的锁机制来实现的。
Ps:更多关于 synchronized 关键字 的介绍, 请移步我的博文《Java 并发:内置锁 Synchronized》。
1、乐观锁
乐观锁,虽然名字中带“锁”,但是乐观锁并不锁住任何东西,而是在提交事务时检查这条记录是否被其他事务进行了修改:如果没有,则提交;否则,进行回滚。相对于悲观锁,在对数据库进行处理的时候,乐观锁并不会使用数据库提供的锁机制。如果并发的可能性并不大,那么乐观锁定策略带来的性能消耗是非常小的。乐观锁采用的实现方式一般是记录数据版本。
数据版本是为数据增加的一个版本标识。当读取数据时,将版本标识的值一同读出,数据每更新一次同时对版本标识进行更新。当我们提交更新的时候,判断数据库表对应记录的当前版本信息与第一次取出来的版本标识进行比对,如果数据库表当前版本号与第一次取出来的版本标识值相等,则予以更新,否则认为是过期数据。一般地,实现数据版本有两种方式,一种是使用版本号,另一种是使用时间戳。
2、悲观锁
悲观锁,正如其名,它指的是对数据被外界修改持保守(悲观)态度,因此,在整个数据处理过程中,将数据处于锁定状态。悲观锁的实现往往依靠数据库提供的锁机制,也只有数据库层提供的锁机制才能真正保证数据访问的排他性,否则即使在本系统中实现了加锁机制,也无法保证外部系统不会修改数据。悲观并发控制主要用于数据争用激烈的环境,以及发生并发冲突时使用锁保护数据的成本要低于回滚事务的成本的环境中。和乐观锁相比,悲观锁则是一把真正的锁了,它通过SQL语句“select for update”锁住select出的那批数据,这时如果其他事务来更新这批数据时会等待。
悲观并发控制实际上是“先取锁再访问”的保守策略,为数据处理的安全提供了保证。但是在效率方面,处理加锁的机制会让数据库产生额外的开销,还有增加产生死锁的机会;另外,在只读型事务处理中由于不会产生冲突,也没必要使用锁,这样做只能增加系统负载;还有会降低了并行性,一个事务如果锁定了某行数据,其他事务就必须等待该事务处理完才可以处理那行数据。
3、小结
悲观锁和乐观锁都是一种解决并发控制问题的思想。特别地,在数据库并发控制方面,悲观锁与乐观锁有以下几点区别:
思想:在事务并发环境中,乐观锁假设不会发生并发冲突,因此只在提交操作时检查是否违反数据完整性;而悲观锁假定会发生并发冲突,会屏蔽一切可能违反数据完整性的操作。
实现:悲观锁是利用数据库本身提供的锁机制来实现的;而乐观锁则是通过记录数据版本实现的;
应用场景:悲观锁主要用于数据争用激烈的环境或者发生并发冲突时使用锁保护数据的成本要低于回滚事务的成本的环境中;而乐观锁主要应用于并发可能性并不太大、数据竞争不激烈的环境中,这时乐观锁带来的性能消耗是非常小的;
脏读: 乐观锁不能解决脏读问题,而悲观锁则可以。
总的来说,悲观锁相对乐观锁更安全一些,但是开销也更大,甚至可能出现数据库死锁的情况,建议只在乐观锁无法工作时才使用。
更多关于 synchronized 关键字 的介绍, 请移步我的博文《Java 并发:内置锁 Synchronized》。
更多关于 Java 并发编程 方面的内容,请关注我的专栏 《Java 并发编程学习笔记》。本专栏全面记录了Java并发编程的相关知识,并结合操作系统、Java内存模型和相关源码对并发编程的原理、技术、设计、底层实现进行深入分析和总结,并持续跟进并发相关技术。
引用
数据库事务的四大特性以及事务的隔离级别
数据库事务隔离级别
深入理解乐观锁与悲观锁
简述数据库事务并发机制
标签:一致性 相互 logs tle img str mit obj 更新