精华内容
下载资源
问答
  • java乐观锁实现-springboot的数据库更新时遇到并发问题遇到的问题什么叫线程安全?参考资料 遇到的问题 有一个安全扫描的项目需要调用其他业务单位的扫描结果,报告结果需要在数据库进行三次更新同一字段。并发高的...


    遇到的问题

    有一个安全扫描的项目需要调用其他业务单位的扫描结果,报告结果需要在数据库进行三次更新同一字段。并发高的时候,可能第二条更新数据覆盖了第一条的更新数据(第一条更新了以后,第二条覆盖了第一条的更新)。

    解决方案

    实体类增加一个version字段和@version的注释

    1. @version
      使用的是spring data jpa的注解,只适合自动生成的sql(jpa自带的save方法)。
      实际达到的效果是每当实体类有字段更新时,对version字段进行校验,如果version不一致则失败,如果一致则更新数据库的同时version也加一。
     update xxx,version+1  where xxxx and version=x
    
    1. 测试
      使用@async注释模拟线程池,更新100次,发现500ms都能成功(相当于同步)50ms左右可以大多数成功(并发少),20ms及以下几乎只有两三次成功(并发多)。
    2. 未解决的问题
      当前只防止了并发的问题,并未达到数据更新失败后重试的效果。

    知识点拓展

    线程安全

    1. 什么是线程安全?
      就是线程同步的意思,就是当一个程序对一个线程安全的方法或者语句进行访问的时候,其他的不能再对他进行操作了,必须等到这次访问结束以后才能对这个线程安全的方法进行访问。
    2. java的自增和自减都是非线程安全的
      为什么呢?
      i++操作分为三步:保存当前值,执行自增操作,更新新值。多线程操作时,可能会同时获取到旧值(假设为1),添加操作后为2,第2个线程刷新新值为3,第3个线程刷新还是3。

    乐观锁和悲观锁

    1. 悲观锁
      什么是悲观锁?
      假设最坏情况,默认每次读取数据时都有其他线程更改数据,因此对数据库进行加锁(共享锁和排它锁)。
      为什么不用悲观锁?
      数据库加锁会增加死锁的机会,降低并发性。
    2. 乐观锁
      乐观锁概念和使用场景
      乐观锁假设一般不会产生冲突,在对数据进行更新和提交时,检测是否存在冲突,如冲突了返回给用户错误信息。乐观锁适用于读多写少的场景。
      乐观锁的实现方式
      两个步骤:冲突检测和数据更新。一个方法是CAS(sun.misc.Unsafe 类提供了硬件级别的原子操作来实现这个 CAS。java.util.concurrent包下大量的类都使用了这个 Unsafe.java 类的 CAS 操作),另一种方法是增加版本号(我就是用的这个方法)。

    使用@Asnyc注解模拟并发

    模拟线程池

    1. 无返回值的异步
      直接使用,方法上加注解
    2. 有返回值的异步
      使用future接受获取使用AsyncResult返回的结果。
      AsyncResult类实现了ListenableFuture接口,ListenableFuture实现了Future接口。

    参考资料

    1. https://www.cnblogs.com/duende99/p/7047067.html
    2. https://blog.csdn.net/u012326462/article/details/81349157
    3. https://www.jianshu.com/p/d2ac26ca6525
    4. https://www.jianshu.com/p/d2ac26ca6525
    5. https://blog.csdn.net/weixin_38446891/article/details/107780867
    展开全文
  • 初识数据库

    2019-01-15 19:41:00
    一、什么数据库: 一个专门管理数据的软件.特点是:管理数据便捷,高效,安全,支持高并发. 数据库专业的名字:数据库管理系统(英语:Database Management System,简称DBMS)我们平常讲的mysql是数据库的一种 ...

    一、什么是数据库:

    一个专门管理数据的软件.特点是:管理数据便捷,高效,安全,支持高并发.
    
    数据库专业的名字叫:数据库管理系统(英语:Database Management System,简称DBMS)我们平常讲的mysql是数据库的一种
    
    数据库现在主流两个大类:
    关系型数据库(RDBMS):
        关系型数据库模型是把复杂的数据结构归结为简单的二元关系(mysql就是关系型数据库,是一款基于CS架构的软件).操作关系型数据库的命令,我们称之为SQL.不同数据库系统之间的SQL不能完全相互通用
    非关系型数据库
    注意: 数据库里面的指令必须要用;分号结尾,然后才能执行
    一些简单语法介绍:
    1.开启服务端,mysqld\ net start mysql 2.使用mysql自带的客户端进行连接,cmd下输入mysql -u root -p,然后回车,会提示你输入密码,此时初始的root用户还没有密码,所以还是直接回车就可以连接上了 3.show databases;先不讲里面的内容,说一下这是几个库,每个项目可以有自己单独的一个库,里面放这个项目的所有数据表 4.创建一个库:create database CRM;然后show databases;查看一下就有了这个crm库,不分大小写,统一会变成小写,对照着我们mysql安装目录下的data文件夹里面的内容看一下,库就是对应的文件夹。 5.我们目前在所有数据库之上,想在我们自己项目的库里面操作数据,就需要切换到我们自己这个crm项目的库里面进行数据的操作,切换数据库使用use + 库名,例如:use crm;就提示你切换成功了。 6.我们说过,库里面维护的数据就像一张一张的数据表,类似excel,对不对,那我们创建一张表看一下,命令:   create table student(           id int,           name char(10),           age int,); 7.再执行show tables;就可以看到有了一个student表 8.查看一下这个表里的数据select * from student;发现什么数据也没有

    二、mysql文件介绍:

     

    重点看一下data文件夹:如果你找不到自己建立的库或者表的文件,可能不在这个data文件夹下面,连接上mysql之后,输入show global variables like "%datadir%";
    来查看数据文件存储路径,找到路径之后,到对应路径下如果找不到这个文件夹,那么可能是隐藏的,把隐藏的文件显示一下就行了。

     

    三、设置密码和忘记密码的解决方案

    方法1: 用SET PASSWORD命令 
    首先登录MySQL,使用mysql自带的那个客户端连接上mysql。 
        格式:mysql> set password for 用户名@localhost = password('新密码'); 
        例子:mysql> set password for root@localhost = password('123'); 
    方法2:用mysqladmin  (因为我们将bin已经添加到环境变量了,这个mysqladmin也在bin目录下,所以可以直接使用这个mysqladmin功能,使用它来修改密码)
    关于mysqladmin的介绍:是一个执行管理操作的客户端程序。它可以用来检查服务器的配置和当前状态、创建和删除数据库、修改用户密码等等的功能,
    格式:mysqladmin
    -u用户名 -p旧密码 password 新密码 例子:mysqladmin -uroot -p123456 password 123
    注意:
    只用mysqladmin的时候,会出现一个warning警告信息:Warning: Using a password on the command line interface can be insecure.,这个没关系,是提示你,
    你直接在cmd下使用明文设置密码的时候,是不安全的,因为别人可以通过翻看你输入指令的历史记录来查看到你设置的密码,所以提示你一下,不信你按上下键,
    可以看到自己之前输入的命令.所以我们最好连接进入到mysql里面之后,再进行密码的修改和设置
    方法3:用UPDATE直接编辑那个自动的mysql库中的user表 
    1.首先登录MySQL,连接上mysql服务端。 
    2.mysql> use mysql;   #use mysql的意思是切换到mysql这个库,这个库是所有的用户表和权限相关的表都在这个库里面,我们进入到这个库才能修改这个库里面的表。
    3.mysql> update user set password=password('123') where user='root' and host='localhost';   #其中password=password('123') 前面的password是变量,
    后面的password是mysql提供的给密码加密用的,我们最好不要明文的存密码,其中user是一个表,存着所有的mysql用户的信息。 4.mysql
    > flush privileges; 刷新权限,让其生效,否则不生效,修改不成功。

    忘记密码解决方案:(链接有具体实例)

    cd转到mysqll\bin目录,输入mysql --skip-grant-tables 跳过认证表来启动mysql 服务端,这样在链接的时候就不需要输入密码了,直接输入一个mysql一个回车就行了,然后到里面取修改密码.

     

    1 https://www.cnblogs.com/clschao/articles/9907529.html#part_4
    忘记mysql后如何重置密码

     四、设置字符集编码和设置快捷登陆操作

    为什么要统一字符集编码:
      为了读取和写入数据时不产生乱码.(系统的编码、客户端、服务端、库、表、列,这几项的编码都要统一才不会出现乱码的情况)
    第一种方法:在插入数据之前,先执行一条指令:set names latin1;临时修改客户端字符集,让客户端插入数据的时候按照服务端的字符集编码来插入数据. 第二种方法:在配置文件里面修改客户端和服务端参数,可以实现set names latin1;的效果,并且永久生效   
    1.修改配置文件my.ini文件(win10,unix叫做my.cnf),这个文件是mysql启动的时候加载的一些用户自定制配置的文件   2.首先在安装目录下创建一个my.ini文件(copy一份my-default.ini文件,改名为my.ini文件),使用Notepad++打开,里面写上下面的内容,保存.

    我们在我们创建的my.ini文件中写上下面几行,然后保存:       
    
    [mysql]   #配置客户端连接的时候,指定一下用户名和密码,那么我们在进行mysql客户端连接的时候,直接输入mysql然后回车就可以了,并且用户是我们下面指定的root用户
    user=root
    password=666
    #针对客户端命令的全局配置,当mysql客户端命令执行时,下列配置生效
    [client]
    default-character-set=utf8
    #只针对mysql这个客户端的配置,3中的是全局配置,而此处的则是只针对mysql这个命令的局部配置
    [mysql]
    user=root
    password=222
    default-character-set=utf8
    #-----------------------------------------------------------------------------
    然后重启mysql服务,让配置文件生效:
    C:\WINDOWS\system32>net stop mysql
    C:\WINDOWS\system32>net start mysql
     

     五、数据库指令:

    SQL语句主要是针对数据库里面三个角色进行操作,对象是:库、表、行,操作包括:增删改查。
    1.库(data文件夹中的文件夹,每创建一个库,这个库的名称就是文件夹的名称,文件夹里面保存着一些这个库相关的初始信息)
    增:create database db1 charset utf8; #创建一个库,可以指定字符集       
    查:show databases; #查看数据库中所有的库
        show create database db1; #查看单独某个库db1的信息       
    改:alter database db1 charset latin1; #修改库的字符集,注意语句的格式(其他语句也是这么个格式),alter(修改)database(修改数据库)
        db1(哪个数据库)charset(字符集)latin1(改成哪个字符集)       
    删除: drop database db1; #删除数据库
    
    2、表(操作文件,表是上面库文件夹里面的文件)
    先切换库:use db1; #要操作表文件,要先切换到对应的库下才能操作表
      查看当前所在的是哪个库:select database();
    增:create table t1(id int,name char(10) )
    
    3. 行(操作文件(表)中的内容/记录)(*****将来的重中之重)
    增:insert into t1 values(1,'dsb1'),(2,'dsb2'),(3,'dsb3'); #往t1表中插入三行数据,注意你插入的每行内容都要和你创建表的时候的字段个数和字段属性对应好,注意每行数据以逗号分隔。
      insert后面的into可以不用写。
    查:select * from t1; #查看t1表中所有字段的数据,select 字段 from 表。
        select id,name from t1;#查看t1表中的id和name列的数据,其他的不看,注意格式,每个字段逗号分隔,在cmd窗口下只是展示给我们看,将来我们通过程序获取查询数据的时候,
    就可以这么获取,查询字段的顺序也是可以颠倒的,name,id这样也是可以的
    改:update t1 set name='sb' where id=2; #把id为2的行(记录)中的name字段的数据改为sb;id>1;id<=1;等等都可以。后面会细讲的~~~
      update t1 set name='sb',id=88 where id>2; #对两个字段进行修改
      update t1 set name='sb';#如果不指定where,那么会name字段的所有数据都改成sb。
    删:delete from t1 where id=1; #删除id为1的行
    清空表:
      delete from t1; #如果有自增id,新增的数据,仍然是以删除前的最后一样作为起始。
      truncate table t1;数据量大,删除速度比上一条快,且直接从零开始,
      auto_increment 表示:自增
      primary key 表示:约束(不能重复且不能为空);加速查找
    \c #可以清除之前输入的错误指令
    在创建表的时候,我们去看一下mysql安装目录里面的data文件夹里面的db1文件夹里面的文件,然后我们执行创建表的指令,看看db1文件夹里面的变化,多了两个文件,
    分别是:db1.frm,db1.ibd文件,创建了一张表为什么会多了两个文件呢,这两个文件都是啥呢?

     

    1 1.后缀名为.frm的文件:这个文件主要是用来描述数据表结构(id,name字段等)和字段长度等信息
    2 2.后缀名为.ibd的文件:这个文件主要储存的是采用独立表储存模式时储存数据库的数据信息和索引信息;
    3 3.后缀名为.MYD(MYData)的文件:从名字可以看出,这个是存储数据库数据信息的文件,主要是存储采用独立表储存模式时存储的数据信息;
    4 4.后缀名为.MYI的文件:这个文件主要储存的是数据库的索引信息;
    5 5.ibdata1文件:主要作用也是储存数据信息和索引信息,这个文件在mysql安装目录的data文件夹下。
    6     从上面可以看出,.ibd储存的是数据信息和索引信息,ibdata1文件也是存储数据信息和索引信息,.MYD和.MYI也是分别储存数据信息和索引信息,那他们之间有什么区别呢? 
    7     主要区别是再于数据库的存储引擎不一样,如果储存引擎采用的是MyISAM,则生成的数据文件为表名.frm、表名.MYD、表名的MYI;而储存引擎如果是innoDB,开启了innodb_file_per_table=1,也就是采用独立储存的模式,生成的文件是表名.frm、表名.ibd,如果采用共存储模式的,数据信息和索引信息都存储在ibdata1中; 
    表文件的后缀名解释

    六、永久设置以管理员身份运行cmd窗口

    1、创建“cmd.exe”快捷方式: 
    2、右击选择“属性”,选择“快捷方式”,再选择“高级”,在选择“以管理员身份运行”,
    再单击“确定”。 

     ------------------------------------------------------- -------------------------------------------------------

    其他零碎补充

    关于pycharm里用pip 删除下载的内容

    指令: pip uninstall  pymysq(删除的内容)

    转载于:https://www.cnblogs.com/lgw1171435560/p/10273915.html

    展开全文
  • 数据库的事务机制

    千次阅读 2017-10-01 13:45:42
    什么需要事务,并发访问数据会造成什么问题 事务的ACID原则 事务的隔离级别 数据库的锁机制 为什么需要锁,存在哪些锁 悲观锁 数据库的悲观锁有两种实现方式:共享锁和排它锁,根据锁的范围又有行级锁和表级...

    1. 数据库的事务机制

    1.1 为什么需要事务

    在实际中存在并发访问数据的问题,比如当A在查询数据库里的某条记录时,同一时刻B对这条记录进行了修改,那么A就有可能读取到有问题的脏数据。数据库的事务机制,就是为了解决并发访问所产生的问题。

    事务的基本操作:
    1. 开启一个事务
    2. 进行一系列的数据操作
    3. 提交或回滚事务,提交成功则将数据持久化到数据库,否则该事务中的所有数据操作全部无效

    1.2 事务的ACID原则

    事务具备四个特性:原子性、一致性、隔离性、持久性(ACID原则)

    原子性(Atomic)

    一个事务内的所有操作都是原子性的,要么全部成功,要么全部失败

    一致性(Consistency)

    在完成一个事务操作后应该使数据库从一个一致性状态达到另一个一致性状态,比如在转账功能中,A转账给B一百元,那么B的账号增加一百元,而A的账号也应该减少一百元。

    一致性可以说是ACID原则中最基础的特性,其他三个特性都是为了保证一致性而存在的。关于数据库的一致性更加具体的说明可以参考知乎的该问答

    隔离性(Isolation)

    不同事务之间的操作互不影响,数据库对于事务存在着不同的隔离级别,详情请见下文。

    持久性(Durability)

    事务的操作一旦完成,必须持久化到数据库中。

    1.3 并发访问数据会造成什么问题

    并发访问数据会出现三种情况:脏读、不可重复读、幻读。

    脏读(Dirty Read)

    当事务A在修改(insert、delete、update)记录但还未提交时,另一个事务B读取了该记录,此时事务B读到的数据就是脏数据,如果此时事务A回滚了事务,则事务B读到的数据无效。

    不可重复读(Non-repeatable Read)

    当事务A在读取记录时,另一个事务B修改(delete、update)了该记录并提交,此时事务A再一次读取该记录会读取到被事务B修改后的数据。在一个事务中前后两次读取的数据不一样,因此被称作不可重复读。

    幻读(Phantom Read)

    当事务A在读取记录时,另一个事务B插入(insert)了新记录并提交,导致事务A再次查询记录时多出了原本不存在的记录,就像看到了幻觉一样,所以被称作幻读。

    1.4 事务的隔离级别

    事务的隔离级别描述了事务被隔离的程度,其隔离级别有4个,由低到高依次为Read Uncommitted 、Read Committed 、Repeatable Read 、Serializable。通过设置不同的事务隔离级别可以解决脏读、不可重复读和幻读。

    读未提交(Read Uncommitted)

    在该隔离级别,所有事务都可以看到其他未提交事务的执行结果。在实际中很少使用这种隔离级别,其性能并没有比其他隔离级别好多少,且会发生脏读、不可重复读和幻读。

    读提交(Read Committed)

    在该隔离级别,所有事务都只能看到其他已经提交的事务的执行结果。这是大多数数据库系统的默认隔离级别(MySQL默认的是可重复读),在该隔离级别会发生不可重复读和幻读。

    可重复读(Repeatable Read)

    这是MySQL默认的事务隔离级别,该隔离级别虽然解决了脏读和不可重复读,但还是无法避免幻读。

    可串行化(Serializable)

    最高级别的事务隔离级别,通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。但是系统开销花费最高,性能很低,一般很少使用。

    • √表示发生,×表示不会发生
    脏读 可重复读 幻读
    读未提交
    读提交 ×
    可重复读 × ×
    可串行化 × × ×

    1.5 如何查询并设置数据库中的事务隔离级别

    1.5.1 MySQL

    MySQL支持四种事务隔离级别,默认的事务隔离级别是Repeatable Read

    查询事务隔离级别

    //查询下一个(未开启)事务的隔离级别
    select @@tx_isolation;
    //查询当前会话事务的隔离级别
    select @@session.tx_isolation;
    //查询全局事务的隔离级别
    select @@global.tx_isolation;
    

    修改事务隔离级别

    set [SESSION | GLOBAL] transaction isolation level {READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE}
    

    如果不添加session或者global,则是为下一个(未开启)事务设置隔离级别,比如

    //为下一个(未开启)事务设置read uncommitted隔离级别
    set transaction isolation level read uncommitted
    

    如果添加了session关键字则表示为当前连接上执行的事务设置默认的隔离级别;如果添加了global关键字则表示在全局为所有新创建的连接上执行的事务设置默认的隔离级别

    还可以使用另一种方式来设置隔离级别

    set @@tx_isolation = 'read-committed';
    set @@session.tx_isolation = 'repeatable-read';
    set @@global.tx_isolation = 'read-uncommitted';
    

    1.5.2 Oracle

    Oracle只支持两种事务隔离级别Read Committed和Serializable,所以Oracle不支持脏读。Read Only是Serializable的子集,两者都避免了不可重复读和幻读,区别是Read Only不允许在事务中进行DML操作,而Serializable可以。Oracle的默认事务隔离级别是Read Committed。

    设置事务隔离级别

    SET TRANSACTION ISOLATION LEVEL [READ COMMITED | SERIALIZABLE | READ ONLY];
    

    设置一个会话的隔离级别

    ALTER SESSION SET ISOLATION_LEVEL [READ COMMITTED| SERIALIZABLE];
    

    事务的隔离级别和锁机制的关系

    为了维护数据库事务的ACID四大特性,数据库一般使用加锁这种方式。事务隔离级别是为了有效保证并发读取数据的正确性,而数据库的锁机制,则是为了构建这些隔离级别而存在的。

    关于数据库的锁机制,可以参考这篇文章

    展开全文
  • 数据库的锁机制

    2017-10-02 13:54:03
    什么需要锁机制事务是并发控制的基本单位,保证事务ACID原则是事务处理的重要任务,但是当多个事务对数据库进行并发操作时,就有可能破坏事务的ACID特性。为了保证事务的隔离性与一致性,就有了数据库的锁机制。在...

    为什么需要锁机制

    事务是并发控制的基本单位,保证事务ACID原则是事务处理的重要任务,但是当多个事务对数据库进行并发操作时,就有可能破坏事务的ACID特性。

    为了保证事务的隔离性与一致性,就有了数据库的锁机制。

    在数据库中,存在着很多种类的锁:共享锁、排他锁、悲观锁、乐观锁、行级锁、表级锁等。

    基本的锁类型

    锁有两种基本的类型:共享锁、排他锁

    共享锁(Share Locks,简称S锁,也叫读锁)

    若事务T对数据对象A加上S锁,则事务T只能读取A而不能修改A,其他事务也只能对该数据对象A加上S锁,而不能加上X锁,直到事务T释放A上的S锁。

    即是说,共享锁只允许多个事务读取数据,而不允许修改数据。

    排他锁(Exclusive Locks,简称X锁,也叫写锁)

    若事务T对数据对象A加上X锁,则只允许事务T对A进行读取和修改,其他事务都不能对A加上任何类型的锁,直到事务T释放A上的X锁。

    即是说,排他锁只允许一个事务读取和修改被锁定的数据。

    锁会带来什么问题

    给数据加锁可能会引起活锁和死锁的问题。

    活锁

    如果事务T1封锁了数据对象R,事务T2也请求封锁R,于是T2等待。T3也请求封锁R,当T1释放了R上的锁后系统首先批准了T3的请求,于是T2仍然等待。然后T4也请求封锁R,当T3释放了R上的锁后系统又批准了T4的请求,于是T2仍然等待……

    在这个过程中,T2可能会永远在等待,这就是活锁。

    避免活锁的简单方法就是采用先来先到的策略,当多个事务请求封锁同一数据对象的时候,封锁子系统按请求封锁的先后次序对事务进行排队,数据对象上的锁一旦释放,就批准申请队列中第一个事务获得锁。

    死锁

    如果事务T1封锁了数据R1,事务T2封锁了数据R2,然后T1请求封锁R2,由于R2已经被T2封锁,所以T1等待T2释放R2上的锁;接着T2也请求封锁R1,由于R1已经被T1封锁,所以T2等待T1释放R1上的锁。

    这样就出现了两个事务互相等待的局面,这两个事务永远也不能结束,形成了死锁。

    数据库一般允许发生死锁,并采用一定手段定期诊断系统中有无死锁,若有则解除之。一般采用超时法或事务等待图法来诊断死锁。

    • 超时法

    如果一个事务等待的时间超过了规定的时限,就认为发生了死锁。超时法实现简单,但有可能发生误判死锁,事务因为其他原因使等待时间超过了时限导致被系统误认为发生了死锁;如果时限设置得太长,也可能无法及时发现死锁。

    • 事务等待图法

    事物等待图是一个有向图G=(T,U)。T为结点的集合,每个结点表示正运行的事务;U为边的集合,每条边表示事务等待的情况。若T1等待T2,则T1、T2之间画一条有向边,从T1指向T2。

    事务等待图动态地反映了所有事务的等待情况,并发控制子系统周期性地生成事务等待图,并进行检测。如果发现图中存在回路,则表示系统中发生了死锁。

    死锁的情况可以多种多样,如下图所示,在大回路中又有小回路。

    事物等待图

    如何解除死锁

    当DBMS检测到系统中存在死锁,就要设法解除。通常采用的做法是选择一个处理死锁代价最小的事务,将其撤销,释放此事务持有的锁,使其他事务得以运行下去。解除死锁之后,被撤销的事务所执行的数据操作必须加以恢复。

    锁的粒度

    锁的粒度就是锁的作用范围,一般分为行级锁、表级锁。行级锁锁定记录行,表级锁锁定整个表。

    行级锁

    系统开销大,加锁慢,锁定粒度最小,会发生死锁,但是发生冲突的概率最低,并发性最高

    表级锁

    系统开销小,加锁快,锁定粒度最大,不会发生死锁,但是发生冲突的概率最高,并发性最低

    总结

    • 共享锁只用于表级,排它锁用于行级或表级。
    • 加了共享锁的对象,可以继续加共享锁,不能再加排他锁。
    • 加了排他锁的对象,不能再加任何锁。

    悲观锁(Pessimistic Lock)

    顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。

    它指的是对数据被外界(包括本系统当前的其他事务,以及来自外部系统的事务处理)修改持保守态度,因此,在整个数据处理过程中,将数据处于锁定状态。

    悲观锁的实现,往往依靠数据库提供的锁机制(也只有数据库层提供的锁机制才能真正保证数据访问的排他性,否则,即使在本系统中实现了加锁机制,也无法保证外部系统不会修改数据)。

    乐观锁(Optimistic Lock)

    顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据。

    乐观锁适用于多读的应用类型,即冲突真的很少发生的时候,这样可以提高吞吐量。但如果经常产生冲突,上层应用会不断的进行retry,这样反倒会降低性能,所以这种情况下用悲观锁就比较合适。

    乐观锁与悲观锁不同的是,它是一种逻辑上的锁,而不需要数据库提供锁机制来支持,它需要我们自己在程序中实现。乐观锁的实现,一般是通过数据版本version或者时间戳来实现。

    数据版本version(版本戳)

    在需要乐观锁的表中添加一个version字段,每修改一次数据就将version+1。每次对数据进行操作时先读出当前的数据版本,如果要对数据进行修改就先判断此时的version是否与之前查询到的version一致,如果version一样说明在这期间没有其他人修改这条数据,则可以执行此次更新操作并更新版本号;如果version不一致,则意味着冲突,不执行此次更新。

    代码实现例子:

    查询当前商品信息:
    select name,num,version from products where id = #{id};

    执行更新商品操作:
    update products set num = num - 1, version = version + 1 where id = #{id} and version = #{version};

    时间戳timestamp

    和version类似,每操作一次数据就修改时间戳;在进行更新操作时需要先判断当前时间戳是否与之前查询到的时间戳一致。

    总结

    通常情况下,写操作较少时,使用乐观锁,写操作较多时,使用悲观锁。除了自己手动实现乐观锁之外,有的持久层框架已经封装好了乐观锁的实现。比如Hibernate就提供了以数据版本实现的乐观锁机制。

    展开全文
  • 目录一、什么是事务二、事务的四个特性(ACID)1. 原子性(Atomicity)2. 一致性(Consistency)3. 隔离性(Isolation)4. 持久性(Durability)三、隔离级别和并发问题1.丢失更新2.脏读3.幻读(phantom read,也虚...
  • 数据库原理

    2019-05-08 17:16:54
    什么叫事务 通俗点说:一组要么完全执行,要么完全不执行的SQL语句,用来维护数据库的完整性。 事务与并发 并发下,事务会产生问题: 丢失修改、脏读、不可重复读、幻影读 事务的隔离级别 并发下事务会产生问题,...
  • 数据库-MVCC

    2020-10-13 10:24:26
    MVCC (Multiversion Concurrency Control) 中文全称多版本并发控制,是现代数据库(包括 MySQL、Oracle、PostgreSQL 等)引擎实现中常用的处理读写冲突的手段,目的在于提高数据库并发场景下的吞吐性能。...
  • 什么叫MVCC

    2019-08-28 00:37:02
    MVCC 并发控制下的读事务一般使用时间戳或者事务 ID去标记当前读的数据库的状态(版本),读取这个版本的数据。读、写事务相互隔离,不需要加锁。读写并存的时候,写操作会根据目前数据库的状态,创建一个新版本,...
  • 若尺寸没达标的公蟹会重新放到大海里,邪恶的美国你为什么这么强大、我愿意当个幸福的母蟹、但是千万不要把我生在邪恶的东海,曾经从来没想移民的愿望,看了这期探险节目后,更加懂了什么叫爱护环境爱护地球了。...
  • 数据库悲观锁和乐观锁 一下是转载的oracle和Mysql两种数据库悲观锁和乐观锁机制及乐观锁实现方式: 一、Oracle Oracle数据库悲观锁与乐观锁是本文我们主要要介绍的内容。有时候为了得到最大的性能,...什么叫悲...
  • 数据库基础(Mysql)

    2020-10-11 20:21:43
    1 什么数据库 数据库(Database)就是按照数据结构来组织,存储和管理数据的仓库。专业的数据库是专门对数据进行创建,访问,管理,搜索等操作的软件,比起我们自己用文件读写的方式对数据进行管理更加的方便,快速...
  • Redis (NoSql数据库)

    2018-04-18 12:47:40
    1.1 什么是NoSql数据库 为了解决高并发、高可用、高可扩展,大数据存储等一系列问题而产生的数据库解决方案,就是NoSql。 NoSql,非关系型数据库,它的全名Not only sql。它不能替代关系型数据库,只能作为关系型...
  • 数据库锁与事物

    2018-05-21 10:42:50
    事务并发控制我们从另外一个方向来说说,如果不对事务进行并发控制,我们看看数据库并发操作是会有那些异常情形,有些使我们可以接受的,有些是不能接受的,注意这里的异常就是特定语境下的,并不一定就是错误什么的...
  • 数据库悲观锁和乐观锁使用Mybatis

    千次阅读 2018-10-16 14:46:43
    以下是转载的oracle和Mysql两种数据库悲观锁和乐观锁机制及乐观锁实现方式: 一、Oracle Oracle数据库悲观锁与乐观锁是本文我们主要要介绍的内容。有时候为了得到最大的性能,...什么叫悲观锁呢,悲观锁顾名思义,...
  • 什么叫数据?描述事件的符号记录。只要在计算机存下来的就是数据。 数据库(database DB)永久存储、有组织、可共享的大量数据集合。 数据库管理系统(Database Management System DBMS)数据库管理软件。 1、提供...
  • Oracle数据库悲观锁与乐观锁是本文我们主要要介绍的内容。...什么叫悲观锁呢,悲观锁顾名思义,就是对数据的冲突采取一种悲观的态度,也就是说假设数据肯定会冲突,所以在数据开始读取的时候就把数据锁定住。而...
  • Oracle数据库悲观锁与乐观锁是我们主要介绍的内容。...什么叫悲观锁呢,悲观锁顾名思义,就是对数据的冲突采取一种悲观的态度,也就是说假设数据肯定会冲突,所以在数据开始读取的时候就把数据锁定住。而乐观锁就...

空空如也

空空如也

1 2 3 4 5 ... 13
收藏数 253
精华内容 101
关键字:

数据库什么叫并发