数据库锁的基本原理

简介: 前言:为了保证数据的完整性和一致性,数据库系统采用锁来实现事务的隔离性。各种大型数据库采用的锁基本理论是一致的,但在具体实现上各有差别。从并发事务锁定的关系上看,可以分为共享锁定和独占锁定。从锁定的对象不同,一般可以分为表锁定和行锁定。 1、锁的分类   锁分为悲观锁和乐观锁:     ● 悲观锁:悲观的思想,认为并发问题总会出现,每次一个事务读取某一条记录后,就会把这条记录

前言:为了保证数据的完整性和一致性,数据库系统采用锁来实现事务的隔离性。各种大型数据库采用的锁基本理论是一致的,但在具体实现上各有差别。从并发事务锁定的关系上看,可以分为共享锁定和独占锁定。从锁定的对象不同,一般可以分为表锁定和行锁定。


1、锁的分类


  锁分为悲观锁和乐观锁:

    ● 悲观锁:悲观的思想,认为并发问题总会出现,每次一个事务读取某一条记录后,就会把这条记录锁住,这样其它的事务要想更新,必须等以前的事务提交或者回滚解除锁。悲观锁的性能低,其基本种类有:

    ● 乐观锁:乐观的思想,认为并发问题不总是出现;每次提交一个事务更新时,我们先看看要修改的东西从上次读取以后有没有被修改过,如果修改过,那么更新就会失败。乐观锁其实并不会锁定任何记录,所以如果我们数据库的事务隔离级别设置为读取已提交或者更低的隔离界别,那么是不能避免不可重复读问题的(因为此时读事务不会阻塞其它事务),所以采用乐观锁的时候,系统应该要容许不可重复读问题的出现。


2、悲观锁分类


  (1)共享锁


  共享锁用于读取数据操作,它是非独占的,允许其他事务同时读取其锁定的资源,但不允许其他事务更新它。

     加锁的条件:当一个事务执行select语句时,数据库系统会为这个事务分配一把共享锁,来锁定被查询的数据。

     解锁的条件:在默认情况下,数据被读取后,数据库系统立即解除共享锁。例如,当一个事务执行查询“SELECT * FROM accounts”语句时,数据库系统首先锁定第一行,读取之后,解除对第一行的锁定,然后锁定第二行。这样,在一个事务读操作过程中,允许其他事务同时更新accounts表中未锁定的行。

     与其他锁的兼容性:如果数据资源上放置了共享锁,还能再放置共享锁和更新锁。

     并发性能:具有良好的并发性能,当数据被放置共享锁后,还可以再放置共享锁或更新锁。所以并发性能很好。 


  (2)更新锁


    更新锁在的初始化阶段用来锁定可能要被修改的资源,这可以避免使用共享锁造成的死锁现象。例如,对于以下的update语句:

<span style="font-size:18px;">UPDATE accounts SET balance=900 WHERE id=1</span>

    更新操作需要分两步:

       读取accounts表中id为1的记录;

       执行更新操作。

    如果在第一步使用共享锁,再第二步把锁升级为独占锁,就可能出现死锁现象。例如:两个事务都获取了同一数据资源的共享锁,然后都要把锁升级为独占锁,但需要等待另一个事务解除共享锁才能升级为独占锁,这就造成了死锁。


    更新锁有如下特征:

      ● 加锁的条件:当一个事务执行update语句时,数据库系统会先为事务分配一把更新锁。

      ● 解锁的条件:当读取数据完毕,执行更新操作时,会把更新锁升级为独占锁。

      ● 与其他锁的兼容性:更新锁与共享锁是兼容的,也就是说,一个资源可以同时放置更新锁和共享锁,但是最多放置一把更新锁。这样,当多个事务更新相同的数据时,只有一个事务能获得更新锁,然后再把更新锁升级为独占锁,其他事务必须等到前一个事务结束后,才能获取得更新锁,这就避免了死锁。

      ● 并发性能:允许多个事务同时读锁定的资源,但不允许其他事务修改它。


  (3)独占锁


    独占锁:独占锁也叫排他锁,适用于修改数据的场合。它所锁定的资源,其他事务不能读取也不能修改。

     加锁的条件:当一个事务执行insert、update或delete语句时,数据库系统会自动对SQL语句操纵的数据资源使用独占锁。如果该数据资源已经有其他锁(任何锁)存在时,就无法对其再放置独占锁了。

     解锁的条件:独占锁需要等到事务结束才能被解除。

     兼容性:独占锁不能和其他锁兼容,如果数据资源上已经加了独占锁,就不能再放置其他的锁了。同样,如果数据资源上已经放置了其他锁,那么也就不能再放置独占锁了。

     并发性能:不用说了,最差。只允许一个事务访问锁定的数据,如果其他事务也需要访问该数据,就必须等待,起到前一个事务结束,解除了独占锁,其他事务才有机会访问该数据。


  当一个事务访问某种数据库资源时,如果执行select语句,必须先获得共享锁,如果执行insert、update或delete语句,必须获得独占锁,这些锁用于锁定被操作的资源。

  当第二个事务也要访问相同的资源时,如果执行select语句,也必须先获得共享锁,如果执行insert、update或delete语句,也必须获得独占锁。此时根据已经旋转在资源上的锁的类型,来决定第二个事务应该等待第一个事务解除对应资源的锁定,还是可以立刻获得锁。

                                    

3、乐观锁


  乐观锁与数据库锁机制无关,其锁实现策略为:

     版本 (Version) 字段:在我们的实体中增加一个版本控制字段,每次事务更新后就将版本字段的值加 1。

     时间戳 (timestamps):实现方式和版本字段差不多,同样是在需要乐观锁控制的table中增加一个字段,名称无所谓,字段类型使用时间戳(timestamp),和上面的version类似,也是在更新提交的时候检查当前数据库中数据的时间戳和自己更新前取到的时间戳进行对比,如果一致则OK,否则就是版本冲突。


  版本字段方式实例:

    我们修改t_person表,添加version字段表示当前记录的版本,默认值为1。

    当事务查询记录时得到version=1,再执行update时需要比较当前version的值是否与之前查询到的version相同,决定update是否执行成功。如果update成功,还要把version的值加1。

	public void update(Connection con, Person p) throws Exception {
		String sql = "update t_person set pname=?, age=?, gender=?, version=version+1 where pid=? and version=?"; //version是版本字段
		PreparedStatement pstmt = con.prepareStatement(sql);
		pstmt.setString(1, p.getPname());
		pstmt.setInt(2, p.getAge());
		pstmt.setString(3, p.getGender());
		pstmt.setString(4, p.getPid());
		pstmt.setInt(5, p.getVersion());
		
		pstmt.executeUpdate();
	}

  场景模拟:

    事务1:查询时得到version=1;

    事务2:查询时得到version=1; 

    事务1:执行update时因为version没有改变,所以update执行成功,update不只修改了age=42,还修改了version=2;

    事务2:执行update语句时version已经为2,而查询时的version为1,所以update执行失败;


  小结:乐观锁和悲观锁的区别在于是否认为并发问题一定会存在。悲观锁也就是上面讲到的我们认为的通常意义上的锁,而乐观锁实质是与数据库锁机制无关的。共享锁定会防止独占锁定,但允许其它的共享锁定。而独占锁定既防止其它的独占锁定,也防止其它的共享锁定。为了更改数据,数据库必须在进行更改的行上施加行独占锁定。



目录
相关文章
|
1月前
|
SQL 存储 关系型数据库
数据库的行级锁与表锁?
表锁:存储引擎在SQL数据读写请求前对涉及的表加锁,分共享读锁和独占写锁,读锁阻塞写,写锁阻塞读写,易发锁冲突,并发性低。行级锁:InnoDB支持,通过索引加锁,提高并发性,但可能引起死锁,需注意索引使用,适用于避免不可重复读场景。
62 21
|
2月前
|
存储 缓存 网络安全
南大通用GBase 8s 数据库 RHAC集群基本原理和搭建步骤
南大通用GBase 8s 数据库 RHAC集群基本原理和搭建步骤
|
3月前
|
缓存 算法 关系型数据库
Mysql(3)—数据库相关概念及工作原理
数据库是一个以某种有组织的方式存储的数据集合。它通常包括一个或多个不同的主题领域或用途的数据表。
102 5
Mysql(3)—数据库相关概念及工作原理
|
2月前
|
存储 Java 关系型数据库
在Java开发中,数据库连接是应用与数据交互的关键环节。本文通过案例分析,深入探讨Java连接池的原理与最佳实践
在Java开发中,数据库连接是应用与数据交互的关键环节。本文通过案例分析,深入探讨Java连接池的原理与最佳实践,包括连接创建、分配、复用和释放等操作,并通过电商应用实例展示了如何选择合适的连接池库(如HikariCP)和配置参数,实现高效、稳定的数据库连接管理。
73 2
|
3月前
|
SQL 关系型数据库 数据库
SQL数据库:核心原理与应用实践
随着信息技术的飞速发展,数据库管理系统已成为各类组织和企业中不可或缺的核心组件。在众多数据库管理系统中,SQL(结构化查询语言)数据库以其强大的数据管理能力和灵活性,广泛应用于各类业务场景。本文将深入探讨SQL数据库的基本原理、核心特性以及实际应用。一、SQL数据库概述SQL数据库是一种关系型数据库
131 5
|
3月前
|
存储 关系型数据库 MySQL
MySQL数据库锁:共享锁和独占锁
本文详细介绍了`InnoDB`存储引擎中的两种行级别锁:共享锁(S锁)与排他锁(X锁)。通过具体示例展示了这两种锁的工作机制及其在`InnoDB`与`MyISAM`引擎中的表现差异。文章还提供了锁的兼容性矩阵,帮助读者更好地理解锁之间的互斥关系。最后总结了两种锁的特点及适用场景。适合希望深入了解`MySQL`并发控制机制的读者阅读。
120 1
|
3月前
|
SQL 关系型数据库 MySQL
sql注入原理与实战(三)数据库操作
sql注入原理与实战(三)数据库操作
sql注入原理与实战(三)数据库操作
|
3月前
|
SQL 存储 Java
sql注入原理与实战(二)数据库原理
sql注入原理与实战(二)数据库原理
|
5月前
|
消息中间件 Kafka 数据库
深入理解Kafka的数据一致性原理及其与传统数据库的对比
【8月更文挑战第24天】在分布式系统中,确保数据一致性至关重要。传统数据库利用ACID原则保障事务完整性;相比之下,Kafka作为高性能消息队列,采用副本机制与日志结构确保数据一致性。通过同步所有副本上的数据、维护消息顺序以及支持生产者的幂等性操作,Kafka在不牺牲性能的前提下实现了高可用性和数据可靠性。这些特性使Kafka成为处理大规模数据流的理想工具。
115 6
|
5月前
|
SQL 存储 关系型数据库
"MySQL增列必锁表?揭秘InnoDB在线DDL,让你的数据库操作飞一般,性能无忧!"
【8月更文挑战第11天】在数据库领域,MySQL凭借其稳定高效的表现深受开发者喜爱。对于是否会在给数据表添加列时锁表的问题,MySQL的行为受版本、存储引擎等因素影响。从5.6版起,InnoDB支持在线DDL,可在改动表结构时保持表的可访问性,避免长时间锁表。而MyISAM等则需锁表完成操作。例如,在使用InnoDB的表上运行`ALTER TABLE users ADD COLUMN email VARCHAR(255);`时,通常不会完全锁表。虽然在线DDL提高了灵活性,但复杂操作或大表变更仍可能暂时影响性能。因此,进行结构变更前应评估其影响并择机执行。
88 6