【发布时间】:2010-07-11 20:52:07
【问题描述】:
我正在尝试将 JDBC Web 应用程序迁移到 JDO DataNucleus 2.1.1。
假设我有一些看起来像这样的类:
公共类职位{ 私人整数 id; 私有字符串标题; }
公共类员工{ 私人整数 id; 私有字符串名称; 私人职位职位; }
Position SQL 表的内容确实不会经常更改。使用 JDBC,我将整个表读入内存(能够定期或随意刷新)。然后,当我将 Employee 读入内存时,我只需从 Employee 表中检索职位 ID 并使用它来获取内存中的 Position 实例。
但是,使用 DataNucleus,如果我遍历所有位置:
Extent<Position> extent =pm.getExtent(Position.class, true);
Iterator<Position> iter =extent.iterator();
while(iter.hasNext()) {
Position position =iterPosition.next();
System.out.println(position.toString());
}
然后,使用不同的 PersistenceManager,遍历所有员工,获得他们的职位:
Extent<Employee> extent =pm.getExtent(Employee.class, true);
Iterator<Employee> iter =extent.iterator();
while(iter.hasNext()) {
Employee employee =iter.next();
System.out.println(employee.getPosition());
}
然后,当我获得 Employee's Position 时,DataNucleus 似乎会生成连接两个表的 SQL:
SELECT A0.POSITION_ID,B0.ID,B0.TITLE FROM MYSCHEMA.EMPLOYEE A0 LEFT OUTER JOIN MYSCHEMA."POSITION" B0 ON A0.POSITION_ID = B0.ID WHERE A0.ID =
我的理解是,DataNucleus 将使用缓存的 Position 实例(如果可用)。 (对吗?)但是,我担心连接会降低性能。我还远远不够运行基准测试。我的恐惧是不是错位了?我应该继续并进行基准测试吗?有没有办法让 DataNucleus 避免加入?
<jdo>
<package name="com.example.staff">
<class name="Position" identity-type="application" schema="MYSCHEMA" table="Position">
<inheritance strategy="new-table"/>
<field name="id" primary-key="true">
<column name="ID" jdbc-type="integer"/>
</field>
<field name="title">
<column name="TITLE" jdbc-type="varchar"/>
</field>
</class>
</package>
</jdo>
<jdo>
<package name="com.example.staff">
<class name="Employee" identity-type="application" schema="MYSCHEMA" table="EMPLOYEE">
<inheritance strategy="new-table"/>
<field name="id" primary-key="true">
<column name="ID" jdbc-type="integer"/>
</field>
<field name="name">
<column name="NAME" jdbc-type="varchar"/>
</field>
<field name="position" table="Position">
<column name="POSITION_ID" jdbc-type="int" />
<join column="ID" />
</field>
</class>
</package>
</jdo>
我想我希望能够做的是告诉 DataNucleus 继续读取 POSITION_ID int 作为默认提取组的一部分,并查看相应的位置是否已被缓存。如果是这样,则设置该字段。如果没有,则稍后再加入,如果需要的话。更好的是,继续将该 int ID 存储在某处,并在稍后调用 getPosition() 时使用它。这将避免在所有情况下加入。
我认为知道类和主键值就足以避免幼稚的情况,但我对 DataNucleus 的了解还不够。
根据我收到的有用反馈,我的 .jdo 现已清理完毕。但是,在将 POSITION_ID 字段添加到默认提取组后,我仍然得到一个加入。
SELECT 'com.example.staff.Employee' AS NUCLEUS_TYPE,A0.ID,A0."NAME",A0.POSITION_ID,B0.ID,B0.TITLE FROM MYSCHEMA.EMPLOYEE A0 LEFT OUTER JOIN MYSCHEMA."POSITION" B0 ON A0.POSITION_ID = B0.ID
我明白为什么要这样做,天真的方法总是有效的。我只是希望它能够做得更多。尽管 DataNucleus 可能不会从结果集中读取所有列,而是返回缓存的位置,但它仍然调用数据存储来访问第二个表,包括可能的磁盘查找和读取。它会抛弃这项工作这一事实并不能让人感到安慰。
我希望做的是告诉 DataNucleus 所有位置 都将被缓存,相信我。如果由于某种原因你找到了一个不是,请怪我缓存未命中。我了解您必须(透明地)在职位表上执行单独的选择。 (更好的是,固定由于缓存未命中而必须获取的任何位置。这样就不会再次在对象上发生缓存未命中。)
这就是我现在通过 DAO 使用 JDBC 所做的事情。研究持久层的原因之一是放弃这些 DAO。很难想象迁移到无法超越简单获取导致昂贵连接的持久层。
只要 Employee 不仅有一个职位,而且有一个部门和其他字段,一个 Employee 提取会导致访问六个表,即使所有这些对象都已经固定在缓存中,并且在给定的情况下是可寻址的他们的类和主键。事实上,我可以自己实现,将 Employee.position 更改为 Integer,创建 IntIdentity,并将其传递给 PersistenceManager.getObjectByID()。
我认为我听到的是 DataNucleus 无法进行这种优化。那正确吗?没关系,只是和我想的不一样。
【问题讨论】:
-
顺便说一句,您可能不想真正抛弃 DAO。希望您可以使用 JDO 重写 DAO 层,而无需过多更改应用程序代码。
标签: jdo datanucleus