Ebean ORM 使用指南

更新于 2025-12-29

baeldung 2018-10-14

1. 简介

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

尽管它支持标准的 JPA 注解来声明实体,但它提供了一个更简洁的 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>

请确保使用 Ebean 和 H2 的最新版本。

2.2 字节码增强(Enhancements)

Ebean 需要对实体类进行字节码增强,以便服务器能够管理它们。为此,我们需要在 pom.xml 中添加 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>

此外,我们还需要告诉 Maven 插件哪些包中包含实体类和使用事务的类。为此,创建一个名为 ebean.mf 的文件:

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

2.3 日志配置

最后,创建 logback.xml 文件,并将某些包的日志级别设置为 TRACE,以便查看执行的 SQL 语句:

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

3. 配置数据库服务器

接下来,我们将创建一个 Database 实例,用于保存实体或执行数据库查询。有两种方式可以创建服务器实例:使用默认属性文件或通过编程方式配置。下面分别介绍。

3.1 使用默认属性文件

Ebean 会自动查找名为 application.propertiesebean.propertiesapplication.yml 的配置文件(支持 .properties.yaml 格式)。

除了提供数据库连接信息外,还可以指示 Ebean 自动生成并执行 DDL 语句。

示例配置如下(ebean.properties):

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

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 实例对应一个数据库。根据需求,可以创建多个 Database 实例。

如果只创建了一个服务器实例,Ebean 会自动将其注册为默认服务器实例,可以通过 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 注解(来自 io.ebean.annotation 包)实现自动审计功能。

接着,创建两个继承 BaseModel 的实体类: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 的一对一关系,并设置了 CascadeType.ALL,这样在保存或更新 Customer 时,关联的 Address 也会被自动处理。


5. 基本 CRUD 操作

前面我们已经完成了数据库配置和实体定义,现在来执行一些基本的增删改查(CRUD)操作。

我们将使用默认服务器实例来持久化和访问数据。DB 类也提供了静态方法来代理默认服务器的操作:

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 对象,并通过 save() 方法保存。
  2. 然后修改客户信息并再次调用 save() 进行更新。
  3. 使用 DB.find() 根据 ID 查询客户。
  4. 最后调用 delete() 删除该客户。

6. 查询

Ebean 提供了强大的查询 API,可用于构建带过滤条件和谓词的对象图。我们可以使用 EbeanEbeanServer 来创建和执行查询。

下面是一个查询示例:按城市查找客户,并仅加载部分字段:

Customer customer = DB.find(Customer.class)
            .select("name")
            .fetch("address", "city")
            .where()
            .eq("city", "San Jose")
            .findOne();
  • find(Customer.class):指定查询的实体类型。
  • select("name"):仅加载 Customername 字段。
  • fetch("address", "city"):同时加载关联的 Address 实体,并仅获取其 city 字段。
  • where().eq("city", "San Jose"):添加查询条件。
  • findOne():限制结果为单条记录。

7. 事务

Ebean 默认为每条语句或查询开启一个新事务。

但在某些场景下,我们希望将一组操作放在同一个事务中执行。此时,可以使用 @Transactional 注解(来自 io.ebean.annotations 包):

@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 的基本功能,包括:

  • 环境配置与依赖管理
  • 实体定义(支持 JPA 与 Ebean 特有注解)
  • CRUD 操作
  • 高级查询(字段选择、关联加载、条件过滤)
  • 事务控制

Ebean 凭借其简洁的 API、无会话设计以及对原生 SQL 的良好支持,成为 Java 应用中轻量级且高效的 ORM 选择。