1.mysql中的行级锁是由以下sql语句产生:
select * from job_info where id = 1 for update;
主要加上了for update,其中id为主键。
如果查询条件不是主键,则会成为表锁。

2.悲观锁和乐观锁
悲观锁虽然能保证数据一致,可是如果进程从读取到更新的时间太长,会导致其他进程等待时间较长,使得系统效率降低。如有重试机制,也可能会耗光数据库连接数。

乐观锁,是为数据库表增加一个标识数据版本的version字段来实现的,读取数据时把version字段一同读出,写入数据库时比对version字段就知道数据是否被更改过,如果version不相等就说明持有的是过期数据,不能写入,如果相等就可以写入,并把version加一。

所以,悲观锁和乐观锁各有特色,视具体业务选择。

3.Spring Data JPA和锁
@Version – 实体类中用在version字段(类型必须为long/int/short/java.sql.Timestamp)
@Lock – 用在CrudRepository接口中的方法上,
LockModeType有以下枚举值:
NONE: No lock.
OPTIMISTIC: Optimistic lock.
OPTIMISTIC_FORCE_INCREMENT: Optimistic lock, with version update.
PESSIMISTIC_FORCE_INCREMENT: Pessimistic write lock, with version update.
PESSIMISTIC_READ: Pessimistic read lock.
PESSIMISTIC_WRITE: Pessimistic write lock.
READ: Synonymous with OPTIMISTIC.
WRITE: Synonymous with OPTIMISTIC_FORCE_INCREMENT.

4.SpringBoot使用@Transactional

  • mysql默认引擎MyISAM不支持事务,需要指定InnoDB
  • 可以作用于接口、接口方法、类以及类方法上。当作用于类上时,该类的所有 public 方法将都具有该类型的事务属性,
  • 应该只被应用到 public 方法上,这是由 Spring AOP 的本质决定的。如果你在 protected、private 或者默认可见性的方法上使用 @Transactional 注解,这将被忽略,也不会抛出任何异常。
  • 不要在接口上声明@Transactional ,而要在具体类的方法上使用 @Transactional 注解,否则注解可能无效。
  • 不要图省事,将@Transactional放置在类级的声明中,放在类声明,会使得所有方法都有事务。故@Transactional应该放在方法级别,不需要使用事务的方法,就不要放置事务,比如查询方法。否则对性能是有影响的。
  • 使用了@Transactional的方法,对同一个类里面的方法调用, @Transactional无效。比如有一个类Test,它的一个方法A,A再调用Test本类的方法B(不管B是否public还是private),但A没有声明注解事务,而B有。则外部调用A之后,B的事务是不会起作用的。
  • spring的事务在抛异常的时候会回滚,如果是catch捕获了,事务无效。可以在catch里面加上throw new RuntimeException();
  • 最后有个关键的一点:和锁同时使用需要注意:由于Spring事务是通过AOP实现的,所以在方法执行之前会有开启事务,之后会有提交事务逻辑。而synchronized代码块执行是在事务之内执行的,可以推断在synchronized代码块执行完时,事务还未提交,其他线程进入synchronized代码块后,读取的数据不是最新的。所以必须使synchronized锁的范围大于事务控制的范围,把synchronized加到Controller层或者大于事务边界的调用层!