Grails的乐观锁产生的异常无法捕获

今天是一个小想法,引出一堆问题,一顿扫盲呀,基础很重要呀。这也印证了之前在论坛讨论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验证,并处理;而只有在像我模拟的极端情况,才会引发异常)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1. 简介 2. 起步 2.1 下载并安装Grails 2.2 创建一个Grails应用 2.3 Hello World示例 2.4 使用IDE 2.5 规约配置 2.6 运行Grails应用 2.7 测试Grails应用 2.8 部署Grails应用 2.9 所支持的Java EE容器 2.10 创建工件 2.11 生成Grails应用 3. 配置 3.1 基本配置 3.1.1 内置选项 3.1.2 日志 3.2 环境 3.3 数据源 3.3.1 数据源和环境 3.3.2 JNDI数据源 3.3.3 自动数据库移植 3.4 外部配置 3.5 定义版本 4. 命令行 4.1 创建Gant脚本 4.2 可复用的Grails脚本 4.3 脚本中的事件 4.4 Ant和Maven 5. 对象关系映射(GORM) 5.1 快速指南 5.1.1 基本的CRUD 5.2 在GORM中进行领域建模 5.2.1 GORM中的关联 5.2.1.1 一对一 5.2.1.2 一对多 5.2.1.3 多对多 5.2.2 GORM的组合 5.2.3 GORM的继承 5.2.4 集合、列表和映射 5.3 持久化基础 5.3.1 保存和更新 5.3.2 删除对象 5.3.3 级联更新和删除 5.3.4 立即加载和延迟加载 5.3.4 悲观乐观 5.4 GORM查询 5.4.1 动态查找器 5.4.2 条件查询 5.4.3 Hibernate查询语言 5.5 高级GORM特性 5.5.1 事件和自动实现时间戳 5.5.2 自定义ORM映射 5.5.2.1 表名和列名 5.5.2.2 缓存策略 5.5.2.3 继承策略 5.5.2.4 自定义数据库标识符 5.5.2.5 复合主键 5.5.2.6 数据库索引 5.5.2.7 乐观和版本定义 5.5.2.8 立即加载和延迟加载 5.6 事务编程 5.7 GORM和约束 6. Web层 6.1 控制器 6.1.1 理解控制器和操作 6.1.2 控制器和作用域 6.1.3 模型和视图 6.1.4 重定向和链 6.1.5 控制器拦截器 6.1.6 数据绑定 6.1.7 XML和JSON响应 6.1.8 上传文件 6.1.9 命令对象 6.2 Groovy Server Pages 6.2.1 GSP基础 6.2.1.1 变量和作用域 6.2.1.2 逻辑和迭代 6.2.1.3 页面指令 6.2.1.4 表达式 6.2.2 GSP标签 6.2.2.1 变量和作用域 6.2.2.2 逻辑和迭代 6.2.2.3 搜索和过滤 6.2.2.4 链接和资源 6.2.2.5 表单和字段 6.2.2.6 标签作为方法调用 6.2.3 视图和模板 6.2.4 使用Sitemesh布局 6.3 标签库 6.3.1 简单标签 6.3.2 逻辑标签 6.3.3 迭代标签 6.3.4 标签命名空间 6.4 URL映射 6.4.1 映射到控制器和操作 6.4.2 嵌入式变量 6.4.3 映射到视图 6.4.4 映射到响应代码 6.4.5 映射到HTTP方法 6.4.6 映射通配符 6.4.7 自动重写链接 6.4.8 应用约束 6.5 Web Flow 6.5.1 开始和结束状态 6.5.2 操作状态和视图状态 6.5.3 流执行事件 6.5.4 流的作用域 6.5.5 数据绑定和验证 6.5.6 子流程和会话 6.6 过滤器 6.6.1 应用过滤器 6.6.2 过滤器的类型 6.6.3 过滤器的功能 6.7 Ajax 6.7.1 用Prototype实现Ajax 6.7.1.1 异步链接 6.7.1.2 更新内容 6.7.1.3 异步表单提交 6.7.1.4 Ajax事件 6.7.2 用Dojo实现Ajax 6.7.3 用GWT实现Ajax 6.7.4 服务端的Ajax 6.8 内容协商 7. 验证 7.1 声明约束 7.2 验证约束 7.3 客户端验证 7.4 验证和国际化 8. 服务层 8.1 声明式事务 8.2 服务的作用域 8.3 依赖注入和服务 8.4 使用Java的服务 9. 测试 9.1 单元测试 9.2 集成测试 9.3 功能测试 10. 国际化 10.1 理解信息绑定 10.2 改变Locales 10.3 读取信息 11. 安全 11.1 预防攻击 11.2 字符串的编码和解码 11.3 身份验证 11.4 关于安全的插件 11.4.1 Acegi 11.4.2 JSecurity 12 插件 12.1 创建和安装插件 12.2 理解插件的结构 12.3 提供基础的工件 12.4 评估规约 12.5 参与构建事件 12.6 参与运行时配置 12.7 运行时添加动态方法 12.8 参与自动重载 12.9 理解插件加载的顺序 13. Web服务 13.1 REST 13.2 SOAP 13.3 RSS和Atom 14. Grails和Spring 14.1 Grails的支柱 14.2 配置其他Bean 14.3 通过Beans DSL运行Spring 14.4 配置属性占位 14.5 配置属性重载 15. Grails和Hibernate 15.1 通过Hibernate注释进行映射 15.2 深入了解 16. 脚手架

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值