批处理
我们可以通过 transaction.setBatchMode(true) 显式启用 JDBC 批处理。
try (Transaction transaction = database.beginTransaction()) {
// use JDBC batch
transaction.setBatchMode(true);
// these go to batch buffer
aBean.save();
bBean.save();
cBean.save();
// batched
database.saveAll(someBeans);
// flush batch and commit
transaction.commit();
}
@Transactional(batchSize)
使用 @Transactional 设置 batchSize
属性将启用 JDBC 批处理。
@Transactional(batchSize = 50)
public void doGoodStuff() {
...
}
批处理大小
批处理大小控制 Ebean 在执行 JDBC 预处理语句之前绑定该语句的次数。在持久化 Bean(例如 customer.save())时,它实际上是持久化 Bean 的数量。
当 Bean(或 SqlUpdate 或 CallableSql)的数量达到批处理大小时,批处理将刷新,缓冲区中的所有语句都将执行。
在持久化不同类型的 Bean 时(例如“订单”和“订单详情”),当任何缓冲区达到批处理大小时,所有缓冲区都将刷新。这允许 Ebean 保留执行顺序,例如在持久化所有“订单”之前持久化所有“订单详情”。
批处理缓冲区大小的默认值通过 databaseConfig.persistBatchSize 设置,其默认值为 20
。我们可以通过 transaction.setBatchSize()
或 @Transactional(batchSize)
在事务中设置缓冲区大小。
try (Transaction transaction = database.beginTransaction()) {
// use JDBC batch
transaction.setBatchMode(true);
transaction.setBatchSize(50);
// these go to batch buffer
aBean.save();
...
// flush batch and commit
transaction.commit();
}
GetGeneratedKeys
默认情况下,Ebean 将在插入 Bean 后获取生成的键。当我们有处理大量行/Bean 的插入,并且我们实际上不需要在插入后获取键时,我们可以关闭获取生成的键以提高性能。
// don't bother getting back the generated keys
transaction.setGetGeneratedKeys(false);
当我们执行大批量插入时,通常会关闭getGeneratedKeys。
try (Transaction transaction = database.beginTransaction()) {
transaction.setBatchMode(true);
transaction.setBatchSize(100);
// turn off GetGeneratedKeys as we don't need the keys
transaction.setGetGeneratedKeys(false);
// maybe even turn off persist cascade ...
transaction.setPersistCascade(false)
// perform lots of inserts ...
...
transaction.commit();
}
刷新
批处理在以下情况下刷新
- 缓冲区达到批处理大小
- 我们执行查询 - 取决于 setFlushOnQuery()
- 我们混合 SqlUpdate、CallableSql 与持久化 Bean - 取决于 setFlushOnMixed()
- 我们对已批处理的 Bean 属性调用 getter 或 setter,例如 bean.getId()
- 我们显式调用 flush()
setFlushOnQuery()
当我们想要执行查询但不想触发刷新时,在事务中设置 setFlushOnQuery(false)
。
try (Transaction transaction = database.beginTransaction()) {
transaction.setBatchMode(true);
transaction.setFlushOnQuery(false);
// these go to batch buffer
aBean.save();
...
// execute this query but we don't
// want that to trigger flush
SomeOtherBean.find.byId(42);
...
transaction.commit();
}
setFlushOnMixed()
当我们想要执行 SqlUpdate 或 CallableSql 混合 bean save()、delete() 等操作,并且不想触发刷新时,在事务中设置 setFlushOnMixed(false)。
try (Transaction transaction = database.beginTransaction()) {
transaction.setBatchMode(true);
transaction.setFlushOnMixed(false);
// these go to batch buffer
aBean.save();
...
// execute SqlUpdate but we don't
// want that to trigger flush
SqlUpdate update = ...
update.execute();
...
transaction.commit();
}
在 getter/setter 上刷新
对于批处理缓冲区中的 Bean,如果我们对生成属性或“未加载”Id 属性调用 getter/setter,这将触发刷新。
try (Transaction transaction = database.beginTransaction()) {
transaction.setBatchMode(true);
// bean goes to batch buffer
myBean.save();
...
// will trigger flush if id is an "unloaded" property
// and myBean is in the buffer (not flushed)
long id = myBean.getId();
// will trigger flush if myBean is in the buffer (not flushed)
Instant whenCreated = myBean.getWhenCreated();
...
transaction.commit();
}
显式 flush()
当我们想要确保已执行任何批处理语句时,我们可能希望执行显式 transaction.flush()
。这通常意味着我们知道已执行所有 SQL 语句,并且在应用程序逻辑中的该点测试了所有 DB 约束。
try (Transaction transaction = database.beginTransaction()) {
transaction.setBatchMode(true);
// bean goes to batch buffer
myBean.save();
...
// ensure all SQL statements are executed which means that
// all DB constraints (unique, foreign key etc) are tested
transaction.flush();
// carry on with stuff ...
...
transaction.commit();
}
通过 DatabaseConfig 配置
// use JDBC batch by default
databaseConfig.setPersistBatch(PersistBatch.ALL);
我们可以设置 databaseConfig.setPersistBatch(PersistBatch.ALL),以便 JDBC 批处理模式成为所有事务使用的默认模式。
// default batch size
databaseConfig.setPersistBatchSize(50);
我们可以通过 databaseConfig.setPersistBatchSize() 更改全局默认批处理大小。否则,默认设置为 20。
// update all loaded properties or just dirty properties
databaseConfig.setUpdateAllPropertiesInBatch(true);
在使用批处理更新时,我们有权选择在更新中包含脏属性或所有已加载属性。如果我们选择脏属性,我们将把较少的属性包含在更新语句中,但我们可能会得到更多正在执行的不同更新语句(在应用程序逻辑未更新正在更新的所有 Bean 上的相同属性的情况下)。