1. 简介

Ebean 是一个用 Java 编写的对象关系映射(ORM)工具。

虽然它支持标准的 JPA 注解 来定义实体类,但 Ebean 提供了更加简洁的 API 来进行数据持久化操作。值得一提的是,Ebean 是 无会话(sessionless) 架构,这意味着它不会对实体进行全生命周期管理。此外,Ebean 支持原生 SQL 查询,并兼容主流数据库,例如 Oracle、PostgreSQL、MySQL、H2 等。

接下来,我们将从创建和持久化数据开始,然后使用 Ebean 和 H2 数据库进行实体查询。

2. 环境配置

首先,我们需要添加必要的依赖项来搭建项目环境。

2.1. Maven 依赖

pom.xml 文件中添加以下依赖:

<dependency>
    <groupId>io.ebean</groupId>
    <artifactId>ebean</artifactId>
    <version>13.25.2</version>
</dependency>
<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
    <version>2.1.214</version>
</dependency>

✅ 建议始终使用最新版本的 EbeanH2

2.2. 实体增强(Enhancements)

Ebean 需要对实体类进行增强处理,以便服务器能够对其进行管理。为此,我们需要添加 ebean-maven-plugin 插件:

<plugin>
    <groupId>io.ebean</groupId>
    <artifactId>ebean-maven-plugin</artifactId>
    <version>13.25.2</version>
    <executions>
        <execution>
            <id>main</id>
            <phase>process-classes</phase>
            <configuration>
                <transformArgs>debug=1</transformArgs>
            </configuration>
            <goals>
                <goal>enhance</goal>
            </goals>
        </execution>
    </executions>
</plugin>

此外,我们还需要通过 ebean.mf 文件告知插件哪些包中包含实体类和事务类:

entity-packages: com.baeldung.ebean.model
transactional-packages: com.baeldung.ebean.app

2.3. 日志配置

为了方便调试,我们可以在 logback.xml 中开启相关日志:

<logger name="io.ebean.DDL" level="TRACE"/>
<logger name="io.ebean.SQL" level="TRACE"/>
<logger name="io.ebean.TXN" level="TRACE"/>

这样就可以看到 Ebean 执行的 DDL、SQL 和事务日志。

3. 数据库服务器配置

接下来,我们需要创建一个 Database 实例,用于保存实体或执行查询。有两种方式可以创建数据库实例:使用默认配置文件或通过编程方式。

3.1. 使用默认配置文件

Ebean 会自动查找名为 application.propertiesebean.propertiesapplication.yml 的配置文件。

示例配置如下:

ebean.db.ddl.generate=true
ebean.db.ddl.run=true

datasource.db.username=sa
datasource.db.password=
datasource.db.databaseUrl=jdbc:h2:mem:customer
datasource.db.databaseDriver=org.h2.Driver

通过这些配置,我们可以指定数据库连接信息,并让 Ebean 自动生成并执行 DDL 语句。

3.2. 使用 DatabaseConfig 编程配置

我们也可以使用 DatabaseFactoryDatabaseConfig 来手动创建数据库实例:

DatabaseConfig cfg = new DatabaseConfig();

Properties properties = new Properties();
properties.put("ebean.db.ddl.generate", "true");
properties.put("ebean.db.ddl.run", "true");
properties.put("datasource.db.username", "sa");
properties.put("datasource.db.password", "");
properties.put("datasource.db.databaseUrl", "jdbc:h2:mem:app2");
properties.put("datasource.db.databaseDriver", "org.h2.Driver");

cfg.loadFromProperties(properties);
Database server = DatabaseFactory.create(cfg);

3.3. 默认数据库实例

一个 Database 实例对应一个数据库。 根据需要,我们可以创建多个实例。

如果只创建了一个实例,它将自动注册为默认数据库实例,可以通过 DB 类的静态方法访问:

Database server = DB.getDefault();

如果存在多个数据库实例,可以通过以下方式设置默认实例:

cfg.setDefaultServer(true);

4. 创建实体类

Ebean 支持标准的 JPA 注解,同时也提供了自己的扩展注解。

我们先创建一个基类 BaseModel,用于定义通用字段:

@MappedSuperclass
public abstract class BaseModel {

    @Id
    protected long id;
    
    @Version
    protected long version;
    
    @WhenCreated
    protected Instant createdOn;
    
    @WhenModified
    protected Instant modifiedOn;

    // getters and setters
}

这里使用了 JPA 的 @MappedSuperclass,以及 Ebean 的 @WhenCreated@WhenModified 注解用于审计。

然后创建两个实体类 CustomerAddress

@Entity
public class Customer extends BaseModel {

    public Customer(String name, Address address) {
        super();
        this.name = name;
        this.address = address;
    }

    private String name;

    @OneToOne(cascade = CascadeType.ALL)
    Address address;

    // getters and setters
}
@Entity
public class Address extends BaseModel {

    public Address(String addressLine1, String addressLine2, String city) {
        super();
        this.addressLine1 = addressLine1;
        this.addressLine2 = addressLine2;
        this.city = city;
    }
    
    private String addressLine1;
    private String addressLine2;
    private String city;

    // getters and setters
}

Customer 类中,我们定义了与 Address 的一对一关系,并设置了级联操作。

5. 基本 CRUD 操作

我们已经完成了数据库配置和实体创建,现在来进行基本的 CRUD 操作。

使用默认数据库实例进行数据持久化和查询:

Address a1 = new Address("5, Wide Street", null, "New York");
Customer c1 = new Customer("John Wide", a1);

Database server = DB.getDefault();
server.save(c1);

c1.setName("Jane Wide");
c1.setAddress(null);
server.save(c1);

Customer foundC1 = DB.find(Customer.class, c1.getId());

DB.delete(foundC1);

步骤如下:

  1. 创建 Customer 对象并保存;
  2. 更新对象并再次保存;
  3. 查询对象并删除。

6. 查询操作

Ebean 的查询 API 支持构建带有过滤条件的对象图。

下面是一个示例查询,查找城市为 "San Jose" 的客户,并只返回部分字段:

Customer customer = DB.find(Customer.class)
            .select("name")
            .fetch("address", "city")
            .where()
            .eq("city", "San Jose")
            .findOne();

说明:

  • find():指定要查询的实体类型;
  • select():指定要加载的字段;
  • fetch():指定关联对象及要加载的字段;
  • where().eq(...):添加查询条件;
  • findOne():返回单个结果。

7. 事务支持

默认情况下,Ebean 会为每个语句或查询开启一个新的事务。

如果需要在同一个事务中执行多个操作,可以使用 @Transactional 注解:

@Transactional
public static void insertAndDeleteInsideTransaction() {
    Customer c1 = getCustomer();
    Database server = DB.getDefault();
    server.save(c1);
    Customer foundC1 = server.find(Customer.class, c1.getId());
    server.delete(foundC1);
}

此时,方法中的所有数据库操作将在同一个事务中执行。

8. 项目构建

最后,使用以下命令构建 Maven 项目并执行增强处理:

mvn compile io.ebean:ebean-maven-plugin:enhance

9. 总结

本文介绍了 Ebean ORM 的基本用法,包括实体定义、数据库配置、CRUD 操作、查询构建以及事务管理。Ebean 以其简洁的 API 和强大的查询能力,成为 Java 持久化领域的一个不错选择。✅



原始标题:Guide to Ebean ORM | Baeldung