我正在尝试将 JDBC webapp 移动到 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:
选择 A0.POSITION_ID,B0.ID,B0.TITLE 从 MYSCHEMA.EMPLOYEE A0 LEFT OUTER JOIN MYSCHEMA."POSITION" B0 ON A0.POSITION_ID = B0.ID WHERE A0.ID = <1>
我的理解是,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 作为默认提取组的一部分,并查看相应的 Position 是否已被缓存。如果是这样,则设置该字段。如果没有,则稍后再加入,如果需要的话。更好的是,继续将该 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 无法进行这种优化。那正确吗?很好,只是不是我所期望的。