您好,登錄后才能下訂單哦!
這篇文章主要介紹“如何使用JPA加鎖機制”,在日常操作中,相信很多人在如何使用JPA加鎖機制問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”如何使用JPA加鎖機制”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!
JPA的加鎖機制有兩種,樂觀鎖和悲觀鎖。
樂觀鎖:
樂觀鎖的特點在于認為數據沖突或者更新丟失等情況是很少發生的.當發生的時候,拋出異常和回滾就足夠解決問題.
悲觀鎖:
悲觀鎖的邏輯在于認為每次數據操作都很有可能發生沖突,所以一開始就獲得記錄的鎖,再進行記錄的操作是解決問題的優先選擇.
悲觀鎖通常是SQL級別的,通過讀寫時先拿到鎖實現,在SQL語句中就會有體現.
return em.createQuery(sql 語句).setLockMode(LockModeType.NONE).getResultList(); //分解寫法大概是: Query query = getSession().createQuery(hql); query.setLockMode(LockModeType.NONE);
EntityManager 是一個輔助類,createQuery后返回的就是一個Query對象,然后通過
setLockMode設置鎖的級別即可.
LockModeType 類型 | 解釋 |
---|---|
LockMode.READ | 事務的隔離級別是Repeatable Read或Serializable時,請求讀取數據庫記錄時自動獲得 |
LockMode.WRITE | 請求插入或更新數據庫記錄時自動獲得 |
LockMode.OPTIMISTIC | 樂觀鎖 |
LockMode.OPTIMISTIC_FORCE_INCREMENT | 樂觀鎖,通過version控制 |
LockMode.PESSIMISTIC_READ | 與LockMode.PESSIMISTIC_WRITE相同 |
LockMode.PESSIMISTIC_WRITE | 事務開始即獲得數據庫的鎖 |
LockMode.PESSIMISTIC_FORCE_INCREMENT | 事務開始即設置version |
LockMode.NONE | 取消任何鎖,如事務結束后的所有對象,或執行了Session的update()、 |
樂觀鎖本篇的主要內容
實體類是關鍵 , 樂觀鎖常用方法是通過version來控制 ,
數據庫對應的表中需要有一個字段(名字隨意),字段類型設置成BigInt即可
業務不對該字段進行控制,字段的控制交由系統處理
每一次修改都會導致version遞增
當出現同時獲得該記錄的對象且均需要修改時,當第一個已經提交事務,version字段發生改變,后面提交的事務發現version版本不對,則無法提交,拋出異常
@Entity public class User { @Id @GeneratedValue private Long id; private String username; private String userdesc; @Version private Long version; public User() { } public User(String username, String userdesc) { this.username = username; this.userdesc = userdesc; } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getUserDesc() { return userdesc; } public void setUserDesc(String userdesc) { this.userdesc = userdesc; } public Long getVersion() { return version; } public void setVersion(Long version) { this.version = version; } }
controller中通過sleep將線程沉睡,測試事務的提交性
@RestController public class UserController { private Logger logger = LoggerFactory.getLogger(getClass()); @Autowired UserService userService; @PostMapping("/changeone") @Transactional public String changeone() { User user = userService.findUser("gang"); try { logger.info("修改1 before:user--{}--Versdion:{}", user.getUserDesc(), user.getVersion()); Thread.sleep(25000); user.setUserDesc("修改1"); logger.info("修改1 :user--{}--version:{}", user.getUserDesc(), user.getVersion()); } catch (InterruptedException e) { e.printStackTrace(); } catch (Exception e) { logger.info("eeeeeeeeeeeeee"); e.printStackTrace(); } return "true"; } @PostMapping("/changetwo") @Transactional public String changetwo() { User user = userService.findUser("gang"); try { logger.info("修改2 before:user--{}--version:{}", user.getUserDesc(), user.getVersion()); Thread.sleep(30000); user.setUserDesc("修改2"); logger.info("修改2:user--{}--version:{}", user.getUserDesc(), user.getVersion()); } catch (InterruptedException e) { e.printStackTrace(); } catch (Exception e) { logger.info("eeeeeeeeeeeeee"); e.printStackTrace(); } return "true"; } @PostMapping("/changethree") @Transactional public String changethree() { User user = userService.findUser("gang"); logger.info("修改3 before:user--{}--version:{}", user.getUserDesc(), user.getVersion()); user.setUserDesc("修改3"); logger.info("修改3 :user--{}--version:{}", user.getUserDesc(), user.getVersion()); return "true"; } @PostMapping("/newuser") @Transactional public String newuser() { logger.info("save user"); User user = new User(); user.setUserDesc("第一次創建"); user.setUsername("gang"); userService.saveUser(user); return "true"; } }
以及service及repository
@Service public class UserService { @Autowired UserRepository userRepository; public User findUser(String username){ return userRepository.findByUsername(username); } public void saveUser(User user){ userRepository.save(user); } } UserRepository public interface UserRepository extends JpaRepository<User,Long> { User findByUsername(String username); }
使用很簡單,version是自動增長的,唯一的缺點是拋出的異常不易捕獲,捕獲的方法:
@Resource private UserTransaction rtc; try { rtc.begin(); User user = userService.findUser("gang"); user .setDesc("異常捕獲"); rtc.commit(); } catch (OptimisticLockException e) { throw new OptimisticLockException (); } catch (Exception e) { throw new Exception (); }
注意其中的 rtc.begin(); 以及 rtc.commit();
不同于@Transaction,這種是手動的提交方法
到此,關于“如何使用JPA加鎖機制”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。