介紹
當涉及到企業應用程序時,正確地管理對數據庫的並發訪問是至關重要的。為此,我們可以使用Java Persistence API提供的樂觀鎖定機制。它導致在同一時間對同一數據進行多次更新不會相互干擾。為了使用OptimisticLocking,我們需要一個實體(Entity),其中包含一個帶有@Version注釋的屬性。在使用它時,每個讀取數據的事務都持有version屬性的值。在事務想要進行更新之前,它將再次檢查version屬性。如果值在此期間發生了更改,則拋出ObjectOptimisticLockingFailureException。否則,事務提交update並遞增version的值。這種機制適用於讀操作比更新或刪除操作多得多的應用程序。
新建一個UserEntity.java
@Entity
@Table(name = "user")
@Data
@OptimisticLocking
public class User {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Integer id;
@Column(name = "username", unique = true, nullable = true, length = 50)
private String username;
private String password;
@Version
private Integer version;
@PrePersist
public void prePersist() {
version = 0;
}
}
spring data jpa在上一篇文章已經做過一些講解了【快學springboot】7.使用Spring Boot Jpa。感興趣的朋友可以看看。這里定義了一個version字段,使用了Version注解標識。PrePersist這個注解表示在新增數據之前執行。
新建UserRepo接口
public interface UserRepo extends PagingAndSortingRepository<User, Integer>, JpaSpecificationExecutor<User> {
}
新建一個UserTest類,繼承SpringbootApplicationTests
public class UserTest extends SpringbootApplicationTests {
}
SpringbootApplicationTests這個類是使用Spring initialize新建項目的時候自動生成的用來做單元測試的類。在UserTest上注入UserRepo,並且寫一個新增user的單測。

執行之后查看數據庫。

該記錄已經被創建出來了。
測試update該記錄

執行后查看數據庫:

可以看到version字段自增了1。
測試JPA樂觀鎖
新建一個方法,如下

這里查詢了兩次id為1的記錄,然后分別更新了這條記錄。根據前面的描述,這里會拋出一個ObjectOptimisticLockingFailureException異常。啟動測試,結果如下:

這是符合預期的。看下數據庫的version,在這種情況下,我們的預期結果是version變為2。

通過數據庫的值查看,測試都是符合預期的。
去掉User的OptimisticLocking注解
我們把User實體的OptimisticLocking注解去掉,然后再次執行上面的方法。

這一次程序順利執行了,然后查看下數據庫的記錄:
預期應該是version會變為3,然后username變為happyjava-new2。

通過結果來看,這是符合預期的。
總結
spring data jpa通過OptimisticLocking實現了樂觀鎖,該樂觀鎖不是通過數據庫自身去實現的,它是通過version字段(需要Version注解標識)去實現的。如果update的數據時候,發現數據庫的version大於等於當前的version,則會拋出ObjectOptimisticLockingFailureException,錯誤信息是
Row was updated or deleted by another transaction
