JDBC_15_悲观锁和乐观锁
悲观锁和乐观锁
并发控制
当程序中可能出现并发操作的情况时,就需要保证在并发操作的情况下数据的准确性,以此确保当前用户和其他用户一起操作时,所得到的结果和某个用户单独操作时的结果是一样的。这种手段就叫做并发控制。并发控制的目的是
保证一个用户的操作不会对另一个用户的操作结果产生不合理的影响。如果没有做好并发控制,就可能导致数据脏读、幻读和不可重复读等问题。
并发控制,一般都和数据库管理系统(DBMS)有关。在 DBMS 中的并发控制的任务,是为了确保在多个事务同时存取数据库中的同一数据时,不破坏事务的隔离性、一致性和数据库的统一性。
实现并发控制的主要手段大致可以分为乐观并发控制 和 悲观并发控制两种。
乐观锁和悲观锁
无论是悲观锁还是乐观锁,都是人们定义出来的概念,可以认为是一种思想。
其实不仅仅是关系型数据库系统中才有乐观锁和悲观锁的概念,像 hibernate、tair、memcache 等都有类似的概念。所以,不应该拿乐观锁、悲观锁和其他的数据库锁等进行对比。
乐观锁比较适用于读多写少的情况(多读场景),悲观锁比较适用于写多读少的情况(多写场景)。
悲观锁(行级锁)(Pessimistic Lock)
当要对数据库中的一条数据进行修改的时候,为了避免同时被其他人修改,最好的办法就是直接对该数据进行加锁以防止并发。这种借助数据库锁机制,在修改数据之前先锁定,再修改的方式被称之为悲观并发控制.
简单来说就是指某些数据被锁住了,事务需要这些数据的话,就必须排队获取,在当前事务结束之前,别的事务根本修改不了锁住的数据,不支持并发操作。
语句:SELECT ENAME ,JOB,SAL FROM EMP WHERE JOB='MANAGER' FOR UPDATE; 在语句后面加了for update就产生了行级锁,所查询出的数据就会被锁住。
在传统的关系型数据库多使用这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作数据之前先上锁。Java 里面的同步 synchronized 关键字的实现。
悲观锁主要分为共享锁和排他锁:
> 共享锁【shared locks】又称为读锁,简称S锁。顾名思义,共享锁就是多个事务对于同一数据可以共享一把锁,都能访问到数据,但是只能读不能修改。 > 排他锁【exclusive locks】又称为写锁,简称X锁。顾名思义,排他锁就是不能与其他锁并存,如果一个事务获取了一个数据行的排他锁,其他事务就不能再获取该行的其他锁,包括共享锁和排他锁,但是获取排他锁的事务可以对数据行读取和修改。
乐观锁(Optimistic Locking)
乐观锁是相对悲观锁而言的,乐观锁假设数据一般情况下不会造成冲突,所以在数据进行提交更新的时候,才会正式对数据的冲突与否进行检测,如果发现冲突了,则返回给用户错误的信息,让用户决定如何去做。乐观锁适用于读操作多的场景,这样可以提
高程序的吞吐量。乐观锁机制采取了更加宽松的加锁机制。乐观锁是相对悲观锁而言,也是为了避免数据库幻读、业务处理时间过长等原因引起数据处理错误的一种机制,但乐观锁不会刻意使用数据库本身的锁机制,而是依据数据本身来保证数据的正确性。
要使用悲观锁,必须关闭 MySQL 数据库的自动提交属性。因为 MySQL 默认使用 autocommit 模式,也就是说,当执行一个更新操作后,MySQL 会立刻将结果进行提交。 (sql语句:set autocommit=0)
乐观锁支持并发操作,事务不需要排队,只需要获取版本号,查看事务获取数据时和提交时的version号是否一致,一致就提交,不一致就不提交。
乐观锁的实现:
1. CAS 实现:Java 中java.util.concurrent.atomic包下面的原子变量使用了乐观锁的一种 CAS 实现方式。 2. 版本号控制:一般是在数据表中加上一个数据版本号 version 字段,表示数据被修改的次数。例如,某条数据version号是1.1, 事务1,和事务2,同时获取同该条数据,事务1先进行了修改,修改后查看版本号还是1.1,然后提交事务,这时事务2
修改了数据,然后再次查看版本号,获取到了version为1.2,和开始获取的不一致,那么事务2就会放弃这次的修改操作,回滚,不提交事务了。
代码模拟演示悲观锁 (事务1查询数据并使用 for update锁住所查询出的数据, 事务2尝试对事物1锁住的数据进行修改)
import com.shige.JDBC.Utils.DBUtil;
import java.sql.*;
/**
* 事物1
* 演示悲观锁(行级锁)
* 该事务进行查询操作,并使用悲观锁,锁住相关数据
*/
public class JDBCTest10 {
public static void main(String[] args) throws SQLException {
//创建数据库连接所需要的对象‘
Connection connection=null;
PreparedStatement preparedStatement=null;
ResultSet resultSet=null;
try {
//获取连接
connection=DBUtil.getConnection();
// 关闭事务自动提交
connection.setAutoCommit(false);
//获取数据库预编译对象
String sql="SELECT ENAME ,JOB,SAL FROM EMP WHERE JOB=? FOR UPDATE";
preparedStatement=connection.prepareStatement(sql);
//给占位符传值
preparedStatement.setString(1,"MANAGER");
//执行SQL
resultSet=preparedStatement.executeQuery();
//处理查询结果集
while(resultSet.next()){
System.out.print(resultSet.getString("ENAME")+" ");
System.out.print(resultSet.getString("JOB")+" ");
System.out.println(resultSet.getString("SAL")+" ");
}
} catch (SQLException e) {
//回滚事务
if(connection!=null){
connection.rollback();
}
e.printStackTrace();
}finally {
//释放资源
DBUtil.close(connection,preparedStatement,resultSet);
}
}
}
// 这是事物2 对事物1锁住的数据进行修改操作。
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* 演示悲观锁(行级锁)
* 该事务进行修改被上个事务锁住的数据
*/
public class JDBCTest11 {
public static void main(String[] args) throws SQLException {
//创建数据库连接所需要的对象‘
Connection connection=null;
PreparedStatement preparedStatement=null;
int count=0;
try {
//获取连接
connection= DBUtil.getConnection();
// 关闭事务自动提交
connection.setAutoCommit(false);
//获取数据库预编译对象
String sql="UPDATE EMP SET SAL=SAL*2 WHERE JOB=?";
preparedStatement=connection.prepareStatement(sql);
//给占位符传值
preparedStatement.setString(1,"MANAGER");
//执行SQL
count=preparedStatement.executeUpdate();
//输出
System.out.println(count==3?"修改成功":"修改失败");
//手动提交事务
connection.commit();
} catch (SQLException e) {
//回滚事务
if(connection!=null){
connection.rollback();
}
e.printStackTrace();
}finally {
//释放资源
DBUtil.close(connection,preparedStatement,null);
}
}
}
JDBC_15_悲观锁和乐观锁的更多相关文章
- mysql-mysql悲观锁和乐观锁
1.mysql的四种事务隔离级别 I. 对于同时运行多个事务,当这些事务访问数据库中的相同数据时,如果没有采取必要的隔离机制,就会导致各种并发问题. (1)脏读: 对于两个事物 T1, T2, T1 ...
- Hibernate解决高并发问题之:悲观锁 VS 乐观锁
高并发问题是程序设计所必须要解决的问题,解决此类问题最主要的途径就是对对程序进行加锁控制.hibernate对加锁机制同样做出了实现,常用加锁方式为悲观锁和乐观锁.悲观锁指的是对数据被外界(包括本系统 ...
- mysql的锁--行锁,表锁,乐观锁,悲观锁
一 引言--为什么mysql提供了锁 最近看到了mysql有行锁和表锁两个概念,越想越疑惑.为什么mysql要提供锁机制,而且这种机制不是一个摆设,还有很多人在用.在现代数据库里几乎有事务机制,aci ...
- Oracle数据库悲观锁与乐观锁详解
数据的锁定分为两种方法,第一种叫做悲观锁,第二种叫做乐观锁.什么叫悲观锁呢,悲观锁顾名思义,就是对数据的冲突采取一种悲观的态度,也就是说假设数据肯定会冲突,所以在数据开始读取的时候就把数据锁定住.而乐 ...
- 025 hibernate悲观锁、乐观锁
Hibernate谈到悲观锁.乐观锁,就要谈到数据库的并发问题,数据库的隔离级别越高它的并发性就越差 并发性:当前系统进行了序列化后,当前读取数据后,别人查询不了,看不了.称为并发性不好 数据库隔离级 ...
- Mysql锁机制--乐观锁 & 悲观锁
Mysql 系列文章主页 =============== 从 这篇 文章中,我们知道 Mysql 并发事务会引起更新丢失问题,解决办法是锁.所以本文将对锁(乐观锁.悲观锁)进行分析. 第一部分 悲观锁 ...
- Mysql共享锁、排他锁、悲观锁、乐观锁及其使用场景
一.相关名词 |--表级锁(锁定整个表) |--页级锁(锁定一页) |--行级锁(锁定一行) |--共享锁(S锁,MyISAM 叫做读锁) |--排他锁(X锁,MyISAM 叫做写锁) |--悲观锁( ...
- MySQL学习笔记(四)悲观锁与乐观锁
恼骚 最近在搞并发的问题,订单的异步通知和主动查询会存在并发的问题,用到了Mysql数据库的 for update 锁 在TP5直接通过lock(true),用于数据库的锁机制 Db::name('p ...
- 多线程深入:乐观锁与悲观锁以及乐观锁的一种实现方式-CAS(转)
原文:https://www.cnblogs.com/qjjazry/p/6581568.html 首先介绍一些乐观锁与悲观锁: 悲观锁:总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每 ...
随机推荐
- AForge实现拍照
记得先引用DLL private FilterInfoCollection videoDevices; private VideoCaptureDevice videoSource; BLL.AWBL ...
- 【Azure 应用服务】App Service与APIM同时集成到同一个虚拟网络后,如何通过内网访问内部VNET的APIM呢?
问题描述 App Service访问的APIM已配置内部虚拟网络(Internal VNet)并拥有内网IP地址.App Service与APIM都在相同的虚拟网络(VNET)中.App Servic ...
- [计算机图形学]Blinn-Phong光照模型
目录 一.前言 二.原理 三.代码 一.前言 Blinn-Phong光照模型以Phong模型为基础的,提供比Phong更柔和.更平滑的高光,而且由于Blinn-Phong的光照模型省去了计算反射光线的 ...
- Qt update刷新之源码分析(二)
大家好,我是IT文艺男,来自一线大厂的一线程序员 上次视频给大家从源码层面剖析了Qt update刷新机制的异步事件投递过程,这次视频主要从源码层面剖析Qt刷新事件(QEvent::UpdateReq ...
- Wayland architecture
Introduction Motivation Most Linux and Unix-based systems rely on the X Window System (or simply X) ...
- JVM之类加载器子系统
类加载器子系统 作用 负责从文件系统或网络系统中加载class文件,class文件在开头有特殊的标记(魔术开头CA FE BA BE) ClassLoader只负责加载class文件,至于能否运行,由 ...
- 【Azure Redis 缓存】Azure Redis 功能性讨论二
继承上一次讨论了Azure Redis的可用性,可靠性,稳定性,安全性,监控方面的九大功能点.详情可回顾文章:[Azure Redis 缓存]Azure Redis功能性讨论 这次我们继续讨论Azur ...
- vue封装一个弹框组件
这是一个提示框和对话框,例: 这是一个组件 eject.vue <template> <div class='kz-cont' v-show='showstate'> &l ...
- CCF(公共钥匙盒):思维+模拟
公共钥匙盒 201709-2 这题的思路一开始不是很清晰,一开始想用贪心去做.但是发现按照题目的思路不对.所以这里采用的是类似于多项式的加减的处理. #include<iostream> ...
- 【Arduino学习笔记05】Arduino数字输入、输出和脉冲宽带调制 -- 小项目:彩色小台灯
基本功能: 长按控制按钮开机,长按控制按钮关机(>3s) 通过三个调节按钮调节灯的颜色,每一个按钮分别对应R,G,B值 模式切换:短按控制按钮切换模式(长亮模式/闪烁模式) 元器件清单: Ard ...