1. 概述
Reladomo(前称 Mithra) 是由高盛开发并开源的 Java 对象关系映射(ORM)框架。它不仅提供了 ORM 的常用功能,还包含一些独特的增强特性。
Reladomo 的核心优势包括:
✅ 代码生成能力:自动生成 Java 类和 DDL 脚本
✅ 元数据驱动:基于 XML 配置文件驱动
✅ 可扩展性:生成的代码支持自定义扩展
✅ 强类型查询:提供面向对象的强类型查询语言
✅ 分片支持:支持同构多数据集分片
✅ 内置测试工具:提供专门的测试支持
✅ 高性能缓存:内置高效缓存机制和事务管理
接下来我们将通过实际示例,逐步解析 Reladomo 的配置与使用。
2. Maven 配置
首先在 pom.xml
中添加核心依赖:
<dependency>
<groupId>com.goldmansachs.reladomo</groupId>
<artifactId>reladomo</artifactId>
<version>18.1.0</version>
</dependency>
示例使用 H2 内存数据库,需额外添加:
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>2.1.214</version>
</dependency>
⚠️ 关键配置:需配置代码生成插件。通过 maven-antrun-plugin
实现类生成:
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<id>generateMithra</id>
<phase>generate-sources</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<tasks>
<property name="plugin_classpath"
refid="maven.plugin.classpath"/>
<taskdef name="gen-reladomo"
classpath="plugin_classpath"
classname="com.gs.fw.common.mithra.generator.MithraGenerator"/>
<gen-reladomo
xml="${project.basedir}/src/main/resources/reladomo/ReladomoClassList.xml"
generateGscListMethod="true"
generatedDir="${project.build.directory}/generated-sources/reladomo"
nonGeneratedDir="${project.basedir}/src/main/java"/>
</tasks>
</configuration>
</execution>
</executions>
</plugin>
该任务通过 MithraGenerator
基于配置文件生成代码,关键目录说明:
-
generatedDir
:存放不可修改的自动生成类 -
nonGeneratedDir
:存放可扩展的具体实体类
DDL 脚本生成任务:
<taskdef
name="gen-ddl"
classname = "com.gs.fw.common.mithra.generator.dbgenerator.MithraDbDefinitionGenerator"
loaderRef="reladomoGenerator">
<classpath refid="maven.plugin.classpath"/>
</taskdef>
<gen-ddl
xml="${project.basedir}/src/main/resources/reladomo/ReladomoClassList.xml"
generatedDir="${project.build.directory}/generated-db/sql"
databaseType="postgres"/>
添加插件依赖:
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<dependencies>
<dependency>
<groupId>com.goldmansachs.reladomo</groupId>
<artifactId>reladomogen</artifactId>
<version>16.5.1</version>
</dependency>
<dependency>
<groupId>com.goldmansachs.reladomo</groupId>
<artifactId>reladomo-gen-util</artifactId>
<version>16.5.1</version>
</dependency>
</dependencies>
</plugin>
最后通过 build-helper-maven-plugin
将生成文件加入 classpath:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<executions>
<execution>
<id>add-source</id>
<phase>generate-sources</phase>
<goals>
<goal>add-source</goal>
</goals>
<configuration>
<sources>
<source>${project.build.directory}/generated-sources/reladomo</source>
</sources>
</configuration>
</execution>
<execution>
<id>add-resource</id>
<phase>generate-resources</phase>
<goals>
<goal>add-resource</goal>
</goals>
<configuration>
<resources>
<resource>
<directory>${project.build.directory}/generated-db/</directory>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
3. XML 配置
3.1. 对象 XML 文件
每个实体需定义独立的 XML 文件。以部门(Department)和员工(Employee)实体为例:
Department.xml 配置:
<MithraObject objectType="transactional">
<PackageName>com.baeldung.reladomo</PackageName>
<ClassName>Department</ClassName>
<DefaultTable>departments</DefaultTable>
<Attribute name="id" javaType="long"
columnName="department_id" primaryKey="true"/>
<Attribute name="name" javaType="String"
columnName="name" maxLength="50" truncate="true"/>
<Relationship name="employees" relatedObject="Employee"
cardinality="one-to-many"
reverseRelationshipName="department"
relatedIsDependent="true">
Employee.departmentId = this.id
</Relationship>
</MithraObject>
关键配置解析:
-
MithraObject
:根元素定义实体 -
Attribute
:属性映射(主键、字段名、类型) Relationship
:关系定义-
cardinality="one-to-many"
:一对多关系 -
reverseRelationshipName
:双向关系简化配置 -
relatedIsDependent="true"
:启用级联操作
-
Employee.xml 配置:
<MithraObject objectType="transactional">
<PackageName>com.baeldung.reladomo</PackageName>
<ClassName>Employee</ClassName>
<DefaultTable>employees</DefaultTable>
<Attribute name="id" javaType="long"
columnName="employee_id" primaryKey="true"/>
<Attribute name="name" javaType="String"
columnName="name" maxLength="50" truncate="true"/>
<Attribute name="departmentId" javaType="long"
columnName="department_id"/>
</MithraObject>
3.2. ReladomoClassList.xml 文件
需在 ReladomoClassList.xml
中声明所有实体:
<Mithra>
<MithraObjectResource name="Department"/>
<MithraObjectResource name="Employee"/>
</Mithra>
该文件作为代码生成任务的输入源,指定需生成类的实体列表。
4. 生成的类结构
执行 mvn clean install
后生成两类代码:
示例 Department
类:
public class Department extends DepartmentAbstract {
public Department() {
super();
// You must not modify this constructor. Mithra calls this internally.
// You can call this constructor. You can also add new constructors.
}
}
❌ 注意:默认构造器不可修改,但可添加自定义构造器:
public Department(long id, String name){
super();
this.setId(id);
this.setName(name);
}
自动生成类(位于 generated-sources/reladomo
):
核心类类型:
-
DepartmentAbstract
/EmployeeAbstract
:实体操作基类 -
DepartmentListAbstract
/EmployeeListAbstract
:集合操作基类 -
DepartmentFinder
/EmployeeFinder
:查询工具类 - 其他辅助类
✅ 优势:CRUD 操作代码已自动生成,无需手动编写。
5. Reladomo 应用开发
5.1. 连接管理器
实现 SourcelessConnectionManager
接口管理数据库连接:
public class ReladomoConnectionManager implements SourcelessConnectionManager {
private static ReladomoConnectionManager instance;
private XAConnectionManager xaConnectionManager;
public static synchronized ReladomoConnectionManager getInstance() {
if (instance == null) {
instance = new ReladomoConnectionManager();
}
return instance;
}
private ReladomoConnectionManager() {
this.createConnectionManager();
}
//...
}
连接池初始化(H2 内存数据库示例):
private XAConnectionManager createConnectionManager() {
xaConnectionManager = new XAConnectionManager();
xaConnectionManager.setDriverClassName("org.h2.Driver");
xaConnectionManager.setJdbcConnectionString("jdbc:h2:mem:myDb");
xaConnectionManager.setJdbcUser("sa");
xaConnectionManager.setJdbcPassword("");
xaConnectionManager.setPoolName("My Connection Pool");
xaConnectionManager.setInitialSize(1);
xaConnectionManager.setPoolSize(10);
xaConnectionManager.initialisePool();
return xaConnectionManager;
}
实现接口方法:
@Override
public Connection getConnection() {
return xaConnectionManager.getConnection();
}
@Override
public DatabaseType getDatabaseType() {
return H2DatabaseType.getInstance();
}
@Override
public TimeZone getDatabaseTimeZone() {
return TimeZone.getDefault();
}
@Override
public String getDatabaseIdentifier() {
return "myDb";
}
@Override
public BulkLoader createBulkLoader() throws BulkLoaderException {
return null;
}
DDL 脚本执行方法(开发环境专用):
public void createTables() throws Exception {
Path ddlPath = Paths.get(ClassLoader.getSystemResource("sql").toURI());
try (
Connection conn = xaConnectionManager.getConnection();
Stream<Path> list = Files.list(ddlPath)) {
list.forEach(path -> {
try {
RunScript.execute(conn, Files.newBufferedReader(path));
}
catch (SQLException | IOException exc){
exc.printStackTrace();
}
});
}
}
5.2. 初始化 Reladomo
创建运行时配置文件 ReladomoRuntimeConfig.xml
:
<MithraRuntime>
<ConnectionManager
className="com.baeldung.reladomo.ReladomoConnectionManager ">
<MithraObjectConfiguration
className="com.baeldung.reladomo.Department" cacheType="partial"/>
<MithraObjectConfiguration
className="com.baeldung.reladomo.Employee " cacheType="partial"/>
</ConnectionManager>
</MithraRuntime>
主类初始化流程:
public class ReladomoApplication {
public static void main(String[] args) {
try {
ReladomoConnectionManager.getInstance().createTables();
} catch (Exception e1) {
e1.printStackTrace();
}
MithraManager mithraManager = MithraManagerProvider.getMithraManager();
mithraManager.setTransactionTimeout(120);
try (InputStream is = ReladomoApplication.class.getClassLoader()
.getResourceAsStream("ReladomoRuntimeConfig.xml")) {
MithraManagerProvider.getMithraManager()
.readConfiguration(is);
//执行业务操作
}
catch (IOException exc){
exc.printStackTrace();
}
}
}
5.3. CRUD 操作示例
级联插入(需在关系配置中设置 relatedIsDependent="true"
):
Department department = new Department(1, "IT");
Employee employee = new Employee(1, "John");
department.getEmployees().add(employee);
department.cascadeInsert();
查询操作:
Department depFound = DepartmentFinder
.findByPrimaryKey(1);
Employee empFound = EmployeeFinder
.findOne(EmployeeFinder.name().eq("John"));
⚠️ 注意:查询返回的是"实时对象",修改会立即同步到数据库:
empFound.setName("Steven"); // 直接更新数据库
获取非实时副本:
Department depDetached = DepartmentFinder
.findByPrimaryKey(1).getDetachedCopy();
删除操作:
empFound.delete();
5.4. 事务管理
使用事务包装操作:
mithraManager.executeTransactionalCommand(tx -> {
Department dep = new Department(2, "HR");
Employee emp = new Employee(2, "Jim");
dep.getEmployees().add(emp);
dep.cascadeInsert();
return null;
});
6. 测试支持
6.1. 测试依赖配置
添加测试专用依赖:
<dependency>
<groupId>com.goldmansachs.reladomo</groupId>
<artifactId>reladomo-test-util</artifactId>
<version>16.5.1</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
6.2. 测试配置文件
创建 ReladomoTestConfig.xml
:
<MithraRuntime>
<ConnectionManager
className="com.gs.fw.common.mithra.test.ConnectionManagerForTests">
<Property name="resourceName" value="testDb"/>
<MithraObjectConfiguration
className="com.baeldung.reladomo.Department" cacheType="partial"/>
<MithraObjectConfiguration
className="com.baeldung.reladomo.Employee " cacheType="partial"/>
</ConnectionManager>
</MithraRuntime>
6.3. 测试数据文件
创建测试数据文件 test-data.txt
:
class com.baeldung.reladomo.Department
id, name
1, "Marketing"
class com.baeldung.reladomo.Employee
id, name
1, "Paul"
6.4. JUnit 测试类
public class ReladomoTest {
private MithraTestResource mithraTestResource;
@Before
public void setUp() throws Exception {
this.mithraTestResource
= new MithraTestResource("reladomo/ReladomoTestConfig.xml");
ConnectionManagerForTests connectionManager
= ConnectionManagerForTests.getInstanceForDbName("testDb");
this.mithraTestResource.createSingleDatabase(connectionManager);
mithraTestResource.addTestDataToDatabase("reladomo/test-data.txt",
connectionManager);
this.mithraTestResource.setUp();
}
@Test
public void whenGetTestData_thenOk() {
Employee employee = EmployeeFinder.findByPrimaryKey(1);
assertEquals(employee.getName(), "Paul");
}
@After
public void tearDown() throws Exception {
this.mithraTestResource.tearDown();
}
}
✅ 优势:自动管理测试数据库生命周期,隔离测试数据。
7. 总结
本文详细解析了 Reladomo 框架的核心特性与使用方法:
- 代码生成:通过 XML 配置自动生成实体类、查询类和 DDL
- 强类型查询:避免 SQL 注入,提升类型安全性
- 缓存优化:内置高效缓存机制
- 测试支持:提供专用测试工具简化单元测试
完整示例代码可在 GitHub 获取。对于需要高性能、强类型 ORM 的企业级应用,Reladomo 是一个值得考虑的选择。