举个场景:多线程、多进程应用在对数据库的同一数据进行非幂等操作时,如果没有添加相应的锁机制进行校验、判断,通常会导致数据的脏写。抛开分布式锁这种解决思路,简单的来讲,可以优先考虑从数据库层面去解决这个问题。
数据库锁分为乐观锁和悲观锁,前者适合读多写少的场景,后者适合读少写多的场景。乐观锁的实现通常是采用加版本号的形式,即如果更新时版本号未发生改变,则本次操作是成功的,且当前版本号的信息也相应会发生改变;再来看看悲观锁,悲观锁的实现方式是在待执行的SQL语句后加上for update
,利用了数据库的行锁或是表锁特性来进行实现,但如果使用不当,会严重拖累整个操作的执行速度。
下面的实际案例展示了具体的操作,该项目基于 Spring Data JPA 实现:
- 新建两个实体类,
Teacher
对应悲观锁的示例,User
对应乐观锁示例:
/**
* 悲观锁示例
*/
@Data
@Entity
@NoArgsConstructor
public class Teacher {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name;
public Teacher(String name) {
this.name = name;
}
}
/**
* 乐观锁示例
*/
@Data
@Entity
@NoArgsConstructor
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name;
/**
* 乐观锁实现方式①:直接添加@Version
*/
@Version
private Integer version = 0;
public User(String name) {
this.name = name;
}
}