JPA 加锁机制及@Version版本控制方式

网友投稿 1185 2022-12-01

JPA 加锁机制及@Version版本控制方式

JPA 加锁机制及@Version版本控制方式

目录一 简述悲观锁的用法1.1 EntityManager 用法二 乐观锁的详细用法实体类(注意其中的@Version注解)总结

JPA的加锁机制有两种,乐观锁和悲观锁。

乐观锁:

乐观锁的特点在于认为数据冲突或者更新丢失等情况是很少发生的.当发生的时候,抛出异常和回滚就足够解决问题.

悲观锁:

悲观锁的逻辑在于认为每次数据操作都很有可能发生冲突,所以一开始就获得记录的锁,再进行记录的操作是解决问题的优先选择.

一 简述悲观锁的用法

悲观锁通常是SQL级别的,通过读写时先拿到锁实现,在SQL语句中就会有体现.

1.1 EntityManager 用法

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版本不对,则无法提交,抛出异常

实体类(注意其中的@Version注解)

@Entity

public class User {

@Id

@GeneratedValue

private Long id;

private String username;

private String userdesc;

@Version

http:// 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.gkYZESCBlkIetVersion());

} 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 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,这种是手动的提交方法

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:x Problem B
下一篇:C Need for Pink Slips
相关文章

 发表评论

暂时没有评论,来抢沙发吧~