hibernate查询使用默认锁,加读锁,加写锁测试
UserDao
@Repository
public class UserDao {
@PersistenceContext
private EntityManager entityManager;
public User get(Long id) {
String hql = "select u from User u where id = :id";
return entityManager.createQuery(hql, User.class).setParameter("id", id)
.setLockMode(LockModeType.PESSIMISTIC_READ)
.getSingleResult();
}
public void update(Integer age, Long id) {
String hql = "update User set age = :age where id = :id";
entityManager.createQuery(hql).setParameter("age", age).setParameter("id", id).executeUpdate();
}
}
UserService
@Service
@Transactional
public class UserService {
@Autowired
private UserDao userDao;
public void update() {
User user = userDao.get(1L);
try {
TimeUnit.MILLISECONDS.sleep(50);
}catch (Exception e){
}
userDao.update(user.getAge()+1,1L);
}
public class InnerThread implements Runnable{
@Override
public void run() {
update();
}
}
}
Test
@Test
public void contextLoads(){
for(int i =0;i<2;i++){
new Thread(userService.new InnerThread()).start();
}
try {
TimeUnit.SECONDS.sleep(5);
}catch (Exception e){
}
System.out.println("over");
}
1. 如果UserDao里的get语句把.setLockMode注释, 则存在第二类丢失更新, 两次update, 实际上只做了一次. 说明默认情况下, select语句对数据不加锁, RR和RC隔离级别的读是一致性非锁定读, 即快照读
2. 如果改成.setLockMode(LockModeType.PESSIMISTIC_READ), 则会产生死锁
3. 如果改成.setLockMode(LockModeType.PESSIMISTIC_WRITE), 才能保证数据安全, 避免第二类丢失更新
4. setLocalMode加锁模式, 使用的是DB底层的悲观锁原理, 此外还可以通过hibernate提供的乐观锁来做数据安全控制