怎么理解数据库的锁? 一般锁分别哪几种?

怎么理解数据库的锁? 一般锁分别哪几种?,第1张

数据库是一个多用户使用的共享资源。当多个用户并发地存取数据时,在数据库中就会产生多个事务同时存取同一数据的情况。若对并发 *** 作不加控制就可能会读取和存储不正确的数据,破坏数据库的一致性。

加锁是实现数据库并发控制的一个非常重要的技术。当事务在对某个数据对象进行 *** 作前,先向系统发出请求,对其加锁。加锁后事务就对该数据对象有了一定的控制,在该事务释放锁之前,其他的事务不能对此数据对象进行更新 *** 作。

在数据库中有两种基本的锁类型:排它锁(Exclusive Locks,即X锁)和共享锁(Share Locks,即S锁)。当数据对象被加上排它锁时,其他的事务不能对它读取和修改。加了共享锁的数据对象可以被其他事务读取,但不能修改。数据库利用这两种基本的锁类型来对数据库的事务进行并发控制。

扩展资料:

排它锁和共享锁的不同之处:

1、共享锁(S锁):如果事务T对数据A加上共享锁后,则其他事务只能对A再加共享锁,不能加排他锁。获准共享锁的事务只能读数据,不能修改数据。

排他锁(X锁):如果事务T对数据A加上排他锁后,则其他事务不能再对A加任任何类型的封锁。获准排他锁的事务既能读数据,又能修改数据。

2、共享锁下其它用户可以并发读取,查询数据。但不能修改,增加,删除数据,资源共享。

3、共享锁又称为读锁(Share lock,简记为S锁),若事务T对数据对象A加上S锁,则其它事务只能再对A加S锁,而不能加X锁,直到T释放A上的S锁。

参考资料:百度百科-排它锁

参考资料:百度百科-共享锁

锁是计算机协调多个进程或线程并发访问某一资源的机制,在数据库中,除传统的计算资源(CPU、RAM、I/O)争用外,数据也是一种供许多用户共享的资源,如何保证数据并发访问的一致性,有效性是所有数据库必须解决的一个问题,锁冲突也是影响数据库并发访问性能的一个重要因素,从这个角度来说,锁对数据库而言是尤其重要,也更加复杂。MySQL中的锁,按照锁的粒度分为:1、全局锁,就锁定数据库中的所有表。2、表级锁,每次 *** 作锁住整张表。3、行级锁,每次 *** 作锁住对应的行数据。

全局锁就是对整个数据库实例加锁,加锁后整个实例就处于只读状态,后续的DML的写语句,DDL语句,已经更新 *** 作的事务提交语句都将阻塞。其典型的使用场景就是做全库的逻辑备份,对所有的表进行锁定,从而获取一致性视图,保证数据的完整性。但是对数据库加全局锁是有弊端的,如在主库上备份,那么在备份期间都不能执行更新,业务会受影响,第二如果是在从库上备份,那么在备份期间从库不能执行主库同步过来的二进制日志,会导致主从延迟。

解决办法是在innodb引擎中,备份时加上--single-transaction参数来完成不加锁的一致性数据备份。

添加全局锁: flush tables with read lock解锁 unlock tables。

表级锁,每次 *** 作会锁住整张表.锁定粒度大,发送锁冲突的概率最高,并发读最低,应用在myisam、innodb、BOB等存储引擎中。表级锁分为: 表锁、元数据锁(meta data lock, MDL)和意向锁。

表锁又分为: 表共享读锁 read lock、表独占写锁write lock

语法: 1、加锁 lock tables 表名 ... read/write

2、释放锁 unlock tables 或者关闭客户端连接

注意: 读锁不会阻塞其它客户端的读,但是会阻塞其它客户端的写,写锁既会阻塞其它客户端的读,又会阻塞其它客户端的写。大家可以拿一张表来测试看看。

元数据锁,在加锁过程中是系统自动控制的,无需显示使用,在访问一张表的时候会自动加上,MDL锁主要作用是维护表元数据的数据一致性,在表上有活动事务的时候,不可以对元数据进行写入 *** 作。为了避免DML和DDL冲突,保证读写的正确性。

在MySQL5.5中引入了MDL,当对一张表进行增删改查的时候,加MDL读锁(共享);当对表结构进行变更 *** 作时,加MDL写锁(排他).

查看元数据锁:

select object_type,object_schema,object_name,lock_type,lock_duration from performance_schema_metadata_locks

意向锁,为了避免DML在执行时,加的行锁与表锁的冲突,在innodb中引入了意向锁,使得表锁不用检查每行数据是否加锁,使用意向锁来减少表锁的检查。意向锁分为,意向共享锁is由语句select ... lock in share mode添加。意向排他锁ix,由insert,update,delete,select。。。for update 添加。

select object_schema,object_name,index_name,lock_type,lock_mode,lock_data from performance_schema.data_lock

行级锁,每次 *** 作锁住对应的行数据,锁定粒度最小,发生锁冲突的概率最高,并发读最高,应用在innodb存储引擎中。

innodb的数据是基于索引组织的,行锁是通过对索引上的索引项加锁来实现的,而不是对记录加的锁,对于行级锁,主要分为以下三类:

1、行锁或者叫record lock记录锁,锁定单个行记录的锁,防止其他事物对次行进行update和delete *** 作,在RC,RR隔离级别下都支持。

2、间隙锁Gap lock,锁定索引记录间隙(不含该记录),确保索引记录间隙不变,防止其他事物在这个间隙进行insert *** 作,产生幻读,在RR隔离级别下都支持。

3、临键锁Next-key-lock,行锁和间隙锁组合,同时锁住数据,并锁住数据前面的间隙Gap,在RR隔离级别下支持。

innodb实现了以下两种类型的行锁

1、共享锁 S: 允许一个事务去读一行,阻止其他事务获得相同数据集的排他锁。

2、排他锁 X: 允许获取排他锁的事务更新数据,阻止其他事务获得相同数据集的共享锁和排他锁。

insert 语句 排他锁 自动添加的

update语句 排他锁 自动添加

delete 语句 排他锁 自动添加

select 正常查询语句 不加锁 。。。

select 。。。lock in share mode 共享锁 需要手动在select 之后加lock in share mode

select 。。。for update 排他锁 需要手动在select之后添加for update

默认情况下,innodb在repeatable read事务隔离级别运行,innodb使用next-key锁进行搜索和索引扫描,以防止幻读。

间隙锁唯一目的是防止其它事务插入间隙,间隙锁可以共存,一个事务采用的间隙锁不会阻止另一个事务在同一间隙上采用的间隙锁。

方法1:用mysql命令锁住表.

public void test() {  

  

    String sql = "lock tables aa1 write"  

    // 或String sql = "lock tables aa1 read"   

    // 如果想锁多个表 lock tables aa1 read ,aa2 write , .....   

    String sql1 = "select * from aa1 "  

  

    String sql2 = "unlock tables"  

    try {  

        this.pstmt = conn.prepareStatement(sql)  

        this.pstmt1 = conn.prepareStatement(sql1)  

        this.pstmt2 = conn.prepareStatement(sql2)  

        pstmt.executeQuery()  

        pstmt1.executeQuery()  

        pstmt2.executeQuery()  

  

    } catch (Exception e) {  

        System.out.println("异常" + e.getMessage())  

    }  

  

}

对于read lock 和 write lock官方说明:

1.如果一个线程获得一个表的READ锁定,该线程(和所有其它线程)只能从该表中读取。

如果一个线程获得一个表的WRITE锁定,只有保持锁定的线程可以对表进行写入。

其它的线程被阻止,直到锁定被释放时为止。

2.当您使用LOCK TABLES时,您必须锁定您打算在查询中使用的所有的表。

虽然使用LOCKTABLES语句获得的锁定仍然有效,但是您不能访问没有被此语句锁定的任何的表。

同时,您不能在一次查询中多次使用一个已锁定的表——使用别名代替,

在此情况下,您必须分别获得对每个别名的锁定。

对与read lock 和 write lock个人说明:

1.read lock 和 write lock 是线程级(表级别).

2.在同一个会话中加了read lock锁. 只能对这个表进行读 *** 作.对这个表以外的任何表都无法进行增、删、改、查的 *** 作.

但是在不同会话中,只能对加了read lock的表进行读 *** 作.但可以对read lock以外的表进行增、删、改、查的 *** 作.

3.在同一个会话中加了write lock锁.只能对这个表进行读、写 *** 作.对这个表以外的任何表都无法进行增、删、改、查的 *** 作.

但是在不同会话中,无法对加了write lock的表进行读、写 *** 作.但可以对write lock以外的表进行增、删、改、查的 *** 作.

4.如果表中使用了别名.(SELECT * FROM aa1 AS byname_table)

在对aa1加锁时,必须把别名加上去(lock tables aa1 as byname_table read)

在同一个会话中.必须使用别名进行查询.

在不同的会话中.可以不需要使用别名进行查询.

5.在多个会话中可以对同一个表进行lock read *** 作.但不能在多个会话中对同一个表进行lock write *** 作(这些锁将等待已锁的表释放自身的线程锁)

如果多个会话对同一个表进行lock read *** 作.那么在这些会话中,也只能对以锁的表进行读 *** 作.

6.如果要你锁住了一个表,需要嵌套查询.你必须使用别名,并且,要锁定别名.

例如.lock table aa1 read ,aa1 as byname_table read

select * from aa1 where id in (select * from aa1 as xx  where id=2)

7.解锁必须用unlock tables

另:

在JAVA程序中,要想解锁,需要调用 unlock tables来解锁.

如果没有调用unlock tables.

关闭connection 、程序结束 、调用GC 都能解锁.

方法2:用记录锁锁表.

public void test() {  

  

    String sql = "select * from aa1 for update"   

               // select * from aa1 lock in share mode   

  

    try {  

        conn.setAutoCommit(false)  

        this.pstmt = conn.prepareStatement(sql)  

        pstmt.executeQuery()  

  

    } catch (Exception e) {  

        System.out.println("异常" + e.getMessage())  

    }  

  

}

1.for update 与 lock in share mode 属于行级锁和页级锁

2.for update 排它锁,lock in share mode 共享锁

3.对于记录锁.必须开启事务.

4.行级锁定事实上是索引记录的锁定.只要是用索引扫描的行(或没索引全表扫描的行),都将被锁住.

5.在不同的隔离级别下还会使用next-key locking算法.即所扫描的行之间的“间隙”也会也锁住(在Repeatable read和Serializable隔离级别下有间隙锁).

6.在mysql中共享锁的含义是:在被共享锁锁住的行,即使内容被修改且并没有提交.在另一个会话中依然看到最新修改的信息.

在同一会话中加上了共享锁.可以对这个表以及这个表以外的所有表进行增、删、改、查的 *** 作.

在不同的会话中.可以查到共享锁锁住行的最新消息.但是在Read Uncommitted隔离级别下不能对锁住的表进行删,

改 *** 作.(需要等待锁释放才能 *** 作...)

在Read Committed隔离级别下不能对锁住的表进行删,改 *** 作.(需要等待锁释放才能 *** 作...)

在Repeatable read隔离级别下不能对锁住行进行增、删、改 *** 作.(需要等待锁释放才能 *** 作...)

在Serializable隔离级别下不能对锁住行进行增、删、改 *** 作.  (需要等待锁释放才能 *** 作...)

7.在mysql中排他锁的含义是:在被排它锁锁住的行,内容修改并没提交,在另一个会话中不会看到最新修改的信息。

在不同的会话中.可以查到共享锁锁住行的最新消息.但是Read Uncommitted隔离级别下不能对锁住的表进行删,

改 *** 作.(需要等待锁释放才能 *** 作...)

在Read Committed隔离级别下不能对锁住的表进行删,改 *** 作.(需要等待锁释放才能 *** 作...)

在Repeatable read隔离级别下不能对锁住行进行增、删、改 *** 作.(需要等待锁释放才能 *** 作...)

在Serializable隔离级别下不能对锁住行进行增、删、改 *** 作. (需要等待锁释放才能 *** 作...)

8.在同一个会话中的可以叠加多个共享锁和排他锁.在多个会话中,需要等待锁的释放.

9.SQL中的update 与 for update是一样的原理.

10.等待超时的参数设置:innodb_lock_wait_timeout=50 (单位秒).

11.任何可以触发事务提交的命令,都可以关闭共享锁和排它锁.


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/sjk/6688277.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-03-26
下一篇 2023-03-26

发表评论

登录后才能评论

评论列表(0条)

保存