Ubuntu 22.04 安装 Apache Torque 指南
在 Ubuntu 22.04 上从零安装 Apache Torque 4.0(4.x 系列最终版),覆盖 JDK 17 与 Maven 环境、Maven 插件生成 OM 类与建表 SQL、官方 jar 手工 classpath 直跑两种方案,并跑通 Derby 内存库上的真实增删改查,命令与回显均实测通过。
Ubuntu 22.04 安装 Apache Torque 指南
目标:在 Ubuntu 22.04 上从零搭建 Apache Torque 4.0(4.x 系列最终版)的开发与运行环境(JDK 17 + Maven 3.6.3 + Derby 10.14.2.0 嵌入式数据库),跑通「XML schema → OM 类生成 → 建表 SQL 生成 → 建库 → 增删改查」完整链路;本文全部命令与回显均已在 Ubuntu 22.04 实测通过。
Apache Torque 是 Apache DB 项目下的对象关系映射(ORM)框架。与 Hibernate 等基于反射的主流框架不同,Torque 从手写或逆向生成的 XML schema 出发,预生成数据对象(Data Object)、Peer 门面与记录映射器等全部 Java 类,运行时直接调用生成类访问数据库,无反射开销、无运行期配置魔法。它由四个组件构成:torque-runtime(运行时,应用唯一依赖)、torque-generator(代码生成引擎)、torque-maven-plugin(Maven 集成)、torque-templates(OM/SQL 模板包)。本文给出两种落地方式:面向工程开发的 Maven 插件方案,以及无构建体系场景的官方 jar 手工 classpath 方案。
一、环境信息
本节先固定可复现的基线环境,后续所有命令均在此环境执行。列出操作系统、架构、JDK、构建工具与组件版本,便于读者对照复现。
- 操作系统:Ubuntu 22.04.5 LTS(PRETTY_NAME="Ubuntu 22.04.5 LTS")
- 架构:x86_64
- JDK:OpenJDK 17.0.20.1(apt 包
openjdk-17-jdk) - 构建工具:Apache Maven 3.6.3(apt 包
maven) - 组件版本:Torque 4.0(4.x 系列最终版),运行时坐标
org.apache.torque:torque-runtime:4.0 - 嵌入式数据库:Apache Derby 10.14.2.0(
org.apache.derby:derby,内存模式) - Maven 坐标:
org.apache.torque:torque-runtime:4.0、org.apache.torque:torque-maven-plugin:4.0、org.apache.torque:torque-templates:4.0 - 验证用工作目录:
/root/torque-demo(Maven 工程)、/root/jar-run(jar 直跑)
系统与版本确认(实时回显):
cat /etc/os-release | head -3
PRETTY_NAME="Ubuntu 22.04.5 LTS"
NAME="Ubuntu"
VERSION_ID="22.04"
uname -m
x86_64
💡 说明:Torque 是库而非服务,环境中不存在需要常驻的守护进程;数据库选用 Derby 嵌入式内存模式(跟随 JVM 存活),因此「安装完成」的判定标准是跑通一个含建表与增删改查的最小程序,而不是某个端口处于监听状态。
二、前置条件
本节说明安装前必须满足的条件。Ubuntu 22.04 自带可用的软件源,联网即可通过 apt 获取 JDK 与 Maven。
- 具有 root 或 sudo 权限的 Ubuntu 22.04 系统。
- 可访问 Ubuntu 官方软件源(
apt update能正常拉取索引)。 - 可访问 Maven 中央仓库
repo1.maven.org(本文实测网络直连可达,Torque 全部构件均托管于 Maven Central,Apache 官方下载站不提供 Torque 的二进制发布)。 - 至少 2 GB 可用磁盘空间(JDK + Maven + 依赖合计约 600 MB)。
网络连通性确认(实时回显):
curl -sI --max-time 20 https://repo1.maven.org/maven2/org/apache/torque/torque-runtime/4.0/torque-runtime-4.0.jar | head -3
HTTP/1.1 200 OK
Date: Wed, 15 Oct 2026 01:20:11 GMT
Server: nginx
三、版本选型说明
本节给出 Torque 的版本谱系,帮助读者在 4.x 与后续版本之间做出选择。以下版本列表与发布时间均从 Maven Central 的构件目录实时核验(maven-metadata.xml 与各版本 pom 的 Last-Modified 时间):
| 版本线 | 最新版 | 发布日期(Maven Central 实测) | JDK 基线(官网声明) | 适用场景 |
|---|---|---|---|---|
| 3.x(已淘汰) | 3.3 | 2010 年前后 | Java 1.3+ | 极老项目兼容,不建议新用 |
| 4.x(本文实测) | 4.0 | 2013-02-27 | JDK 1.6+ | 经典生成式 ORM,单体 runtime,文档最多 |
| 5.x | 5.1 | 2022-01-05(5.0 为 2020-08-14) | JDK 1.8+ | 模块化改造起点 |
| 6.x | 6.0 | 2024-05-08 | JDK 11+ | 移除老旧依赖后的现代基线 |
| 7.x(当前主线) | 7.0 | 2025-07-31 | JDK 17+ | 当前 production release,最新特性 |
关于维护状态需要如实说明:Torque 4.0 发布于 2013 年 2 月,此后项目经历了 5.0(2020 年)、5.1(2022 年)、6.0(2024 年)到 7.0(2025 年 7 月 31 日)的持续演进,项目仍在活跃维护,Maven Central 上当前 release 为 7.0;但 4.x 分支自 4.0 之后未再发布补丁版本,4.x 系列的最终版就是 4.0。官网(db.apache.org/torque)当前推荐新项目使用 7.0。
本文实际采用 4.0,理由如下:其一,4.0 是 Torque 生成式 ORM 教程与社区资料覆盖最完整的版本;其二,其运行时为单体 jar(torque-runtime),依赖结构简单(commons-configuration 1.6、commons-dbcp 1.3 等),适合作为学习与老系统对照的基线;其三,实测其对 JDK 17 完全兼容——生成器、编译与运行时全链路跑通(详见 4.7 节),仅有生成代码中 new Integer() 等旧式写法在 JDK 17 编译期产生 15 个 deprecation 警告,功能不受影响。
数据库适配是 4.0 的一个硬约束,实测核验结果:torque-runtime 4.0 内置适配器仅有 Mssql、Hsqldb、Mysql、Derby、Oracle、Postgres、None 七种(jar tf torque-runtime-4.0.jar | grep adapter 实测),不包含 H2 适配器;同时 SQL 生成模板包(org.apache.torque.templates.sql)支持的 DDL 方言也只有 derby、hsqldb、mssql、mysql、oracle、postgresql 六种。因此本文选用 Derby 10.14.2.0:完全嵌入、零安装,且官方模板原生支持。Derby 版本选择上有一个实测踩坑:10.16.1.1 的字节码是 Java 17(class file major 61),在 JDK 11 环境加载驱动直接抛 UnsupportedClassVersionError;10.14.2.0 是 Java 8 字节码,JDK 8/11/17 均实测可运行,故统一采用 10.14.2.0。
版本确认为 4.0 的实测回显:
curl -s --max-time 30 https://repo1.maven.org/maven2/org/apache/torque/torque/maven-metadata.xml | grep -E "latest|<version>" | head -9
<latest>7.0</latest>
<release>7.0</release>
<versions>
<version>3.3</version>
<version>4.0-beta1</version>
<version>4.0</version>
<version>5.0</version>
<version>5.1</version>
<version>6.0</version>
<version>7.0</version>
</versions>
四、方案 A:Maven 依赖安装(在线,推荐)
本节面向常规 Java 项目开发,通过 apt 安装 JDK 与 Maven,再用 torque-maven-plugin 从手写 schema 生成 OM 类与建表 SQL,最后引入 torque-runtime 跑通增删改查。这是最贴合工程实践的方式。
4.1 方案说明
方案 A 的链路是:apt 安装 openjdk-17-jdk 与 maven → 创建 Maven 工程,声明 torque-maven-plugin(classpath 模板包模式)与 torque-runtime、Derby 依赖 → 手写 src/main/schema/project-schema.xml → mvn torque:generate 生成 OM 类 → mvn torque:generate -Psql 生成建表 DDL → 编译并运行验证程序。优点是版本由 pom 统一管控、生成与编译一体化;缺点是首次构建需要联网下载依赖。
4.2 安装 JDK 17
Ubuntu 22.04 官方源内置 openjdk-17-jdk,直接安装即可:
apt-get update -qq && apt-get install -y openjdk-17-jdk maven
# 输出节选(实测)
maven is already the newest version (3.6.3-5).
openjdk-17-jdk is already the newest version (17.0.20.1+1-1~22.04).
0 upgraded, 0 newly installed, 0 to remove and 2 not upgraded.
安装后确认版本:
java -version
mvn -v | head -3
openjdk version "17.0.20.1" 2026-08-18
OpenJDK Runtime Environment (build 17.0.20.1+1-1-22.04-Ubuntu)
OpenJDK 64-Bit Server VM (build 17.0.20.1+1-1-22.04-Ubuntu, mixed mode, sharing)
Apache Maven 3.6.3
Maven home: /usr/share/maven
Java version: 17.0.20.1, vendor: Ubuntu, runtime: /usr/lib/jvm/java-17-openjdk-amd64
验证点:java -version 输出 17.0.x、mvn -v 的 Java version 一行同样显示 17.0.20.1,说明 Maven 已绑定 JDK 17。
4.3 创建工程与 schema
建立工程目录与数据库 schema 定义。Torque 的 schema 是一份手写 XML,描述表、列、主键与外键,是整个生成流程的唯一源头:
mkdir -p /root/torque-demo/src/main/schema
mkdir -p /root/torque-demo/src/main/java/com/example/torque
mkdir -p /root/torque-demo/src/main/resources
/root/torque-demo/src/main/schema/project-schema.xml 全文(bookstore 三表示例,直接照抄):
<?xml version="1.0" encoding="UTF-8"?>
<database name="bookstore" defaultIdMethod="native">
<table name="publisher" description="Publisher table">
<column name="publisher_id" primaryKey="true" required="true" type="INTEGER" description="Primary Key"/>
<column name="name" type="VARCHAR" size="128" required="true" description="Publisher Name"/>
</table>
<table name="author" description="Author table">
<column name="author_id" primaryKey="true" required="true" type="INTEGER" description="Primary Key"/>
<column name="first_name" type="VARCHAR" size="128" required="true" description="First Name"/>
<column name="last_name" type="VARCHAR" size="128" required="true" description="Last Name"/>
</table>
<table name="book" description="Book table">
<column name="book_id" primaryKey="true" required="true" type="INTEGER" description="Primary Key"/>
<column name="isbn" required="true" type="VARCHAR" size="24" description="ISBN"/>
<column name="title" required="true" type="VARCHAR" size="255" description="Book Title"/>
<column name="author_id" required="true" type="INTEGER" description="Foreign Key Author"/>
<column name="publisher_id" required="true" type="INTEGER" description="Foreign Key Publisher"/>
<foreign-key foreignTable="author" name="book_fk_author" onDelete="cascade">
<reference local="author_id" foreign="author_id"/>
</foreign-key>
<foreign-key foreignTable="publisher" name="book_fk_publisher" onDelete="cascade">
<reference local="publisher_id" foreign="publisher_id"/>
</foreign-key>
</table>
</database>
逐项说明关键配置:
database name="bookstore":数据库逻辑名,后续torque.properties与生成配置都要引用它。defaultIdMethod="native":主键交给数据库自增机制(Derby 下生成GENERATED BY DEFAULT AS IDENTITY列),插入时无须手工赋主键。type="INTEGER"、type="VARCHAR"、size="128":Torque 的逻辑类型,由 SQL 模板按目标数据库方言翻译成物理类型。foreign-key+reference:声明 book 到 author、publisher 的外键;onDelete="cascade"生成级联删除约束。
4.4 编写 pom.xml
/root/torque-demo/pom.xml 全文(直接照抄):
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example.torque</groupId>
<artifactId>torque-demo</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.torque</groupId>
<artifactId>torque-runtime</artifactId>
<version>4.0</version>
</dependency>
<dependency>
<groupId>org.apache.derby</groupId>
<artifactId>derby</artifactId>
<version>10.14.2.0</version>
</dependency>
<dependency>
<groupId>org.apache.derby</groupId>
<artifactId>derbytools</artifactId>
<version>10.14.2.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.torque</groupId>
<artifactId>torque-maven-plugin</artifactId>
<version>4.0</version>
<dependencies>
<dependency>
<groupId>org.apache.torque</groupId>
<artifactId>torque-templates</artifactId>
<version>4.0</version>
</dependency>
</dependencies>
<configuration>
<packaging>classpath</packaging>
<configPackage>org.apache.torque.templates.om</configPackage>
<sourceDir>src/main/schema</sourceDir>
<options>
<torque.om.package>com.example.torque.om</torque.om.package>
</options>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>3.2.0</version>
<executions>
<execution>
<id>add-torque-sources</id>
<phase>generate-sources</phase>
<goals>
<goal>add-source</goal>
</goals>
<configuration>
<sources>
<source>target/generated-sources</source>
<source>src/main/generated-java</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>sql</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.torque</groupId>
<artifactId>torque-maven-plugin</artifactId>
<version>4.0</version>
<dependencies>
<dependency>
<groupId>org.apache.torque</groupId>
<artifactId>torque-templates</artifactId>
<version>4.0</version>
</dependency>
</dependencies>
<configuration>
<packaging>classpath</packaging>
<configPackage>org.apache.torque.templates.sql</configPackage>
<sourceDir>src/main/schema</sourceDir>
<options>
<torque.database>derby</torque.database>
<torque.sql.generate.drops>true</torque.sql.generate.drops>
</options>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>
逐项说明关键配置:
torque-runtime:4.0:运行期唯一 Torque 依赖,Maven 会自动解析其传递依赖(commons-configuration 1.6、commons-dbcp 1.3、jcs 1.3、avalon-framework-api 4.3.1 等,共 11 个)。derby:10.14.2.0+derbytools:10.14.2.0:嵌入式数据库驱动(版本选型理由见第三章)。- 插件
packaging=classpath+configPackage=org.apache.torque.templates.om:直接以 classpath 上的模板包为生成配置(OM 生成模板自带 control 文件与全部模板),无须在工程里手写任何 control.xml 或模板;这是 torque-maven-plugin 4.0 最省事的用法。 sourceDir=src/main/schema:schema 源文件目录。不设置时插件默认找src/main/torque-gen/src(实测报Could not list files in the following Directory ... torque-gen/src),必须显式指向 schema 目录。torque.om.package:生成类的 Java 包名,模板包强制要求该选项,缺失时实测报Option torque.om.package must be set。build-helper-maven-plugin:torque-maven-plugin 不会把生成目录注册为编译源目录(实测mvn compile直接报No sources to compile),必须用该插件把target/generated-sources(基类)与src/main/generated-java(可编辑类)加入编译范围。sqlprofile:同一个插件换用org.apache.torque.templates.sql模板包生成建表 DDL;torque.database=derby指定方言(该选项同样强制,缺失时报Option torque.database must be set)。
4.5 生成 OM 类
cd /root/torque-demo && mvn -B torque:generate
[INFO] --- torque-maven-plugin:4.0:generate (default-cli) @ torque-demo ---
[INFO] Generation successful
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] Total time: 1.403 s
查看生成结果(实测清单):
find target/generated-sources src/main/generated-java -name "*.java" | sort
src/main/generated-java/com/example/torque/om/Author.java
src/main/generated-java/com/example/torque/om/AuthorPeer.java
src/main/generated-java/com/example/torque/om/AuthorPeerImpl.java
src/main/generated-java/com/example/torque/om/AuthorRecordMapper.java
src/main/generated-java/com/example/torque/om/Book.java
src/main/generated-java/com/example/torque/om/BookPeer.java
src/main/generated-java/com/example/torque/om/BookPeerImpl.java
src/main/generated-java/com/example/torque/om/BookRecordMapper.java
src/main/generated-java/com/example/torque/om/Publisher.java
src/main/generated-java/com/example/torque/om/PublisherPeer.java
src/main/generated-java/com/example/torque/om/PublisherPeerImpl.java
src/main/generated-java/com/example/torque/om/PublisherRecordMapper.java
target/generated-sources/com/example/torque/om/BaseAuthor.java
target/generated-sources/com/example/torque/om/BaseAuthorPeer.java
target/generated-sources/com/example/torque/om/BaseAuthorPeerImpl.java
target/generated-sources/com/example/torque/om/BaseAuthorRecordMapper.java
target/generated-sources/com/example/torque/om/BaseBook.java
target/generated-sources/com/example/torque/om/BaseBookPeer.java
target/generated-sources/com/example/torque/om/BaseBookPeerImpl.java
target/generated-sources/com/example/torque/om/BaseBookRecordMapper.java
target/generated-sources/com/example/torque/om/BasePublisher.java
target/generated-sources/com/example/torque/om/BasePublisherPeer.java
target/generated-sources/com/example/torque/om/BasePublisherPeerImpl.java
target/generated-sources/com/example/torque/om/BasePublisherRecordMapper.java
Torque 4.0 的生成物按「两层目录」组织,共 24 个 Java 文件:target/generated-sources 下是 12 个 Base* 基类(每次生成重新覆盖,承载全部标准逻辑);src/main/generated-java 下是 12 个无前缀业务类(如 Author、BookPeer,仅首次生成,之后模板以 skip 策略跳过,专门留给用户改写定制)。重新执行 mvn torque:generate 不会覆盖用户对业务类的修改,这是 Torque 生成式 ORM 的核心定制机制。
4.6 生成建表 SQL
同一个插件在 sql profile 下切换为 SQL 模板包,生成 Derby 方言的建表 DDL:
cd /root/torque-demo && mvn -B -q torque:generate -Psql
INFO org.apache.torque.generator.control.Controller - Processing output torque.sql.ddl
INFO org.apache.torque.generator.control.Controller - Start generation of File /root/torque-demo/target/generated-sources/project-schema.sql
cp target/generated-sources/project-schema.sql src/main/resources/schema.sql
生成的 /root/torque-demo/src/main/resources/schema.sql 核心内容(实测):
drop table publisher;
drop table author;
drop table book;
CREATE TABLE publisher
(
publisher_id INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY,
name VARCHAR(128) NOT NULL,
PRIMARY KEY(publisher_id));
CREATE TABLE author
(
author_id INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY,
first_name VARCHAR(128) NOT NULL,
last_name VARCHAR(128) NOT NULL,
PRIMARY KEY(author_id));
CREATE TABLE book
(
book_id INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY,
isbn VARCHAR(24) NOT NULL,
title VARCHAR(255) NOT NULL,
author_id INTEGER NOT NULL,
publisher_id INTEGER NOT NULL,
PRIMARY KEY(book_id));
ALTER TABLE book
ADD CONSTRAINT book_fk_author
FOREIGN KEY (author_id)
REFERENCES author (author_id)
ON DELETE CASCADE;
ALTER TABLE book
ADD CONSTRAINT book_fk_publisher
FOREIGN KEY (publisher_id)
REFERENCES publisher (publisher_id)
ON DELETE CASCADE;
验证点:defaultIdMethod="native" 如约生成 GENERATED BY DEFAULT AS IDENTITY 自增列;两条 ADD CONSTRAINT 外键带 ON DELETE CASCADE 级联删除;torque.sql.generate.drops=true 使脚本开头带 drop 语句(对已存在的库可重复执行)。
4.7 编写验证程序并编译运行
验证程序 /root/torque-demo/src/main/java/com/example/torque/Main.java 全文(直接复制):
package com.example.torque;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.Statement;
import java.util.List;
import java.util.Properties;
import org.apache.torque.Torque;
import org.apache.torque.criteria.Criteria;
import com.example.torque.om.Author;
import com.example.torque.om.AuthorPeer;
import com.example.torque.om.Book;
import com.example.torque.om.BookPeer;
import com.example.torque.om.Publisher;
import com.example.torque.om.PublisherPeer;
public class Main {
public static void main(String[] args) throws Exception {
System.out.println("---- [1] Torque.init ----");
Properties props = new Properties();
try (InputStream in = Main.class.getResourceAsStream("/torque.properties")) {
props.load(in);
}
Class.forName("org.apache.derby.jdbc.EmbeddedDriver");
Torque.init(new org.apache.commons.configuration.MapConfiguration(props));
System.out.println("Torque.init 完成, 默认数据库=" + Torque.getDefaultDB()
+ ", 数据库注册表键=" + Torque.getDatabases().keySet());
System.out.println("---- [2] 执行生成的 DDL 建表 ----");
String raw = readResource("/schema.sql");
StringBuilder noComment = new StringBuilder();
for (String line : raw.split("\n")) {
if (!line.trim().startsWith("--")) {
noComment.append(line).append("\n");
}
}
String ddl = noComment.toString();
int done = 0;
try (Connection conn = Torque.getConnection()) {
try (Statement mk = conn.createStatement()) {
mk.execute("CREATE SCHEMA SA");
} catch (Exception e) {
System.out.println("CREATE SCHEMA SA: " + e.getMessage().split(":")[0]);
}
for (String sql : ddl.split(";")) {
String s = sql.replace("\r", "").trim();
boolean keep = s.startsWith("CREATE TABLE") || s.contains("ADD CONSTRAINT");
if (!keep) {
continue;
}
try (Statement st = conn.createStatement()) {
st.execute(s);
}
done++;
}
}
System.out.println("执行 CREATE/ALTER 语句数=" + done + " (3 张表 + 2 个外键)");
System.out.println("---- [3] 新增 (save / 主键自动生成) ----");
Publisher pub = new Publisher();
pub.setName("人民文学出版社");
pub.save();
System.out.println("Publisher 落库: name=" + pub.getName() + " 主键=" + pub.getPublisherId());
Author author = new Author();
author.setFirstName("贯中");
author.setLastName("罗");
author.save();
System.out.println("Author 落库: " + author.getLastName() + author.getFirstName() + " 主键=" + author.getAuthorId());
Book book = new Book();
book.setIsbn("9787020008728");
book.setTitle("三国演义");
book.setAuthorId(author.getAuthorId());
book.setPublisherId(pub.getPublisherId());
book.save();
System.out.println("Book 落库: " + book.getTitle() + " 主键=" + book.getBookId()
+ " author_id=" + book.getAuthorId() + " publisher_id=" + book.getPublisherId());
System.out.println("---- [4] 查询 (Criteria + Peer.doSelect) ----");
Criteria crit = new Criteria();
crit.where(AuthorPeer.LAST_NAME, "罗");
List<Author> authors = AuthorPeer.doSelect(crit);
for (Author a : authors) {
System.out.println("doSelect 命中: id=" + a.getAuthorId()
+ " 姓名=" + a.getLastName() + a.getFirstName());
}
List<Book> books = BookPeer.doSelectJoinAuthor(new Criteria());
for (Book b : books) {
Author a = b.getAuthor();
System.out.println("doSelectJoinAuthor: 《" + b.getTitle() + "》 作者="
+ a.getLastName() + a.getFirstName());
}
System.out.println("---- [5] 更新 (save / retrieveByPK) ----");
book.setTitle("三国演义(校注本)");
book.save();
Book reloaded = BookPeer.retrieveByPK(book.getBookId());
System.out.println("retrieveByPK(" + book.getBookId() + ") 标题=" + reloaded.getTitle()
+ " ISBN=" + reloaded.getIsbn());
System.out.println("---- [6] 删除 (doDelete) ----");
Criteria del = new Criteria();
del.where(BookPeer.BOOK_ID, book.getBookId());
BookPeer.doDelete(del);
System.out.println("删除 book_id=" + book.getBookId()
+ " 后, 剩余 Book 行数=" + BookPeer.doSelect(new Criteria()).size()
+ ", Author 行数=" + AuthorPeer.doSelect(new Criteria()).size()
+ " (外键只级联删 book, 作者保留)");
Torque.shutdown();
System.out.println("---- 全部步骤通过 ----");
}
static String readResource(String path) throws Exception {
try (InputStream in = Main.class.getResourceAsStream(path);
ByteArrayOutputStream out = new ByteArrayOutputStream()) {
byte[] buf = new byte[8192];
int n;
while ((n = in.read(buf)) > 0) {
out.write(buf, 0, n);
}
return new String(out.toByteArray(), "UTF-8");
}
}
}
程序配套的运行时配置 /root/torque-demo/src/main/resources/torque.properties 全文(直接照抄):
torque.database.default=bookstore
torque.database.bookstore.adapter=derby
torque.dsfactory.bookstore.factory=org.apache.torque.dsfactory.SharedPoolDataSourceFactory
torque.dsfactory.bookstore.connection.url=jdbc:derby:memory:bookstore;create=true
torque.dsfactory.bookstore.connection.user=sa
torque.dsfactory.bookstore.connection.password=q1w2e3r4
逐项说明:torque.database.default 指定默认库;adapter=derby 选择内置 Derby 适配器;dsfactory 键在 4.0 中是 torque.dsfactory.<库名>.factory(注意不是 3.x 的 .factory.class,实测写旧键名报 No DataSourceFactory definition for default DB found);连接三要素 url/user/password 直接交给连接池。代码中 Class.forName("org.apache.derby.jdbc.EmbeddedDriver") 显式注册驱动是实测必需项:Torque 4.0 的连接池基于 commons-dbcp 1.3,其配置注入不认 driver/driverClassName 属性(实测两写法均报 Property ... is not supported by DataSource: DriverAdapterCPDS),而 Derby 10.14.2.0 的 JDBC SPI 声明在部分 JDK 版本(实测 JDK 11)不会被自动加载,显式注册在 JDK 8/11/17 全部可靠。
编译并运行:
cd /root/torque-demo && mvn -B -q compile && echo "EXIT=$?"
mvn -B -q dependency:build-classpath -Dmdep.outputFile=/tmp/cp.txt
java -Dfile.encoding=UTF-8 -cp "target/classes:$(cat /tmp/cp.txt)" com.example.torque.Main
---- [1] Torque.init ----
Torque.init 完成, 默认数据库=bookstore, 数据库注册表键=[bookstore, default]
---- [2] 执行生成的 DDL 建表 ----
执行 CREATE/ALTER 语句数=5 (3 张表 + 2 个外键)
---- [3] 新增 (save / 主键自动生成) ----
Publisher 落库: name=人民文学出版社 主键=1
Author 落库: 罗贯中 主键=1
Book 落库: 三国演义 主键=1 author_id=1 publisher_id=1
---- [4] 查询 (Criteria + Peer.doSelect) ----
doSelect 命中: id=1 姓名=罗贯中
doSelectJoinAuthor: 《三国演义》 作者=罗贯中
---- [5] 更新 (save / retrieveByPK) ----
retrieveByPK(1) 标题=三国演义(校注本) ISBN=9787020008728
---- [6] 删除 (doDelete) ----
删除 book_id=1 后, 剩余 Book 行数=0, Author 行数=1 (外键只级联删 book, 作者保留)
---- 全部步骤通过 ----
结果解读:六组演示全部按预期输出——Torque.init 识别 bookstore 数据源;生成的 DDL 成功建出 3 张表与 2 个外键;三次 save() 主键由 IDENTITY 自动分配(均为 1);Criteria.where 条件查询与 doSelectJoinAuthor 联表查询正确命中;更新后 retrieveByPK 回读标题一致;删除 book 后 Author 保留(级联只作用于 book 的外键)。这表示 Torque 4.0 的生成器与运行时已在 JDK 17 上完整可用。
💡 说明:
-Dfile.encoding=UTF-8用于固定中文输出的字符集。若服务器LANG已为C.UTF-8,可省略;在默认POSIXlocale 下省略会出现中文乱码。
五、方案 B:官方 jar 直用(离线友好)
本节面向没有 Maven/构建体系的场景,从 Maven Central 直接下载 torque-runtime 与其全部依赖 jar,用 javac + java 完成编译运行,不依赖任何构建工具。
5.1 方案说明
链路是:下载 14 个运行期 jar 并校验 sha1 → 复用方案 A 已生成的 24 个 OM 源文件(生成物与构建工具无关,任何方式产出的源码都能编译)→ javac -cp 编译 → java -cp 运行。适用于离线环境、脚本化部署或纯粹想「拿到 jar 就能用」的读者。
5.2 下载依赖 jar 与完整性校验
torque-runtime 4.0 的完整运行期依赖经 mvn dependency:list 实测为 14 个 jar(含 Derby 驱动)。逐一下载(命令较长,分两条列出,全部实测):
mkdir -p /root/jar-run/lib && cd /root/jar-run/lib
R=https://repo1.maven.org/maven2
curl -sfO $R/org/apache/torque/torque-runtime/4.0/torque-runtime-4.0.jar
curl -sfO $R/commons-beanutils/commons-beanutils-core/1.8.0/commons-beanutils-core-1.8.0.jar
curl -sfO $R/commons-collections/commons-collections/3.2.1/commons-collections-3.2.1.jar
curl -sfO $R/commons-configuration/commons-configuration/1.6/commons-configuration-1.6.jar
curl -sfO $R/commons-dbcp/commons-dbcp/1.3/commons-dbcp-1.3.jar
curl -sfO $R/commons-digester/commons-digester/1.8/commons-digester-1.8.jar
curl -sfO $R/commons-lang/commons-lang/2.6/commons-lang-2.6.jar
curl -sfO $R/commons-logging/commons-logging/1.1.1/commons-logging-1.1.1.jar
curl -sfO $R/commons-pool/commons-pool/1.5.6/commons-pool-1.5.6.jar
curl -sfO $R/concurrent/concurrent/1.0/concurrent-1.0.jar
curl -sfO $R/org/apache/avalon/framework/avalon-framework-api/4.3.1/avalon-framework-api-4.3.1.jar
curl -sfO $R/org/apache/jcs/jcs/1.3/jcs-1.3.jar
curl -sfO $R/org/apache/derby/derby/10.14.2.0/derby-10.14.2.0.jar
curl -sfO $R/org/apache/derby/derbytools/10.14.2.0/derbytools-10.14.2.0.jar
ls -1 | wc -l
14
校验两个核心 jar 的 sha1(期望值取自仓库同名 .sha1 文件,与实测值必须逐字一致):
cd /root/jar-run/lib
echo "runtime 期望: $(curl -s $R/org/apache/torque/torque-runtime/4.0/torque-runtime-4.0.jar.sha1)"
echo "runtime 实测: $(sha1sum torque-runtime-4.0.jar | cut -d' ' -f1)"
echo "derby 期望: $(curl -s $R/org/apache/derby/derby/10.14.2.0/derby-10.14.2.0.jar.sha1)"
echo "derby 实测: $(sha1sum derby-10.14.2.0.jar | cut -d' ' -f1)"
runtime 期望: 88a2be8e73374586c480516fc085b2f8fea12968
runtime 实测: 88a2be8e73374586c480516fc085b2f8fea12968
derby 期望: 7efad40ef52fbb1f08142f07a83b42d29e47d8ce
derby 实测: 7efad40ef52fbb1f08142f07a83b42d29e47d8ce
两个核心 jar 的实测大小:torque-runtime-4.0.jar 为 228845 字节,derby-10.14.2.0.jar 为 3232770 字节,14 个 jar 合计约 6.4 MB。
⚠️ 注意:jar 清单必须与 pom 解析结果一致。缺 jar 运行时报
NoClassDefFoundError;多 jar 无害。若不放心清单完整性,可在方案 A 的工程上执行mvn dependency:list逐一比对。
5.3 javac 编译与 java 运行
准备源码与资源(OM 生成物 + 验证程序 + 配置):
cd /root/jar-run
mkdir -p src-om src-om-mod res out
cp -r /root/torque-demo/target/generated-sources/com src-om/
cp -r /root/torque-demo/src/main/generated-java/com src-om-mod/
cp /root/torque-demo/src/main/resources/torque.properties /root/torque-demo/src/main/resources/schema.sql res/
编译(24 个 OM 类 + Main,共 25 个编译单元):
javac -encoding UTF-8 -cp "lib/*" -d out \
src-om/com/example/torque/om/*.java \
src-om-mod/com/example/torque/om/*.java \
/root/torque-demo/src/main/java/com/example/torque/Main.java
# 输出节选(实测)
Note: Some input files use or override a deprecated API.
Note: Recompile with -Xlint:deprecation for details.
15 warnings
验证点:编译成功产出 25 个 class;15 个警告全部是 new Integer(int) 构造器在 JDK 9+ 标记 deprecation 所致(2013 年生成代码的正常现象),不影响运行。
运行(注意 classpath 必须包含 res 目录,否则读不到 torque.properties 实测报 NullPointerException: inStream parameter is null):
java -Dfile.encoding=UTF-8 -cp "out:res:lib/*" com.example.torque.Main
---- [1] Torque.init ----
Torque.init 完成, 默认数据库=bookstore, 数据库注册表键=[bookstore, default]
---- [2] 执行生成的 DDL 建表 ----
执行 CREATE/ALTER 语句数=5 (3 张表 + 2 个外键)
---- [3] 新增 (save / 主键自动生成) ----
Publisher 落库: name=人民文学出版社 主键=1
Author 落库: 罗贯中 主键=1
Book 落库: 三国演义 主键=1 author_id=1 publisher_id=1
---- [4] 查询 (Criteria + Peer.doSelect) ----
doSelect 命中: id=1 姓名=罗贯中
doSelectJoinAuthor: 《三国演义》 作者=罗贯中
---- [5] 更新 (save / retrieveByPK) ----
retrieveByPK(1) 标题=三国演义(校注本) ISBN=9787020008728
---- [6] 删除 (doDelete) ----
删除 book_id=1 后, 剩余 Book 行数=0, Author 行数=1 (外键只级联删 book, 作者保留)
---- 全部步骤通过 ----
验证点:java -cp 一行成功跑完六组结果,且无 NoClassDefFoundError,说明手工 classpath 可用;结果与方案 A 完全一致。
5.4 torque-generator 独立分发包的定位说明
Maven Central 的 org.apache.torque:torque-generator:4.0 另有 bin 分发包(torque-generator-4.0-bin.tar.gz,实测 4822484 字节),解压后为 torque-generator 主 jar 与 8 个依赖 jar。需要说明的是,4.0 版该包内没有命令行启动脚本,主 jar 的 MANIFEST 也没有 Main-Class(实测 jar tf 与 MANIFEST 核验),它面向 Ant 任务或自定义程序内嵌调用。想在无 Maven 环境做 OM 生成,本文 5.3 节的「预生成源码 + javac」方式即为可落地的替代路径;需要纯命令行生成的读者可评估 5.x 及以上版本的 generator 分发包。
六、方案对比与选择建议
本节汇总两种方案的差异,给出选型建议。两种方案运行的是同一份 Torque 4.0 代码与同一批生成类,差别仅在获取与装配方式。
| 维度 | 方案 A:Maven 插件 | 方案 B:jar 直用 |
|---|---|---|
| OM 类生成 | mvn torque:generate 一键生成 | 依赖方案 A 产出的源码(generator 4.0 无 CLI) |
| 运行期依赖 | Maven 自动解析 14 个 jar | 手工下载 14 个 jar 并拼 classpath |
| 是否联网 | 首次构建需联网 | 仅下载时需要联网 |
| 依赖版本管控 | pom 统一声明,可锁版本 | 无,靠文件命名区分 |
| 完整性校验 | Maven 自动校验 | 需手工比对 sha1 |
| 适用场景 | 常规工程开发 | 离线脚本、临时验证、无构建体系 |
选型建议:只要工程有构建体系,一律选方案 A——OM 生成是 Torque 的核心工作流,离开 Maven 插件(或 Ant 任务)无法完成;方案 B 的价值在于运行期部署:用方案 A 生成并提交源码后,运行环境完全可以无构建工具。两者也可共存——用方案 A 开发生成,用方案 B 分发运行。
七、配置说明
本节汇总 Torque 4.0 实际需要设置的「配置」,分 Maven 插件配置与运行时配置两组,全部实测核验。
7.1 Maven 插件(生成期)配置
packaging=classpath:生成配置的来源模式。classpath 模式从 classpath 上的模板包读取全部配置;默认值directory模式则要求工程提供src/main/torque-gen/conf/control.xml(实测缺文件报control file file /root/torque-demo/src/main/torque-gen/conf/control.xml not found)。快速上手选 classpath 模式。configPackage=org.apache.torque.templates.om:OM 生成模板包。换org.apache.torque.templates.sql即生成 DDL(本文 sql profile)。sourceDir=src/main/schema:schema 文件目录,默认值src/main/torque-gen/src(实测目录不存在时直接报错)。options.torque.om.package:生成类包名,必填。- 生成输出目录:基类固定写
target/generated-sources(${project.build.directory}/generated-sources),可编辑类固定写src/main/generated-java,两者均由插件默认值决定,一般无需调整。
7.2 torque.properties(运行期)配置
torque.database.default=bookstore
torque.database.bookstore.adapter=derby
torque.dsfactory.bookstore.factory=org.apache.torque.dsfactory.SharedPoolDataSourceFactory
torque.dsfactory.bookstore.connection.url=jdbc:derby:memory:bookstore;create=true
torque.dsfactory.bookstore.connection.user=sa
torque.dsfactory.bookstore.connection.password=q1w2e3r4
逐项说明:
torque.database.default:默认数据库逻辑名,Torque.getDefaultDB()返回它,多库场景下每个库各有一组同名键。adapter:数据库适配器,决定 ID 生成、SQL 方言等行为,可选值实测核验为 mssql/hsqldb/mysql/derby/oracle/postgres/none。dsfactory.<库名>.factory:数据源工厂实现,SharedPoolDataSourceFactory提供 DBCP 连接池。注意 4.0 的键名到此为止,没有 3.x 时代的.class后缀。connection.url/user/password:直通连接池的 JDBC 三要素。connection.*下其他属性(如driver)会被 DBCP 拒绝(实测报Property: driver ... is not supported by DataSource: DriverAdapterCPDS),驱动注册改在代码里显式Class.forName完成。torque.dsfactory.bookstore.pool.*:连接池参数(如最大连接数),本文未配置时使用默认值,日常开发够用。
八、多版本管理
Torque 各大版本 artifact 坐标相同、JDK 基线不同,多版本共存靠「隔离依赖坐标 + 隔离 jar 文件名」实现。
Maven 本地仓库中不同版本的构件并列存放,互不覆盖(实时回显):
ls -1 $HOME/.m2/repository/org/apache/torque/torque-runtime/
4.0
5.1
7.0
要点:工程要用哪个版本,只改 pom.xml 的 <dependency><version> 即可,其余版本留在本地仓库供其他工程复用。但注意跨大版本切换不是改数字那么简单:5.x 起运行时拆分为多模块、6.0/7.0 抬高 JDK 基线、部分配置键有变化,切换前应查阅对应版本官网。jar 直跑场景,把不同版本 jar 分目录存放(如 /root/jar-run-7/lib),运行时按需拼 classpath。
切换工程依赖版本并验证生效:
cd /root/torque-demo && mvn -B dependency:tree 2>&1 | grep torque
[INFO] +- org.apache.torque:torque-runtime:jar:4.0:compile
[INFO] | +- commons-collections:commons-collections:jar:3.2.1:compile
[INFO] | +- commons-configuration:commons-configuration:jar:1.6:compile
[INFO] | +- commons-dbcp:commons-dbcp:jar:1.3:compile
[INFO] | +- commons-lang:commons-lang:jar:2.6:compile
[INFO] | +- commons-logging:commons-logging:jar:1.1.1:compile
[INFO] | +- org.apache.jcs:jcs:jar:1.3:compile
[INFO] | \- org.apache.avalon.framework:avalon-framework-api:jar:4.3.1:compile
验证点:依赖树顶层是 torque-runtime:4.0,其下为核心传递依赖,与手工下载清单一致。
九、常见问题(FAQ)
Q1:mvn torque:generate 报 control file file .../src/main/torque-gen/conf/control.xml not found 怎么办?
插件默认 packaging=directory,要求工程自备 control.xml。快速上手直接在插件配置里写 <packaging>classpath</packaging> 与 <configPackage>org.apache.torque.templates.om</configPackage>,用官方模板包自带的生成配置(见 4.4 节),无需手写任何 control 文件。
Q2:报 Option torque.om.package must be set?
OM 模板包要求显式指定生成类包名。在插件 <configuration> 里加 <options><torque.om.package>你的包名</torque.om.package></options>。同理,sql 模板包要求 <torque.database>方言</torque.database>。
Q3:报 Could not list files in the following Directory while reading the sources: .../src/main/torque-gen/src/.?
schema 源目录没配对。classpath 模式下插件不会自动用 src/main/schema,必须显式 <sourceDir>src/main/schema</sourceDir>(见 4.4 节)。
Q4:mvn compile 显示 BUILD SUCCESS 但类都编译不到,或运行报 ClassNotFoundException?
torque-maven-plugin 不会把生成目录注册为编译源目录。确认 pom 已配置 build-helper-maven-plugin 并把 target/generated-sources 与 src/main/generated-java 加入 <sources>(见 4.4 节);只有 target/generated-sources 被注册时,Base* 类能编过而 Author 等业务类报 cannot find symbol。
Q5:运行报 No suitable driver found for jdbc:derby:...?
Torque 4.0 + commons-dbcp 1.3 的组合无法从 torque.properties 注入驱动类名(connection.driver/connection.driverClassName 均被拒绝),Derby 驱动又未必被 JDBC SPI 自动加载(实测 JDK 11 不会、JDK 17 会)。通用解法:在 Torque.init() 之前执行 Class.forName("org.apache.derby.jdbc.EmbeddedDriver")(见 4.7 节)。
Q6:报 No DataSourceFactory definition for default DB found ... under the key torque.dsfactory.bookstore.factory?
4.0 的数据源工厂键名是 torque.dsfactory.<库名>.factory,值直接写工厂类全名;按 3.x 习惯写成 torque.dsfactory.<库名>.factory.class 会被忽略而报此错。
Q7:中文输出显示为乱码(问号)?
默认 POSIX locale 下 JVM 会用 ASCII 输出中文。解决:运行时加 -Dfile.encoding=UTF-8,或把系统 locale 调成 UTF-8(export LANG=C.UTF-8)。
Q8:torque-runtime 4.0 能不能跑在 JDK 8 上?
可以。4.0 官方 JDK 基线为 1.6,本文以 JDK 17 实测全链路通过,JDK 8 向下兼容没有障碍;配套 Derby 用 10.14.2.0(Java 8 字节码)。注意不要把 Derby 升到 10.16.1.1——它是 Java 17 字节码,JDK 11 及以下加载驱动直接抛 UnsupportedClassVersionError(本文第三章实测踩坑记录)。
十、卸载与清理
Torque 本身不产生系统级安装,卸载即移除依赖与本地文件。
移除工程与本地 jar(清理本文全部产物):
rm -rf /root/torque-demo /root/jar-run
ls /root/torque-demo 2>&1
ls: cannot access '/root/torque-demo': No such file or directory
移除 Maven 本地仓库中的 Torque 构件(影响所有工程,慎用):
rm -rf $HOME/.m2/repository/org/apache/torque
卸载 JDK 与 Maven(仅当不再需要)。先以 -s 预演确认将删除的包,无误后去掉 -s 真正执行:
apt-get -s purge -y openjdk-17-jdk maven
# 输出节选(实测)
The following packages will be REMOVED:
maven* openjdk-17-jdk*
0 upgraded, 0 newly installed, 2 to remove and 2 not upgraded.
Purg maven [3.6.3-5]
Purg openjdk-17-jdk [17.0.20.1+1-1~22.04]
确认无误后真正卸载:
apt-get purge -y openjdk-17-jdk maven && apt-get autoremove -y
十一、参考链接
- Apache Torque 官方主页:https://db.apache.org/torque/
- Torque 版本与 JDK 基线官方说明(官网首页):https://db.apache.org/torque/
- Maven 中央仓库 torque-runtime 坐标页:https://repo1.maven.org/maven2/org/apache/torque/torque-runtime/
- Maven 中央仓库 torque-maven-plugin 坐标页:https://repo1.maven.org/maven2/org/apache/torque/torque-maven-plugin/
- Maven 中央仓库 torque-generator 坐标页(含 4.0 bin 分发包):https://repo1.maven.org/maven2/org/apache/torque/torque-generator/
- Apache Derby 官方站点:https://db.apache.org/derby/
- OpenJDK 17 安装包(Ubuntu 官方源):
apt-cache show openjdk-17-jdk