Spring dat jpa@version楽観ロック
15252 ワード
前言
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
他のエンティティをこのエンティティに継承すればいいです.トランザクションがコミットされると、バージョンによってデータが検証され、トランザクションがコミットされたときにバージョンが変更された場合、今回のトランザクションのコミットに失敗し、ロールバックされます.これにより、データの一貫性が保証されます.
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;
}
}
他のエンティティをこのエンティティに継承すればいいです.トランザクションがコミットされると、バージョンによってデータが検証され、トランザクションがコミットされたときにバージョンが変更された場合、今回のトランザクションのコミットに失敗し、ロールバックされます.これにより、データの一貫性が保証されます.