select for update的本质是数据库行级锁

2,050 阅读2分钟

select for update是什么?作用?

查询的时候,加锁。

何时释放锁?

获取锁的当前数据库连接提交或回滚的时候,就会释放锁。

有加锁,就要释放锁。一个锁,一定有加锁和释放锁。任何一个锁,加了锁,都要释放锁。不然就有问题,其他数据库连接一直获取不了锁,就会一直阻塞。

实现原理

底层的实现原理是数据库厂商实现了行级锁,即select for update会锁住一行或几行数据,本质是数据库客户端的连接,同一时间,只有一个连接能够获取锁住的行的数据,其他连接都获取不了。

和java并发请求的原理其实是一样的,同一时间,只有一个请求线程能执行锁住的代码——锁住代码之后,就锁住了对共享数据的并发修改,最后的目的还是要锁住数据。

如何测试?

比如在pl sql客户端,开2个窗口,模拟2个客户端连接,执行同样的select for update,就会发现:

  1. 第一个连接可以获取数据,但是第一个连接不提交事务
  2. 执行第二个连接的sql,获取不到数据,阻塞了,因为获取不到锁
  3. 提交第一个连接的事务,再次执行第二个连接的sql,现在可以获取到数据了

实际演示如下,开两个窗口:

1)第一个窗口用select for update查询

2)在另一个窗口用同样的语句查询,会显示一直在查询...说明被block了

3)、点击第一个窗口里的提交事务按钮,另一个窗口可以立刻获取查询结果

总结

  1. 行级锁

select for update本质是数据库的行级,而是是数据库本身实现的。

  1. 数据库厂商

oracle、mysql,都实现了select for update 行级锁。

在代码里如何使用?

比如在hibernate里有select for update这个配置。


如何使用?

在dao类里调用hibernate的方法即可,dao类的代码如下:

/**
 * 
 * @param srcCustId
 * @param orderId
 * @return
 */
public Orderbill selectBySrcOrderIdWithLock(String srcCustId, String orderId) {
 QueryHelper help = new QueryHelper();
 help.append("from Orderbill orderbill");
 help.append(" where orderbill.srcCustid=? ", srcCustId);
 help.append(" and orderbill.orderid=? ", orderId);
 Orderbill orderbill = (Orderbill) getUniqueResult(help, "orderbill",
   LockMode.UPGRADE); //
 return orderbill;
}

service类的代码是

事务方法{
查询sql for update:比如查询订单; //当前数据库连接获取锁,其他数据库连接阻塞
更新sql:比如更新订单
} //spring事务方法结束的时候,提交事务,就会释放锁

参考

www.techonthenet.com/oracle/curs…

www.oracletutorial.com/plsql-tutor…

blog.csdn.net/Victor_Cind…