在数据库并发操作时,为了保证数据的正确性,经常要对数据加锁,加锁有两种方式:悲观锁、乐观锁
悲观锁:把所需要的数据全部加锁,不允许其他事务对数据做修改
update xxx where xxxx for update
乐观锁:对数据进行版本校验,如果版本不一致,则操作数据失败
update xxx,version+1 where xxxx and version=x
```
- @Version注解可以在实体 bean 中使用,通过这种方式可添加对乐观锁定的支持
- 一个类中只能有一个@Version注解
- 注意此属性 不能用 String 可取值 int Integer Long
- 在jpa中,@Version注解,可以实现乐观锁功能
实体类Account,version属性上加@Version注解
```java
package com.xhx.springboot.entity;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Version;
/**
* @author xuhaixing
* @date 2018/4/28 10:29
*/
@Entity
public class Account {
@Id
private int id;
private String name;
private Double money;
@Version
private int version;
public int getVersion() {
return version;
}
public void setVersion(int version) {
this.version = version;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Double getMoney() {
return money;
}
public void setMoney(Double money) {
this.money = money;
}
}
在更新数据时,需要用jpa自己实现的save方法
<S extends T> S save(S var1);
<S extends T> Iterable<S> saveAll(Iterable<S> var1);
如果是自己写的update方法,下面这样,是不生效的
@Repository
public interface AccountDao extends JpaRepository<Account, Integer> {
@Modifying
@Query("update Account set name=:name, money=:money where id=:id")
int updateAccount(@Param("id") int id,@Param("name") String name, @Param("money") double money);
}
数据库数据如下:
我们更新id是10的数据,数据库中版本是0,我们设置版本1
Account account = new Account();
account.setId(10);
account.setName("eeee");
account.setMoney(7999.0);
account.setVersion(1);
accountController.update(account);
报如下错误:
org.springframework.orm.ObjectOptimisticLockingFailureException: Object of class [com.xhx.springboot.entity.Account] with identifier [10]: optimistic locking failed; nested exception is org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect) : [com.xhx.springboot.entity.Account#10]
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:298)
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:225)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:527)
把版本号改成0,再更新,数据库中执行如下语句,更新成功
再看数据库,版本号+1了
PREVIOUSDynamicUpdate正确使用方式