0
点赞
收藏
分享

微信扫一扫

Spring data jpa @Version注解及自定义数据库乐观锁实现


 

在数据库并发操作时,为了保证数据的正确性,经常要对数据加锁,加锁有两种方式:悲观锁、乐观锁

悲观锁:把所需要的数据全部加锁,不允许其他事务对数据做修改 

update xxx where xxxx for update

乐观锁:对数据进行版本校验,如果版本不一致,则操作数据失败   

update xxx,version+1  where xxxx and version=x

 

在jpa中,@Version注解,可以实现乐观锁功能

实体类Account,version属性上加@Version注解

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);

}

 

数据库数据如下:

Spring data jpa @Version注解及自定义数据库乐观锁实现_spring

我们更新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,再更新,数据库中执行如下语句,更新成功

Spring data jpa @Version注解及自定义数据库乐观锁实现_spring data jpa_02

再看数据库,版本号+1了

Spring data jpa @Version注解及自定义数据库乐观锁实现_spring_03

 

 

自己实现可以这样:

@Modifying
@Query("update Account set name=:name, money=:money,version=:version+1 where id=:id and version=:version")
int updateAccountByVersion(@Param("id") int id,@Param("name") String name, @Param("money") double money,@Param("version") int version);

service中加判断,抛异常,这样就自己通过数据库实现了乐观锁

@Transactional(rollbackFor = Exception.class)
public int updateAccountByVersion(Account account){
int i =accountDao.updateAccountByVersion(account.getId(),account.getName(),account.getMoney(),account.getVersion());
if(i==0){
throw new ObjectOptimisticLockingFailureException("更新account失败",new Exception());
}
return i;
}

实时内容请关注微信公众号,公众号与博客同时更新:程序员星星

Spring data jpa @Version注解及自定义数据库乐观锁实现_spring data jpa_04

举报

相关推荐

0 条评论