Play 2.6 使用Ebean

Ebean的使用

https://playframework.com/documentation/2.6.x/JavaEbean

配置Ebean

Play自带Ebean。首先在project/plugins.sbt中添加插件

addSbtPlugin("com.typesafe.sbt" % "sbt-play-ebean" % "4.0.1")

然后在build.sbt中启用

lazy val myProject = (project in file("."))
  .enablePlugins(PlayJava, PlayEbean)

配置模型

Play Ebean带有两个组件,一个运行时库与数据库进行交互,另一个sbt插件帮助增强编译java字节码。这两个组件都需要进行配置这样Ebean才能知道你的模型在哪。

配置运行时库

可以通过添加一个含有Ebean模型的package或class列表来配置运行时环境。如果你的模型都在models包中,那么在application.conf中添加

ebean.default = ["models.*"]

这里定义了一个defaultEbean服务,使用default数据源。通过配置ebeanconfig.datasource.default可以重写default服务的名字。在使用独立的数据库进行开发和测试时会很有用。你可以根据需要尽可能多的创建Ebean服务,然后对类和服务进行映射

ebean.orders = ["models.Order", "models.OrderItem"]
ebean.customers =  ["models.Customer", "models.Address"]

每一行都可以映射任意多个Ebean会被使用到的类(eg. @Entity/Model classes, @Embeddables, custom ScalarTypes and CompoundTypes, BeanPersistControllers, BeanPersistListeners, BeanFinders, ServerConfigStartups, etc)。这些可以用逗号分割开,通配符.*也可以使用。

为了定制化Ebean服务的配置,可以另外添加一个conf/ebean.properties的文件,或者创建一个ServerConfigStartup在服务初始化前实例以编程的方式来配置EBeanServerConfig

一个例子, 一个非常场景的问题是为了最小sequence gap化要减少sequence batch的大小,可以通过下面的代码来解决。:

package models;

import io.ebean.config.ServerConfig;
import io.ebean.event.ServerConfigStartup;

public class MyServerConfigStartup implements ServerConfigStartup {
    public void onStart(ServerConfig serverConfig) {
        serverConfig.setDatabaseSequenceBatchSize(1);
    }
}

Ebean也会使用conf/orm.xml文件(如果存在的话)来配置

Ebean文档地址
http://ebean-orm.github.io/docs/

配置sbt插件

默认情况下sbt插件会试着读取application.conf的配置来发现models的配置。在简单的工程中这会有效果,但是对于拥有多个子工程的工程来说,由于application.conf会在一个不同的工程(ebean模型所在的工程)中,这时就会出现问题。在这种情况下需要为每个含有model的子工程指定ebean model。使用playEbeanModels配置项:

playEbeanModels in Compile := Seq("models.*")

在配置时你可能想要启动debug,可以使用playEbeanDebugLevel来配置,-1是关闭,9是显示最多信息

playEbeanDebugLevel := 4

也可以通过playEbeanAgentArgs设置为ebean代理设置参数

playEbeanAgentArgs += ("detect" -> "false")

最后,如果逆向在测试中enhance models,可以对ebean测试进行配置

inConfig(Test)(PlayEbean.scopedSettings)

playEbeanModels in Test := Seq("models.*")

使用Model超类

Ebean定义了一个非常方便的超类io.ebean.Model供你使用

package models;

import java.util.*;
import javax.persistence.*;

import io.ebean.*;
import play.data.format.*;
import play.data.validation.*;

@Entity
public class Task extends Model {

    @Id
    @Constraints.Min(10)
    public Long id;

    @Constraints.Required
    public String name;

    public boolean done;

    @Formats.DateTime(pattern="dd/MM/yyyy")
    public Date dueDate = new Date();

    public static final Finder find = new Finder<>(Task.class);
}

Play被设计为自动生成getter/setter来保证各中类库能够在运行时使用(ORM,DataBinder,JSON Binderd等)。如果Play检测到models中有任何手写的getter/setter方法,就不会产生getter/setter以避免冲突。

附加说明

(1)由于Ebean类型增强是在编译期之后,不要期待能够在编译期使用Ebean生成的getter/setter方法。如果你更喜欢在代码中直接使用,要么自己显示声明,要么保证你的model类在使用前已经编译了,eg,在另外一个子工程使用.

(2)Ebean对域访问的的增强(启动懒加载)仅对Java类有效。因此从Scala源文件(包括标准的Play模板)中直接访问域不会调用懒加载,这经常会导致域值为空(未发布)。为了保证获取正确的数据,有两种方法(a)手写getter/setter方法(b)在使用前保证实体已经完成发布。

如你所见我们添加了一个名为find的static域,为类型为Task的实体定了一个Finder,其中包含了一个Long的标志。这个域可以帮助我们进行简单的查询:

// Find all tasks
List tasks = Task.find.all();

// Find a task by ID
Task anyTask = Task.find.byId(34L);

// Delete a task by ID
Task.find.ref(34L).delete();

// More complex task query
List cocoTasks = Task.find.query().where()
        .ilike("name", "%coco%")
        .orderBy("dueDate asc")
        .setFirstRow(0)
        .setMaxRows(25)
        .findPagedList()
        .getList();

事务

Ebean默认会启用事物,但是这些事务会在单一个sql语句前创建,然后提交或者回滚。

// Created implicit transaction
Task task = Task.find.byId(34L);
// Transaction committed or rolled back

task.done = true;

// Created implicit transaction
task.save();
// Transaction committed or rolled back

如果你想在事务中进行多项操作,你需要使用TxRunnable和TxCallable

import io.ebean.*;

...

Ebean.execute(() -> {
    // code running in "REQUIRED" transactional scope
    // ... as "REQUIRED" is the default TxType
    System.out.println(Ebean.currentTransaction());

    Task task = Task.find.byId(34L);
    task.done = true;

    task.save();
});

如果你的类是一个action,可以在action方法前添加注解@play.db.ebean.Transactional来将你的action方法域一个Action组合起来,这会自动管理一个事务

import play.db.ebean.Transactional;

...

@Transactional
public Result done(long id) {
    Task task = Task.find.byId(34L);
    task.done = true;

    task.save();
    return ok();
}

如果你想通过一个更传统的方法来开始、提交、回滚一个事务:

Ebean.beginTransaction();
try {
    Task task = Task.find.byId(34L);
    task.done = true;

    task.save();

    Ebean.commitTransaction();
} finally {
    Ebean.endTransaction();
}

你可能感兴趣的:(play,2.6,java,Ebean)