日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

Spring Data JPA 从入门到精通~@Version处理乐观锁的问题

發布時間:2024/7/23 javascript 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Spring Data JPA 从入门到精通~@Version处理乐观锁的问题 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

@Version 處理樂觀鎖的問題

@Version 樂觀鎖介紹

我們在研究 Auditing 的時候,發現了一個有趣的注解 @Version,源碼如下:

package org.springframework.data.annotation; /*** Demarcates a property to be used as version field to implement optimistic locking on entities.*/ @Retention(RUNTIME) @Target(value = { FIELD, METHOD, ANNOTATION_TYPE }) public @interface Version {}

發現它幫我們處理了樂觀鎖的問題,什么是樂觀鎖,還有線程的安全性,在另外一本書《Java 并發編程從入門到精通》里面,或者看作者的另外一篇 Chat:Java 多線程與并發編程 · Java 工程師必知必會,作者做了深入的探討。

對于數據來說,簡單理解:在數據庫并發操作時,為了保證數據的正確性,我們會做一些并發處理,主要就是加鎖。在加鎖的選擇上,常見有兩種方式:悲觀鎖和樂觀鎖。

  • 悲觀鎖:簡單的理解就是把需要的數據全部加鎖,在事務提交之前,這些數據全部不可讀取和修改。
  • 樂觀鎖:使用對單條數據進行版本校驗和比較,來對保證本次的更新是最新的,否則就失敗,效率要高很多。在實際工作中,樂觀鎖不止在數據庫層面,其實我們在做分布式系統的時候,為了實現分布式系統的數據一致性,分布式事物的一種做法就是樂觀鎖。

數據庫操作舉例說明

悲觀鎖的做法:

select * from user where id=1 for update; update user set name='jack' where id=1;

通過使用 for update 給這條語句加鎖,如果事務沒有提交,其他任何讀取和修改,都得排隊等待。在代碼中,我們加事務的 Java 方法就會自然的形成了一個鎖。

樂觀鎖的做法:

select uid,name,version from user where id=1; update user set name='jack', version=version+1 where id=1 and version=1

假設本次查詢 version=1,在更新操作時,帶上這次查出來的 Version,這樣只有和我們上次版本一樣的時候才會更新,就不會出現互相覆蓋的問題,保證了數據的原子性。

@Version 用法

在沒有 @Version 之前,我們都是自己手動維護這個 Version 的,這樣很有可能做什么操作的時候給忘掉。或者是我們自己底層做框架,用 AOP 的思路做攔截底層維護這個 Version 的值。而 Spring Data JPA 的 @Version 就是通過 AOP 機制,幫我們動態維護這個 Version,從而更優雅的實現樂觀鎖。

(1)實體上的 Version 字段加上 @Version 注解即可。

我們對上面的實體 UserCustomerEntity 改進如下:

@Entity @Table(name = "user_customer", schema = "test", catalog = "") public class UserCustomerEntity extends AbstractAuditable {//新增控制樂觀鎖的字段。并且加上@Version注解@Version@Column(name = "version", nullable = true)private Long version; ...... }

(2)實際調用

userCustomerRepository.save(new UserCustomerEntity("1","Jack")); UserCustomerEntity uc= userCustomerRepository.findOne(1); uc.setCustomerName("Jack.Zhang"); userCustomerRepository.save(uc);

我們會發現 Insert 和 Update 的 SQL 語句都會帶上 Version 的操作。當樂觀鎖更新失敗的時候,會拋出異常 org.springframework.orm.ObjectOptimisticLockingFailureException。

實現原理關鍵代碼

(1)SimpleJpaRepository.class 里面的 save 方法如下:

public <S extends T> S save(S entity) {if (entityInformation.isNew(entity)) {em.persist(entity);return entity;} else {return em.merge(entity);} }

(2)如果我們在此處設置一個 debug 斷點的話,我們一步一步往下面走會發現進入 JpaMetamodelEntityInformation.class 的關鍵代碼如下:

@Overridepublic boolean isNew(T entity) {if (!versionAttribute.isPresent()|| versionAttribute.map(Attribute::getJavaType).map(Class::isPrimitive).orElse(false)) {return super.isNew(entity);}BeanWrapper wrapper = new DirectFieldAccessFallbackBeanWrapper(entity);return versionAttribute.map(it -> wrapper.getPropertyValue(it.getName()) == null).orElse(true);}

所以到這里,可以看出當我們更新的時候,若實體對象上面有 @Version 注解,那么就一定要帶上 version,如果沒帶上 version 字段的值,只有 ID 字段的值,系統也會認為是新增。相反,如果我們沒有 @Version 注解的字段,那么就會以 @ID 字段來判斷是否是新增。其實這里我們也明白,省去了傳統都需要我們自己去實現的 saveOrUpdate 方法。

(3)其實我們多看看代碼,多 debug 幾次就會發現,也可以在 @Entity 的類里面覆蓋掉 isNew() 方法,這樣可以實現自己的 isNew 的判斷邏輯。

@Entity @Table(name = "user") public class UserEntity implements Persistable {@Transient //這個注解表明這個字段不是持久化的@JsonIgnore //json顯示的時候我們也可忽略這個字段@Overridepublic boolean isNew() {return getId() == null;}.... }

總結

以上是生活随笔為你收集整理的Spring Data JPA 从入门到精通~@Version处理乐观锁的问题的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。