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语句对数据不加锁
2. 如果改成.setLockMode(LockModeType.PESSIMISTIC_READ), 则会产生死锁
3. 如果改成.setLockMode(LockModeType.PESSIMISTIC_WRITE), 才能保证数据安全, 避免脏读问题