2016年9月12日 | Leave a comment 问题: 多台服务器通过JPA操作一条记录,如何避免出现脏数据? 代码如下: /** * 测试锁 * * @throws InterruptedException */ @Test public void testLock() throws InterruptedException { final ExecutorService es = Executors.newFixedThreadPool(20); long c = JPAUtils.queryLong(Config.getEM(), "select quantity from store_item where id=1", null); for (int n = 0; n < 20; ++n) { es.submit(() -> { for (int i = 0; i < 100; ++i) { EntityManager em = Config.getEM(); em.getTransaction().begin(); StoreItem si = em.find(StoreItem.class, 1);//,LockModeType.PESSIMISTIC_READ ok si.setQuantity(si.getQuantity() + 1); em.merge(si); em.getTransaction().commit(); em.close(); } }); } es.shutdown(); es.awaitTermination(60, TimeUnit.SECONDS); long c2 = JPAUtils.queryLong(Config.getEM(), "select quantity from store_item where id=1", null); assertEquals(c + (100 * 20), c2); } 12345678910111213141516171819202122232425262728 /** * 测试锁 * * @throws InterruptedException */ @Test public void testLock() throws InterruptedException { final ExecutorService es = Executors.newFixedThreadPool(20); long c = JPAUtils.queryLong(Config.getEM(), "select quantity from store_item where id=1", null); for (int n = 0; n < 20; ++n) { es.submit(() -> { for (int i = 0; i < 100; ++i) { EntityManager em = Config.getEM(); em.getTransaction().begin(); StoreItem si = em.find(StoreItem.class, 1);//,LockModeType.PESSIMISTIC_READ ok si.setQuantity(si.getQuantity() + 1); em.merge(si); em.getTransaction().commit(); em.close(); } }); } es.shutdown(); es.awaitTermination(60, TimeUnit.SECONDS); long c2 = JPAUtils.queryLong(Config.getEM(), "select quantity from store_item where id=1", null); assertEquals(c + (100 * 20), c2); } 解决: 读锁是最简单的, em.find(StoreItem.class, 1) 改成 em.find(StoreItem.class, 1, LockModeType.PESSIMISTIC_READ)//读出来就加上锁 123 em.find(StoreItem.class, 1) 改成em.find(StoreItem.class, 1, LockModeType.PESSIMISTIC_READ)//读出来就加上锁 2. 参考: