#

分为乐观锁与悲观锁。

# 乐观锁

乐观锁假设数据一般情况下不会造成冲突,所以在数据进行提交更新的时候,使用版本号字段匹配条件,如果更新失败则认为发生了冲突。
使用@Version注解声明一个实体类属性为版本字段,字段在数据库中必须为数字类型,因为版本需要自增。
在使用update更新时,如果Version属性不为null,则会自动作为查询条件;不管Version属性是否为空,框架都会在更新时将其自增。

注:在Hibernate框架中如果发生更新条数为0时,会抛出OptimisticLockException异常,在本框架中需要你自行判定。

# 悲观锁

悲观锁的实现需要数据库支持,一般分为悲观读锁与悲观写锁。

读锁,是指在本事务内,不会更新锁定的数据,但也不希望在本事务结束前,有别的事务更新这条(或这些)数据,多个事务可以同时获取读锁,事务如果要更新锁定的数据,则需要等到所有读锁释放。 写锁,是指在本事务内,将会更新锁定的数据,只有一个事务能获取指定数据的写锁。

# 在命名查询创建器中声明锁
  @NamingQuery
	@StatementOptions(asExpression = "findById", lockModeType = LockModeType.PESSIMISTIC_WRITE)
	public Teacher findByIdWithLock(Long id);
	
	@NamingQuery
	@StatementOptions(asExpression = "findById", lockModeType = LockModeType.PESSIMISTIC_READ)
	public Teacher findByIdWithShareLock(Long id);

在以上示例中,方法名显式地表达了这是一个需要获取锁的查询,但WithLock不是查询创建器中表达式,所以,为了查询创建器能够正确需要在@StatementOptions注解中属性asExpression重新定义表达式。
LockModeType是JPA规范中的枚举类型,枚举类型有很多,如果使用,有如下规则:

  1. READ/WRITE/OPTIMISTIC/OPTIMISTIC_FORCE_INCREMENT都等同于NONE,即无锁,乐观锁是实体在@Version声明之后自动使用的。
  2. PESSIMISTIC_WRITE等于PESSIMISTIC_FORCE_INCREMENT,即使用悲观写锁,如果有@Version声明属性,则该属性自增。
  3. 如果数据库无读锁(共享锁)则PESSIMISTIC_READ跟PESSIMISTIC_WRITE功能一致。
# 在Criteria查询中使用锁

使用Criteria或LambdaCriteria查询时,如果在查询时上锁,只要调用lock方法即可。

List<Teacher> list = teacherMapper.findByCriteria(p -> p.eq("id", 1L).lock(LockModeType.PESSIMISTIC_WRITE)); //指定锁模式

List<Teacher> list = teacherMapper.findByCriteria(p -> p.eq("id", 1L).lock(); //默认悲观写锁