今天是一个小想法,引出一堆问题,一顿扫盲呀,基础很重要呀。这也印证了之前在论坛讨论Grails时我的观点:
[quote]grails不适合新手学习哦~
Grails是一个敏捷的MVC框架,更准确的说是以spring、hibernate为基础的一堆框架的集合。优点就是开发迅速,“容易上手”。
这里,容易上手是针对已经熟悉Java开发的同学:熟悉Servlet、熟悉Spring、熟悉Hibernate等。有这些基础的同学可以很快将Grails运用自如。
但是,Grails不适合作为学习Java Web开发的入门内容,原因就是它太敏捷。没错,照着官方文档,可以很轻松写出Hello World,基于scaffold可以很快搭建出一个小小的原型,新手肯定特别兴奋。但问题就是,当你想要深入一点的时候,会发现缺乏前述各种框架的知识,甚至缺乏对JavaEE的基础知识,然后就会迷失、无从下手。[/quote]
今天的小想法就是想测试一下Grails的乐观锁机制,于是就引出了以下问题:
1. 要测试乐观锁,就需要多线程,而且我想把颗粒度模拟的很细,模拟一些很极端的情况。琢磨半天,发现[size=large]IDEA有多线程debug[/size]的功能(其实大多数IDE都有),用起来老强大了。
[img]http://dl.iteye.com/upload/attachment/0079/0086/9d4f62ba-8d4e-3544-9054-4a1933c95a6e.png[/img]
默认是ALL,也就是单线程的,浏览器B的操作需要等浏览器A的断点完成后才能进行。
[img]http://dl.iteye.com/upload/attachment/0079/0088/60c23734-9408-3baf-a011-f3b991ff7d69.png[/img]
[size=large]改成Thread,就可以debug并发的情况了。两个线程遇到断点都会停下来,还可以选择控制让谁先执行断点,很方便呀。[/size]
2. 有了强大工具支持,可以开始试验了。
[img]http://dl.iteye.com/upload/attachment/0079/0090/443b6fcc-221c-35ad-9fd4-c6d8b2df0a33.png[/img]
如上图,设计了一个试验例子。本以为最终能够模拟出数据一致的情况,但实际却抛出了乐观锁的异常。。。误导我的正是Grails生成的controller update代码,让我误以为需要人为判断version(我还以为这叫乐观锁呢)
[quote] if (testInstance.version > version) {
render(view: "edit", model: [testInstance: testInstance])
return
}[/quote]
错误的理解,需要写代码判断version
正确的理解,[size=large]其实是由Hibernate在save的时候自行判断version,由此实现乐观锁[/size]
3. 好吧,既然你能抛出异常(StaleObjectStateException - Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect),那我就try-catch处理之
[img]http://dl.iteye.com/upload/attachment/0079/0094/cce21c99-34f7-352d-98a6-9ec657a154e6.png[/img]
结果是怎么catch也catch不到。。。百度也烂到家,根本搜不到有用的东西。于是挂上vpn,google是王道。
[quote]try{
getHibernateTemplate().delete(userObj);
} catch (StaleObjectStateException e) {
e.printStackTrace();
}
How do i catch this exception ??
You won't be able to catch it there, because it's not the delete call that throws the exception, but the flush of the session, which happens later (before the execution of a query, or before the transaction commit).
You should not catch this exception anyway, because when Hibernate throws an exception, you can't continue using the session anymore: it's in an unstable state. The only part of the application where such an exception can be caught is outside of the transaction, in order to display an error message to the user (or retry, but this won't be possible in this particular case).
[/quote]
简单的说,就是异常并不是由save()抛出的,而是经过一系列传递由Hibernate抛出的,而且此时会话已经无法使用了。直截了当说,[size=large]这类异常无法捕获[/size]。
这也说明了,为什么Grails生成的代码中,人为判断了一下,这么做可以很大程度上避免异常。(相当于在较长时间的人工录入表单之后,进行了一次version验证,并处理;而只有在像我模拟的极端情况,才会引发异常)
[quote]grails不适合新手学习哦~
Grails是一个敏捷的MVC框架,更准确的说是以spring、hibernate为基础的一堆框架的集合。优点就是开发迅速,“容易上手”。
这里,容易上手是针对已经熟悉Java开发的同学:熟悉Servlet、熟悉Spring、熟悉Hibernate等。有这些基础的同学可以很快将Grails运用自如。
但是,Grails不适合作为学习Java Web开发的入门内容,原因就是它太敏捷。没错,照着官方文档,可以很轻松写出Hello World,基于scaffold可以很快搭建出一个小小的原型,新手肯定特别兴奋。但问题就是,当你想要深入一点的时候,会发现缺乏前述各种框架的知识,甚至缺乏对JavaEE的基础知识,然后就会迷失、无从下手。[/quote]
今天的小想法就是想测试一下Grails的乐观锁机制,于是就引出了以下问题:
1. 要测试乐观锁,就需要多线程,而且我想把颗粒度模拟的很细,模拟一些很极端的情况。琢磨半天,发现[size=large]IDEA有多线程debug[/size]的功能(其实大多数IDE都有),用起来老强大了。
[img]http://dl.iteye.com/upload/attachment/0079/0086/9d4f62ba-8d4e-3544-9054-4a1933c95a6e.png[/img]
默认是ALL,也就是单线程的,浏览器B的操作需要等浏览器A的断点完成后才能进行。
[img]http://dl.iteye.com/upload/attachment/0079/0088/60c23734-9408-3baf-a011-f3b991ff7d69.png[/img]
[size=large]改成Thread,就可以debug并发的情况了。两个线程遇到断点都会停下来,还可以选择控制让谁先执行断点,很方便呀。[/size]
2. 有了强大工具支持,可以开始试验了。
[img]http://dl.iteye.com/upload/attachment/0079/0090/443b6fcc-221c-35ad-9fd4-c6d8b2df0a33.png[/img]
如上图,设计了一个试验例子。本以为最终能够模拟出数据一致的情况,但实际却抛出了乐观锁的异常。。。误导我的正是Grails生成的controller update代码,让我误以为需要人为判断version(我还以为这叫乐观锁呢)
[quote] if (testInstance.version > version) {
render(view: "edit", model: [testInstance: testInstance])
return
}[/quote]
错误的理解,需要写代码判断version
正确的理解,[size=large]其实是由Hibernate在save的时候自行判断version,由此实现乐观锁[/size]
3. 好吧,既然你能抛出异常(StaleObjectStateException - Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect),那我就try-catch处理之
[img]http://dl.iteye.com/upload/attachment/0079/0094/cce21c99-34f7-352d-98a6-9ec657a154e6.png[/img]
结果是怎么catch也catch不到。。。百度也烂到家,根本搜不到有用的东西。于是挂上vpn,google是王道。
[quote]try{
getHibernateTemplate().delete(userObj);
} catch (StaleObjectStateException e) {
e.printStackTrace();
}
How do i catch this exception ??
You won't be able to catch it there, because it's not the delete call that throws the exception, but the flush of the session, which happens later (before the execution of a query, or before the transaction commit).
You should not catch this exception anyway, because when Hibernate throws an exception, you can't continue using the session anymore: it's in an unstable state. The only part of the application where such an exception can be caught is outside of the transaction, in order to display an error message to the user (or retry, but this won't be possible in this particular case).
[/quote]
简单的说,就是异常并不是由save()抛出的,而是经过一系列传递由Hibernate抛出的,而且此时会话已经无法使用了。直截了当说,[size=large]这类异常无法捕获[/size]。
这也说明了,为什么Grails生成的代码中,人为判断了一下,这么做可以很大程度上避免异常。(相当于在较长时间的人工录入表单之后,进行了一次version验证,并处理;而只有在像我模拟的极端情况,才会引发异常)