Apache JDO 3.2.1 配置参数详解
详解 Apache JDO 3.2.1 + DataNucleus 6.0 的运行时配置:编程式 Properties 与 jdoconfig.xml 两种创建方式、javax.jdo.option 标准属性、datanucleus 扩展属性、连接 URL、增强插件参数与 JDOQL 配置,含实测示例
Apache JDO 3.2.1 配置参数详解
配置分两层:
javax.jdo.option.*是 JDO 规范标准属性,任何实现都认识;datanucleus.*是 DataNucleus 6.0 的实现扩展属性。本文实测环境:DataNucleus 6.0.11 + api-jdo 6.0.5 + H2 2.2.224 + Temurin 17。标注"实测"的输出均为容器内真实回显。
一、PMF 创建的两种方式
PersistenceManagerFactory(PMF)是 JDO 的会话工厂,等价于 JPA 的 EntityManagerFactory。两种创建方式:
| 方式 | 载体 | 适用 |
|---|---|---|
| 编程式 Properties | JDOHelper.getPersistenceManagerFactory(props) | 单元测试、内存库、想避免 XML 失败面(本文实测采用) |
| jdoconfig.xml | META-INF/jdoconfig.xml + JDOHelper.getPersistenceManagerFactory("pu-name") | 传统工程、多持久化单元切换 |
1.1 编程式(实测通过的最小集)
Properties props = new Properties();
props.setProperty("javax.jdo.PersistenceManagerFactoryClass",
"org.datanucleus.api.jdo.JDOPersistenceManagerFactory");
props.setProperty("javax.jdo.option.ConnectionURL",
"jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1");
props.setProperty("datanucleus.schema.autoCreateAll", "true");
PersistenceManagerFactory pmf = JDOHelper.getPersistenceManagerFactory(props);
实测运行结果(节选):
[persist] 3 objects committed
[JDOQL] age > 25 -> 2 rows
Person{id=3, name='Carol', age=27}
Person{id=1, name='Alice', age=30}
1.2 jdoconfig.xml(参考,本文未实测)
<jdoconfig xmlns="http://xmlns.jcp.org/xml/ns/jdo/jdoconfig">
<persistence-manager-factory name="demo">
<property name="javax.jdo.option.ConnectionURL" value="jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1"/>
<property name="datanucleus.schema.autoCreateAll" value="true"/>
</persistence-manager-factory>
</jdoconfig>
放 src/main/resources/META-INF/jdoconfig.xml,运行时 JDOHelper.getPersistenceManagerFactory("demo")。
二、javax.jdo.option 标准属性表
| 属性 | 必填 | 示例值 | 说明 |
|---|---|---|---|
javax.jdo.PersistenceManagerFactoryClass | 是 | org.datanucleus.api.jdo.JDOPersistenceManagerFactory | 实现类 |
javax.jdo.option.ConnectionURL | 是 | jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1 | JDBC 连接串(RDBMS 场景) |
javax.jdo.option.ConnectionDriverName | 视驱动 | org.h2.Driver | 显式指定驱动类,多数驱动可自动识别 |
javax.jdo.option.ConnectionUserName | 生产必填 | griffin | 用户名 |
javax.jdo.option.ConnectionPassword | 生产必填 | *** | 口令 |
javax.jdo.option.ConnectionFactoryName | 二选一 | java:comp/env/jdbc/demo | JNDI 数据源名(容器托管时替代 URL 三件套) |
javax.jdo.option.ReadOnly | 否 | true | PMF 级只读 |
javax.jdo.option.Multithreaded | 否 | true | 允许同一 PM 跨线程使用(默认 false,慎开) |
javax.jdo.option.Optimistic | 否 | true | 乐观事务(版本号校验) |
javax.jdo.option.RestoreValues | 否 | true | 回滚时恢复字段值 |
javax.jdo.option.RetainValues | 否 | true | 提交后保留字段值 |
javax.jdo.option.NontransactionalRead | 否 | true | 允许事务外读 |
javax.jdo.option.Mapping | 否 | mysql | ORM 映射文件命名空间(多库共用注解时) |
三、DataNucleus 关键扩展属性
| 属性 | 实测值 | 说明 |
|---|---|---|
datanucleus.schema.autoCreateAll | true(实测) | 自动建表建约束,演示/开发利器;生产建议显式 DDL |
datanucleus.schema.autoCreateTables | — | 只自动建表(autoCreateAll 的细分) |
datanucleus.schema.validateTables | — | 启动时校验表结构 |
datanucleus.ConnectionURL | — | 与 javax.jdo.option.ConnectionURL 等价的 DN 写法 |
datanucleus.connectionPoolType | — | 连接池实现(DBCP/HikariCP,需加对应依赖) |
datanucleus.connectionPool.maxPoolSize | — | 池上限(配合 HikariCP 等) |
datanucleus.autoStartMechanism | — | 启动时扫描已有数据类(None/Table/Classes) |
datanucleus.identifierCase | — | 标识符大小写策略(MixedCase/UpperCase 等) |
datanucleus.cache.level2.type | — | 二级缓存(none/javax.cache);默认 none |
datanucleus.datastoreTransactionTimeout | — | 数据store事务超时(毫秒) |
datanucleus.persistenceByReachabilityAtCommit | — | 提交时可达性分析开关 |
实测提示:未配 log4j2 绑定时,DataNucleus 的 SQL/建表日志不会输出(实测 grep CREATE TABLE 运行日志为空)。要看 SQL 需引入 log4j-core 并将 DataNucleus.Datastore 日志级别调 DEBUG。
四、连接 URL 与数据库矩阵
| 数据库 | ConnectionURL | 驱动依赖 |
|---|---|---|
| H2 内存 | jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1 | com.h2database:h2 |
| H2 文件 | jdbc:h2:file:./data/demo | 同上 |
| MySQL 8 | jdbc:mysql://host:3306/demo?useSSL=false | com.mysql:mysql-connector-j |
| PostgreSQL | jdbc:postgresql://host:5432/demo | org.postgresql:postgresql |
| Derby | jdbc:derby:./data/demo;create=true | org.apache.derby:derby |
URL 中的连接参数(如 H2 的 DB_CLOSE_DELAY=-1)直接控制行为;实测 DB_CLOSE_DELAY=-1 是跨 PM 访问同一内存库的关键,不加则每个连接各得一个空库。
五、datanucleus-maven-plugin 增强配置
<plugin>
<groupId>org.datanucleus</groupId>
<artifactId>datanucleus-maven-plugin</artifactId>
<version>6.0.1</version>
<configuration>
<verbose>true</verbose>
</configuration>
<executions>
<execution>
<phase>process-classes</phase>
<goals><goal>enhance</goal></goals>
</execution>
</executions>
</plugin>
| 参数 | 默认 | 说明 |
|---|---|---|
verbose | false | 打印增强明细(实测输出 ENHANCED (Persistable) : demo.Person) |
api | JDO | 持久化 API(JDO/JPA) |
log4jConfiguration | — | 增强器日志配置文件路径 |
persistenceUnitName | — | 按 persistence.xml 选择增强范围 |
includes/excludes | — | 类文件 glob 过滤 |
fork | true | 独立 JVM 运行增强器 |
<phase>process-classes</phase> 把增强挂在编译后、打包前;实测增强耗时 input=69 ms, enhance=56 ms, total=125 ms(1 个类)。
实测排障要点:6.0.1 将增强器 stderr 转发为 Maven [ERROR] 行,内容实为 INFO,不代表失败——以 ENHANCED (Persistable) 行 + BUILD SUCCESS 为准:
[INFO] DataNucleus Enhancer (version 6.0.11) for API "JDO"
ENHANCED (Persistable) : demo.Person
DataNucleus Enhancer completed with success for 1 classes. Timings : input=69 ms, enhance=56 ms, total=125 ms.
六、JDOQL 查询配置与参数化
6.1 单字符串 JDOQL(实测通过)
Query<Person> q = pm2.newQuery("javax.jdo.query.JDOQL",
"SELECT FROM demo.Person WHERE age > 25 ORDER BY age ASC");
语法骨架:SELECT [DISTINCT] FROM 全限定类名 [WHERE 条件] [PARAMETERS 声明] [ORDER BY] [GROUP BY]。实测命中 2 行且升序(见 1.1 回显)。
6.2 参数化(生产必用,防注入)
Query<Person> q = pm.newQuery(Person.class, "age > :minAge");
List<Person> rows = (List<Person>) q.execute(25);
或显式声明:q.declareParameters("int minAge"); q.setFilter("age > minAge"); q.execute(25);
6.3 主键回读(实测)
Person bob = pm2.getObjectById(Person.class, 2L);
// [getObjectById] id=2 -> Person{id=2, name='Bob', age=22}
getObjectById 走主键索引直达,不产生集合扫描,是最快的单条读取方式。
七、事务参数与生命周期
Transaction tx = pm.currentTransaction();
tx.begin();
try { /* 操作 */ tx.commit(); }
finally { if (tx.isActive()) tx.rollback(); }
pm.close();
| 关注点 | 配置/做法 |
|---|---|
| 乐观锁 | PMF 属性 javax.jdo.option.Optimistic=true + 实体加 @Version 字段 |
| 跨 PM 读内存库 | H2 URL DB_CLOSE_DELAY=-1(实测必需) |
| 提交后继续读对象 | javax.jdo.option.RetainValues=true |
| 回滚恢复字段 | javax.jdo.option.RestoreValues=true |
| 大批量插入 | 每 N 条 tx.commit() 分段提交,避免长事务 |
八、FAQ
Q1:Properties 和 jdoconfig.xml 混用时优先级? 编程式传入的 Properties 为准;JDOHelper(name) 方式只读 jdoconfig.xml。
Q2:autoCreateAll 生产环境能用吗?
不建议,表结构漂移难审计;生产用显式 DDL 或 validateTables 启动校验。
Q3:连接池怎么配?
datanucleus.connectionPoolType=HikariCP 并引入 HikariCP 依赖,再用 datanucleus.connectionPool.* 细调。
Q4:密码明文写在 Properties 里安全吗?
不安全,从环境变量/JNDI 注入:props.setProperty("javax.jdo.option.ConnectionPassword", System.getenv("DB_PWD"))。
Q5:为什么我改了实体字段但库里没变? autoCreateAll 只建不改;字段变更需手工 ALTER 或清库重建。
Q6:Multithreaded=true 就线程安全了吗? 只是解除"单 PM 单线程"限制,业务层仍需自行同步;常规做法是每线程各取 PM。
Q7:JDOQL 能做聚合吗?
支持 SUM/COUNT/MIN/MAX/AVG + GROUP BY/HAVING;复杂报表建议原生 SQL(pm.newQuery("javax.jdo.query.SQL", "..."))。
Q8:如何关闭二级缓存?
默认就是 none;显式声明 datanucleus.cache.level2.type=none 防止依赖传递引入意外配置。
Q9:enhance 只增强部分类怎么配?
<includes><include>demo/*.class</include></includes>(插件 configuration 段)。
Q10:javax.jdo.option.Mapping 什么时候需要? 同一套注解要按数据库微调映射时(如 MySQL/Oracle 各一份 mapping 文件),普通项目留空。
参考链接
- JDO 规范属性清单:https://db.apache.org/jdo/jdo_dtd.html(随包 doc 亦有)
- DataNucleus Properties 参考:https://www.datanucleus.org/products/accessplatform/jdo/persistence.html
- jdo-api 3.2.1:https://repo1.maven.org/maven2/javax/jdo/jdo-api/