昨天,Linda DeMichiel 宣布了即将到来的 EJB 3.0 的变化。她的演示中有许多内容需要消化,我认为人们需要一段时间才能弄清楚新规范的全部影响。到目前为止,大部分注意力都集中在实体bean的重设计上,但这绝对不是全部的新内容!专家小组积极采用注解,最终消除了部署描述符XML的困境。借鉴Avalon、Pico、Spring、Hivemind等,EJB将使用依赖注入作为JNDI查找的替代方案。会话bean将是POJO,具有业务接口,已经消除了home对象。随着各种其他变化,这意味着EJB 3.0将是一个更适合基于Web的应用程序的解决方案,这些应用程序将servlet和业务逻辑放置在同一进程中(这无疑是大多数应用程序最合理的部署拓扑),同时不失去处理更复杂的分布式物理架构的能力。
令人惊讶的是,EJB专家小组在EJB3中最需要的方面达成了广泛的共识——从传统的J2EE供应商如BEA到我们这些开源爱好者。用户的声音得到了很多关注,这让我感到惊讶。Linda的领导力也值得赞扬。
但是,无论如何,这是Hibernate博客,所以我要讨论持久性……
EJB 3.0采用了基于POJO的实体bean编程模型,这与我们在Hibernate中使用的方法非常相似。实体bean可能是可序列化的。它们不需要扩展或实现javax.ejb中的任何接口。它们将是具体的类,具有JavaBeans风格的属性访问器。关联将是Set或Collection类型,始终双向,但未管理
。(双向关联的引用完整性在您的对象模型中很容易实现,并且即使在持久对象分离时也适用。)这种模型促进了测试驱动开发,允许在EJB容器之外重用领域模型(特别是,DTO将对于许多应用程序来说将成为过去式)并强调业务问题,而不是容器。
Hibernate查询语言最初基于EJBQL、ANSI SQL和ODMG OQL,现在这个循环已经完成,HQL(最初从SQL和OQL中借用)的特点正在回归到EJBQL中。这些特性包括显式连接(包括外连接)、投影、聚合、子查询。不再有“快速通道读取器”类型的反模式!
此外,EJBQL将增加对批量更新和批量删除的支持(这是我们目前没有的功能)。许多用户都提出了这个请求。
对于偶尔需要增强后的EJBQL的情况,您将能够使用原生的SQL编写查询,并且容器将返回托管实体。
EJB 3.0将用单例EntityManager对象替换实体bean homes。实体可以使用new实例化,然后通过调用create()使其持久化。可以通过调用remove()使其变为瞬时的。EntityManager是查询对象的工厂,可以执行元数据中定义的命名查询,或者通过嵌入的字符串或字符串操作定义的动态查询。EntityManager与Hibernate Session、JDO PersistenceManager、TopLink UnitOfWork或ODMG数据库非常相似——这是一个非常成熟的模式!关联级别的级联样式将提供级联保存和删除。
将有一个完整的ORM元数据规范,通过注解定义。继承最终将被支持,也许还有一些“不错”的特性,如派生属性。
因为每个人都会问……
JDO有什么问题?好吧,在我加入之前,EJB专家小组得出结论,JDO根本不适合ORM模型,这与Hibernate团队以及许多其他人的结论相呼应。JDO规范的核心存在一些问题,这些问题很难解决。
我肯定会因为公开谈论这些问题而受到很多批评,但我觉得我们需要向社区证明这个决定是合理的,因为它影响了社区,并且EG应该对社区负责。我们还需要消除这种印象:这只是“非本地发明”的一个案例。
首先,JDOQL是一个令人厌恶的东西。(我说了。)有四种标准的方式来表达面向对象的查询:查询语言、基于标准的查询、基于示例的查询和原生SQL。JDOQL不属于这些。我不知道JDO EG是如何得出他们选择的设计的,但看起来他们似乎无法在查询语言和基于标准的查询之间做出决定,因此选择了一条奇怪的中间道路,既不具备这两种方法的优点。我建议采用类似HQL的东西,但这是一个没有结果的提议。JDO2中添加对投影和聚合的支持使JDOQL比以前更加丑陋和复杂。这绝对不是我们需要解决的方案!
其次,字段拦截——这是一种实现像Bill Burke的ACID POJOs或JBossCache中的细粒度缓存复制的好方法——结果证明,也许令人惊讶的是,这是实现POJO持久化的完全不合适的方法。当我们将延迟关联获取与分离对象结合使用时,最大的问题就出现了。在基于代理的解决方案中,如果它们在容器上下文之外被访问,我们会从未获取的关联中抛出异常。JDO使用null表示未获取的关联。这最多意味着你得到一个没有意义的NPE而不是LazyInitializationException。最坏的情况是,你的代码可能会误解null的语义,并假设没有关联对象。这是绝对不能接受的,而且似乎没有方法来修复JDO以解决这个问题,除非基本上重新设计JDO。(与Hibernate和TopLink不同,JDO不是为支持分离和重新连接而设计的。)
基于代理的解决方案还有一些其他的好处,比如能够在不实际从数据库中获取对象的情况下创建一个与对象关联的关联,以及能够发现一个关联对象的主键而不获取它。这些都是非常有用的特性。
最后,JDO 规范过于复杂,定义了三种——现在四种——身份类型,而只需要一种;还有无数的生存周期状态和转换,而实际上只需要三种状态(持久、瞬态、分离)并且充斥着诸如《瞬态事务》实例等无用的特性。再次强调,这些内容很难更改——整个规范都需要重写。
因此,而不是重写 JDO,EJB 3.0 实体将基于(更广泛采用的)专用 ORM 解决方案,如 Hibernate 和 TopLink。