溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶(hù)服務(wù)條款》

如何使用JPA加鎖機(jī)制

發(fā)布時(shí)間:2021-10-15 11:17:33 來(lái)源:億速云 閱讀:463 作者:iii 欄目:開(kāi)發(fā)技術(shù)

這篇文章主要介紹“如何使用JPA加鎖機(jī)制”,在日常操作中,相信很多人在如何使用JPA加鎖機(jī)制問(wèn)題上存在疑惑,小編查閱了各式資料,整理出簡(jiǎn)單好用的操作方法,希望對(duì)大家解答”如何使用JPA加鎖機(jī)制”的疑惑有所幫助!接下來(lái),請(qǐng)跟著小編一起來(lái)學(xué)習(xí)吧!

    JPA的加鎖機(jī)制有兩種,樂(lè)觀(guān)鎖和悲觀(guān)鎖。

    樂(lè)觀(guān)鎖:

    樂(lè)觀(guān)鎖的特點(diǎn)在于認(rèn)為數(shù)據(jù)沖突或者更新丟失等情況是很少發(fā)生的.當(dāng)發(fā)生的時(shí)候,拋出異常和回滾就足夠解決問(wèn)題.

    悲觀(guān)鎖:

    悲觀(guān)鎖的邏輯在于認(rèn)為每次數(shù)據(jù)操作都很有可能發(fā)生沖突,所以一開(kāi)始就獲得記錄的鎖,再進(jìn)行記錄的操作是解決問(wèn)題的優(yōu)先選擇.

    一 簡(jiǎn)述悲觀(guān)鎖的用法

    悲觀(guān)鎖通常是SQL級(jí)別的,通過(guò)讀寫(xiě)時(shí)先拿到鎖實(shí)現(xiàn),在SQL語(yǔ)句中就會(huì)有體現(xiàn).

    1.1 EntityManager 用法

    return em.createQuery(sql 語(yǔ)句).setLockMode(LockModeType.NONE).getResultList();
        //分解寫(xiě)法大概是:
        Query query = getSession().createQuery(hql);
        query.setLockMode(LockModeType.NONE);

    EntityManager 是一個(gè)輔助類(lèi),createQuery后返回的就是一個(gè)Query對(duì)象,然后通過(guò)

    setLockMode設(shè)置鎖的級(jí)別即可.

    LockModeType 類(lèi)型解釋
    LockMode.READ事務(wù)的隔離級(jí)別是Repeatable Read或Serializable時(shí),請(qǐng)求讀取數(shù)據(jù)庫(kù)記錄時(shí)自動(dòng)獲得
    LockMode.WRITE請(qǐng)求插入或更新數(shù)據(jù)庫(kù)記錄時(shí)自動(dòng)獲得
    LockMode.OPTIMISTIC樂(lè)觀(guān)鎖
    LockMode.OPTIMISTIC_FORCE_INCREMENT樂(lè)觀(guān)鎖,通過(guò)version控制
    LockMode.PESSIMISTIC_READ與LockMode.PESSIMISTIC_WRITE相同
    LockMode.PESSIMISTIC_WRITE事務(wù)開(kāi)始即獲得數(shù)據(jù)庫(kù)的鎖
    LockMode.PESSIMISTIC_FORCE_INCREMENT事務(wù)開(kāi)始即設(shè)置version
    LockMode.NONE取消任何鎖,如事務(wù)結(jié)束后的所有對(duì)象,或執(zhí)行了Session的update()、

    二 樂(lè)觀(guān)鎖的詳細(xì)用法

    樂(lè)觀(guān)鎖本篇的主要內(nèi)容

    實(shí)體類(lèi)是關(guān)鍵 , 樂(lè)觀(guān)鎖常用方法是通過(guò)version來(lái)控制 ,

    • 數(shù)據(jù)庫(kù)對(duì)應(yīng)的表中需要有一個(gè)字段(名字隨意),字段類(lèi)型設(shè)置成BigInt即可

    • 業(yè)務(wù)不對(duì)該字段進(jìn)行控制,字段的控制交由系統(tǒng)處理

    • 每一次修改都會(huì)導(dǎo)致version遞增

    • 當(dāng)出現(xiàn)同時(shí)獲得該記錄的對(duì)象且均需要修改時(shí),當(dāng)?shù)谝粋€(gè)已經(jīng)提交事務(wù),version字段發(fā)生改變,后面提交的事務(wù)發(fā)現(xiàn)version版本不對(duì),則無(wú)法提交,拋出異常

    實(shí)體類(lèi)(注意其中的@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中通過(guò)sleep將線(xiàn)程沉睡,測(cè)試事務(wù)的提交性

    @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("第一次創(chuàng)建");
            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);
    }

    總結(jié)

    使用很簡(jiǎn)單,version是自動(dòng)增長(zhǎng)的,唯一的缺點(diǎn)是拋出的異常不易捕獲,捕獲的方法:

    @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,這種是手動(dòng)的提交方法

    到此,關(guān)于“如何使用JPA加鎖機(jī)制”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識(shí),請(qǐng)繼續(xù)關(guān)注億速云網(wǎng)站,小編會(huì)繼續(xù)努力為大家?guī)?lái)更多實(shí)用的文章!

    向AI問(wèn)一下細(xì)節(jié)

    免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

    jpa
    AI