并发现象
public class Demo { public Integer count = 0; public static void main(String[] args) { final Demo demo = new Demo(); Executor executor = Executors.newFixedThreadPool(10); for(int i=0;i<1000;i++){ executor.execute(new Runnable() { @Override public void run() { demo.count++; } }); } try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("final count value:"+demo1.count); } }
并发导致读到脏数据。
实际到数据库中的操作
充血模型遭遇并发(将行为和属性都加上,简单理解为bean加上数据库的操作方法)
@Component public class Demo2 { @Autowired TestNumDao testNumDao; @Transactional public void test(){ TestNum testNum = testNumDao.findOne("1"); testNum.setCount(testNum.getCount()+1); testNumDao.save(testNum); } } //多线程进行操作 Demo2 demo2; public String test(){ Executor executor = Executors.newFixedThreadPool(10); for(int i=0;i<1000;i++){ executor.execute(new Runnable() { @Override public void run() { demo2.test(); } }); } return "test"; }
final count value:973
贫血模型遭遇并发(进行行为和属性的分离,分离出dao)
@RequestMapping("testSql") @ResponseBody public String testSql() throws InterruptedException { final CountDownLatch countDownLatch = new CountDownLatch(1000); long start = System.currentTimeMillis(); Executor executor = Executors.newFixedThreadPool(10); for(int i=0;i<1000;i++){ executor.execute(new Runnable() { @Override public void run() { jdbcTemplate.execute("update test_num set count = count + 1 where id = ‘1‘"); countDownLatch.countDown(); } }); } countDownLatch.await(); long costTime =System.currentTimeMillis() - start; System.out.println("共花费:"+costTime+" s"); return "testSql"; }
count : 1000
修改个人信息:非并发
//Transaction start User user = userDao.findById("1"); user.setName("newName"); user.setAge(user.getAge()+1); ...//其他耗时操作 userDao.save(user); //Transaction commit
修改商品信息:并发,场景乐观
class Goods{ @Version //使用乐观锁,修改成功后版本号变化,另一个操作员失败 int version; } //Transaction start try{ Goods goods = goodsDao.findById("1"); goods.setName("newName"); goods.setPrice(goods.getPrice()+100.00); ...//其他耗时操作 goodsDao.save(goods); }catch(org.hibernate.StaleObjectStateException e){ //返回给前台 } //Transaction commit
扣除账号余额:并发,场景不乐观
update set balance = balance – money where userId = ? and balance >= money; update stock = stock – number where goodsId = ? and stock >= number ;
然后在后台 查看返回值是否影响行数为1,判断请求是否成功,利用数据库保证并发。
数据库行级锁