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 首先介绍一些乐观锁与悲观锁: 悲观锁:总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每 ...
随机推荐
- 微信小程序:单选框radio和复选框CheckBox
单选框radio: 可以通过color属性来修改颜色. 复选框checkbox:
- Java基本概念:面向对象
一.简介 面向过程的思维模式是简单的线性思维,思考问题首先陷入第一步做什么.第二步做什么的细节中. 面向对象的思维模式说白了就是分类思维模式.思考问题首先会解决问题需要哪些分类,然后对这些分类进行单独 ...
- Python函数注解
目录 函数注解概述 实际应用 inspect模块 业务代码 总结 以下内容基于Python 3x 涉及的知识前提: 建议理解Python装饰器后学习此内容 函数注解概述 函数注解可以针对函数的参数.返 ...
- 后端程序员之路 8、一种内存kv数据库的实现
键值(Key-Value)存储数据库,这是一种NoSQL(非关系型数据库)模型,其数据按照键值对的形式进行组织.索引和存储.KV存储非常适合不涉及过多数据关系业务关系的业务数据,同时能有效减少读写磁盘 ...
- WPF 应用 - 在 web 中启动 exe
以下 F:/Debug/xx.exe 为客户端路径. 1. Web 调用 1.1 IE 内核的浏览器调用方式 js 函数调用如下: var a=new ActiveXObject("Wscr ...
- JS逆向-抠代码的第二天【手把手学会抠代码】
今天的学习项目:沃支付:https://epay.10010.com/auth/login 清空浏览器缓存后,打开网页,输入手机号,密码222222,按照网站要求填入验证码(sorry,我没有账号密码 ...
- Dart简明教程
[前言]Dart语言是使用flutter框架开发时候必备的语言,flutter是一个跨平台的框架,一套代码就可以完美实现安卓和ios两个平台,适配也很不错,Dart语言很友好,和java很类似,学习成 ...
- 如何提高Web应用系统的性能?
随着互联网信息技术的发展,人们逐渐开始习惯在网络上交友.购物.学习.娱乐.工作,甚至是找工作.因此市场对网站的响应速度也提出了新的要求,提高Web应用系统的性能成为急需解决的关键问题.本文将会给出一些 ...
- 我的开源GIS解决方案之路
好久没更新了,因为我在--憋--大--招--,对,就是今天这篇. 今天跟大家分享一下我的开源GIS解决方案经历. --额-- 考虑到单聊技术解决方案你可能会很快睡着,所以我今天会把重点放在我封装地图A ...
- java例题_28 冒泡排序
1 /*28 [程序 28 排序算法] 2 题目:对 10 个数进行排序 3 程序分析:可以利用选择法,即从后 9 个比较过程中,选择一个最小的与第一个元素交换, 下次类推, 4 即用第二个元素与后 ...