OAF: 关于"钝化" Passivation

这篇是前段时间那个bug 的续篇. 那个bug 从两年前 Pan 就在搞, 后来老大也在搞, 知道今天才弄明白是什么原因导致的. 我跟这个 bug 整整两个月, 在 ATG 的帮助下, 总算知道了原因.

Passivation, 翻译作”钝化”, 听名字也不知道是干什么的. 开发文档Chapter 6, OA Framework State Persistence Model (Passivation) 里面有详细介绍.
简单来说, 钝化就是在资源消耗非常高时, 应用会把空闲的线程的状态保存到数据库中, 把这些资源给其他用户使用. 当空闲的线程被唤醒时, 保存的状态会被恢复回来. 如果出现 timeout 的情况, 可以用来恢复用户未完成的事务.
但是钝化是有风险的. 如果没有启用钝化, 在一个事务中的多个多个页面中操作, AM 和 DBtxn 都被完全保留下来, 这样以来跟很多数据库连接状态相关的功能都可以用, 比如 PL/SQL EO 可以不用 insertRow() deleteRow() 来插入删除数据.
在开发文档中, PL/SQL Entity Object Design and Development 这一章, 里面说了这么一句”You should call your PL/SQL insert procedure in your insertRow() method”, 是说如果要用 PL/SQL 代码插入数据的话, 那么就要在 insertRow() 里面去调用, 而不是直接调用. 开始我不明白为什么. 文档中紧接着一条warning: “Do not bypass the insert PL/SQL call within your insertRow() method since BC4J doesn’t have any way to know that you didn’t actually perform the insert, and might try to lock the row at some point since it expects it to exist.” 我们这个bug 报的错就是这条 warning 所导致的. 在我们的代码中, 直接调用 PL/SQL 代码插入了表, 绕过了 insertRow(), 导致BC4J 不知道我们插入了数据. 而当OAF 代码用 select for update nowait 尝试锁这条记录的时候, 就报了找不到记录的错. 现在看起来, 原因就是如果启用了钝化, BC4J 又不知道我们插入了数据, 于是钝化的时候把数据库连接session 就丢掉了. 而如果用insertRow() 的话, 插入的数据信息会被AM 保存下来. 钝化的时候AM 中就带有了这个插入信息, 所以之后就不会报错. 根据我的测试, 如果不启用钝化, 那么数据库session 就一直不会丢, 自然不会报错. 如果用insertRow(), 同时启用钝化, 数据库session 会丢掉, 但是依然不会报错.
启用钝化就是在建立 AM 的时候设置一条属性, RETENTION_LEVEL=MANAGE_STATE. 还需要设置一些其他的profile 之类的东西, 但是不重要了, 因为我觉得还是不要启用钝化的好. 因为性能方面未必会好很多, 毕竟把状态写入数据库, 再从数据库读取出来也是要消耗资源的. 况且这可能会带来这种诡异的bug, 太蛋疼了. 而且在开发文档里面, 这一章的开头也说, “Information about the forthcoming passivation feature is provided for preview/planning purposes only; passivation is not supported in Release R12.” 还是不用的好.
root AM 和 DBtxn 是很重要的东西, 在写代码的时候最好能显式释放和刷新. 不仅代码阅读性好一些, 而且能避免一些框架层面的bug, 而这些bug 要跟踪确实会消耗很大的精力.

你可能感兴趣的:(OAF: 关于"钝化" Passivation)