spring dat jpa @version 乐观锁

前言

Mysql使用Innodb引擎,支持事务,行锁,
那么,高并发情况下,多个事务同时进行;如果多个事务对同一条数据进行操作,并且都成功了,肯定会出现脏读等问题,最终导致数据库的数据有问题。破坏了数据的原子性,唯一性,正确性。

简单举个栗子:

银行转账:
小李卡里有10块钱。
小李和小王同时来取钱,小李取2块钱,小王取2块钱。
取钱操作加了事务。

【预期结果,最后剩余: 10 - 2 - 2 = 6】
【实际结果,最后剩余:8】

原因:小李取钱,上下文开启事务1,读取的余额是10;
小王取钱,这个时候事务1还没有提交,又开启事务2,读取到的的余额也是10;
事务1不知道事务2取钱了,都提交成功了。数据库最终是8.

@Version

公司用的spring data jpa,通过@version注解添加表数据的乐观锁定的支持
添加@version注解,系统每次保存会自动给该属性值加1。配合事务,版本不对,事务则不能提交,数据回滚,保证数据没有脏写入

实体基类:
DomainObject

package com.test.domain;

import javax.persistence.*;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

@MappedSuperclass
public class DomainObject implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "id")
    Long id;

    @Version
    @Column(name = "version", length = 11)
    private int version = 0;


    @Column(name = "guid")
    String guid = GuidGenerator.createGuid();


    @Column(name = "archived", length = 1)
    boolean archived = false;

    @Column(name = "created_datetime")
    protected LocalDateTime createdDateTime = LocalDateTime.now();


    @Column(name = "last_modified_datetime")
    LocalDateTime lastModifiedDateTime;

    @PrePersist
    @PreUpdate
    public void updateLastModifiedDateTime() {
        lastModifiedDateTime = LocalDateTime.now();
    }

    public void updateLastModifiedDateTime(LocalDateTime localDateTime) {
        lastModifiedDateTime = localDateTime;
    }

    public void archive() {
        archived = true;
    }

    public void unarchive() {
        archived = false;
    }


    public boolean isArchived() {
        return archived;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null || !(obj instanceof DomainObject)) {
            return false;
        }

        DomainObject other = (DomainObject) obj;

        // if the id is missing, return false
        if (guid() == null) {
            return false;
        }

        // equivalence by guid
        return guid().equals(other.guid());
    }

    @Override
    public int hashCode() {
        return guid.hashCode();
    }

    public String guid() {
        return guid;
    }

    public int version() {
        return version;
    }

    public LocalDateTime createdDateTime() {
        return createdDateTime;
    }

    public LocalDateTime lastModifiedDateTime() {
        return lastModifiedDateTime;
    }

    public boolean isNew() {
        return id == null;
    }

    public boolean isPersisted() {
        return id != null;
    }

    public void copyFrom(DomainObject domainObject) {
        this.guid = domainObject.guid;
        this.archived = domainObject.archived;
        this.version = domainObject.version;
        this.createdDateTime = domainObject.createdDateTime;
        this.lastModifiedDateTime = domainObject.lastModifiedDateTime;
    }

}

其他实体继承至这个实体,就可以了。当事务提交时,通过版本来对数据进行校验,如果事务提交时,版本已经被修改了,那本次事务提交失败并回滚。从而保证数据一致性。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值