JavaDataObjects(JDO)全面解析
立即解锁
发布时间: 2025-08-19 02:32:43 阅读量: 3 订阅数: 11 


Spring框架下的Java开发实践与进阶
# Java Data Objects (JDO) 全面解析
## 1. JDO 概述
Java Data Objects (JDO) 并非严格意义上的 O/R 映射规范,而是用于通用对象持久化,可涵盖任何类型的后端数据存储,包括关系型数据库和面向对象数据库。不过,大多数 JDO 实现主要针对关系型数据库,因此可归类为 O/R 映射解决方案。
### 1.1 JDO 版本特性
- **JDO 2.0**:基于 JDO 1.0 构建,新增了两项重要特性:对分离对象的支持以及专门的 O/R 映射支持。在 Web 应用中,分离和重新附加对象是常见用例,但 JDO 1.0 API 无法很好地支持这一点(与 iBATIS SQL Maps 和 Hibernate 等其他持久化解决方案不同)。
- **JDOQL**:是一种遵循 ODMG 的 OQL 传统的纯对象查询语言,使用 Java 查询 API 和基于 Java 的条件字符串。在 JDO 2.0 中,查询功能将显著扩展,例如引入文本查询作为替代方式。许多当前的 JDO 实现已经支持查询扩展,主要用于访问关系型数据库。
### 1.2 变更检测机制
- **JDO 1.0**:通过增强持久对象的字节码,使其实现 `javax.jdo.PersistenceCapable` 接口来执行变更检测。字节码增强器需要作为应用程序构建过程的一部分运行。增强后的类会在事务中通知 JDO StateManager 其实例字段的任何更改;JDO 始终处理实例字段,而不是 JavaBean 属性的 setter 或 getter 方法。在事务提交时,JDO PersistenceManager 会将更改刷新到数据库,使内存状态与数据库状态同步。
- **JDO 2.0**:将字节码增强降级为一种实现选项,取消了二进制兼容性要求。JDO 2.0 实现可以自由选择其他变更检测策略,例如 Hibernate 和 TopLink 使用的快照比较。
## 2. 持久对象生命周期
JDO 的一个重要特性是持久对象具有严格的生命周期。默认情况下,持久对象只能在活动的 JDO PersistenceManager 中工作;在 PersistenceManager 关闭后访问其实例字段会抛出异常。此外,对持久对象的更改只能在 JDO 事务中进行,不存在非事务性修改的概念。
### 2.1 分离和重新附加对象
为了在活动的 JDO 连接之外使用持久对象,需要将它们变为瞬态(JDO 1.0)或分离(JDO 2.0),这通常是一个显式步骤。瞬态实例会失去其持久标识,因此无法再次持久化;这就是 JDO 2.0 引入分离和重新附加概念的原因,允许在加载对象的 JDO PersistenceManager 之外修改对象,然后在新事务中持久化它们(这在 Web 应用中是典型用例)。
### 2.2 生命周期管理选项
JDO 2.0 还讨论了自动关闭分离和自动序列化分离等选项,旨在消除显式分离的负担。目前尚不清楚这些选项是否会成为规范的一部分;某些 JDO 实现已经将这些选项作为特定于供应商的扩展提供支持。
```mermaid
graph LR
classDef startend fill:#F5EBFF,stroke:#BE8FED,stroke-width:2px
classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px
classDef decision fill:#FFF6CC,stroke:#FFBC52,stroke-width:2px
A([持久对象]):::startend --> B(活动的 PersistenceManager):::process
B --> C{是否需要外部使用}:::decision
C -->|是| D(分离对象):::process
D --> E(外部修改):::process
E --> F(重新附加到新事务):::process
F --> G(持久化):::process
C -->|否| H(在事务中使用):::process
H --> I(事务提交):::process
I --> J(刷新更改到数据库):::process
```
## 3. DAO 实现
### 3.1 传统 JDO 使用方式
传统的 JDO 使用涉及一个资源工厂 `javax.jdo.PersistenceManagerFactory`,用于为每个事务或操作序列打开一个单线程资源 `javax.jdo.PersistenceManager`。这大致类似于 Hibernate 的 SessionFactory 和 Session。在 Spring 环境中,提供的便利类减轻了应用程序开发人员的资源管理负担。
### 3.2 Spring 支持的 DAO 实现
Spring 中提供了 `org.springframework.orm.jdo.JdoTemplate` 作为数据访问操作的模板类,它在底层使用 JDO 的 PersistenceManager API。通常通过 `org.springframework.orm.jdo.support.JdoDaoSupport` 基类使用,该基类将 JDO PersistenceManagerFactory 实例作为 bean 属性,并为其提供一个 JdoTemplate 实例。
以下是一个基于 JDO 实现 PetClinic DAO 的示例:
```java
public class JdoClinic extends JdoDaoSupport implements Clinic {
public Collection getVets() throws DataAccessException {
return getJdoTemplate().find(
Vet.class, null, "lastName ascending, firstName ascending");
}
public Collection getPetTypes() throws DataAccessException {
return getJdoTemplate().find(PetType.class, null, "name ascending");
}
public Collection findOwners(String lastName) throws DataAccessException {
return getJdoTemplate().find(
Owner.class, "lastName == value", "String value", new Object[] {value});
}
...
}
```
### 3.3 其他实现方式
除了使用 `JdoDaoSupport`,DAO 实现还可以实现自己的 `setPersistenceManagerFactory` 方法,最好为 DAO 创建一个共享的 JdoTemplate 实例。或者,DAO 实现也可以直接使用提供的 PersistenceManagerFactory 实例,而不使用 Spring 的 JdoTemplate,但这需要手动处理 JDO PersistenceManager、手动进行异常转换以及手动与 Spring 事务同步,因此通常建议使用 JdoTemplate。
### 3.4 懒加载问题
与 Hibernate 一样,JDO 对懒加载有特殊要求。最初加载受影响持久对象的 JDO PersistenceManager 需要保持打开状态才能使懒加载正常工作。由于 JdoTemplate 默认在每个操作结束时关闭 JDO PersistenceManager,因此返回的对象无法进行懒加载。建议在事务中执行此类操作,以确保在整个事务生命周期内保持同一个 JDO PersistenceManager 打开。如果需要在事务范围之外进行懒加载,例如在 Web 视图中,则需要采用“Open PersistenceManager in View”模式。
## 4. Spring 上下文配置
### 4.1 使用 LocalPersistenceManagerFactoryBean 配置
在 Spring 应用程序上下文中,通常通过 Spring 的 `LocalPersistenceManagerFactoryBean` 来设置 JDO 实现,并通过指定的 JDO 属性进行配置。以下是开源 JDO 实现 JPOX 的配置示例:
```xml
<bean id="persistenceManagerFactory"
class="org.springframework.orm.jdo.LocalPersistenceManagerFactoryBean">
<property name="jdoProperties">
<props>
<prop key="javax.jdo.PersistenceManagerFactoryClass">
org.jpox.PersistenceManagerFactoryImpl
</prop>
<prop key="javax.jdo.option.ConnectionDriverName">
com.mysql.jdbc.Driver
</prop>
<prop key="javax.jdo.option.ConnectionURL">...</prop>
<prop key="javax.jdo.option.NontransactionalRead">true</prop>
</props>
</property>
</bean>
```
### 4.2 使用配置文件配置
也可以使用标准的 `jdo.properties` 文件来配置 PersistenceManagerFactory,并通过 `configLocation` 指定其位置。这种基于文件的属性可以与 `LocalPersistenceManagerFactoryBean` 属性混合使用,后者具有更高的优先级。
```xml
<bean id="persistenceManagerFactory"
class="org.springframework.orm.jdo.LocalPersistenceManagerFactoryBean">
<property name="configLocation">
<value>classpath:jdo.properties</value>
</property>
</bean>
```
### 4.3 直接配置 PersistenceManagerFactory 实现类
另一种配置方式是将 PersistenceManagerFactory 实现类本身设置为 Spring bean。JDO 属性通常可以作为 bean 属性应用,使用等效的 bean 属性名称(可以在 JDO 实现的 javadoc 中查看)。此外,通常可以将 Spring 管理的 JDBC DataSource 指定为 JDO 连接工厂,这对于同时使用 JDO 和 JDBC 访问代码共享 DataSource 很重要。以下是使用 JPOX 的示例:
```xml
<bean id="persistenceManagerFactory"
class="org.jpox.PersistenceManagerFactoryImpl">
<property name="connectionFactory">
<ref bean="dataSource"/>
</property>
<property name="nontransactionalRead">
<value>true</value>
</property>
</bean>
```
### 4.4 特殊配置需求
对于特殊的设置需求,可能需要使用 `LocalPersistenceManagerFactoryBean` 的自定义子类,重写 `newPersistenceManagerFactory` 方法并使用特定于供应商的实例化代码。大多数 JDO 实现还提供了 JCA 连接器,但通常不需要使用它进行 JTA 集成,一个本地定义的 PersistenceManagerFactory 并正确配置 JTA 事务管理器查找通常就足够了。
DAO 可以通过 Spring bean 引用接收 JDO PersistenceManagerFactory 实例的引用,就像基于 JDBC 的 DAO 接收 JDBC DataSource 的引用一样。
```xml
<bean id="clinicDao"
class="org.springframework.samples.petclinic.jdo.JdoClinic">
<property name="persistenceManagerFactory">
<ref bean="persistenceManagerFactory"/>
</property>
</bean>
```
## 5. 事务管理
### 5.1 事务管理方式
在 Spring 环境中,通常不使用 JDO PersistenceManager API 提供的事务处理方式,而是将事务管理委托给 Spring 的通用事务设施,使用通用的 `TransactionTemplate` 或 `TransactionProxyFactoryBean` 进行事务划分。
### 5.2 后端事务策略
- **`org.s
0
0
复制全文
相关推荐









