【发布时间】:2017-08-08 05:35:46
【问题描述】:
我有一个默认的standalone.xml 配置,其中在数据库连接池中最多有20 个连接同时处于活动状态。有充分的理由,我猜。我们运行一个 Oracle 数据库。
存在合理数量的数据库流量,因为存在第三方 API 流量,例如我正在开发的企业应用程序中的 SOAP 和 HTTP 调用。
我们经常这样做:
@PersistenceContext(unitName = "some-pu")
private EntityManager em;
public void someBusinessMethod() {
someEntity = em.findSomeEntity();
soap.callEndPoint(someEntity.getSomeProperty()); // may take up to 1 minute
em.update(someEntity);
cdiEvent.fire(finishedBusinessEvent);
}
但是,在这种情况下,在获取实体时获取数据库连接,并在更新后释放(实际上是在整个事务完成时)。关于事务,一切都是容器管理的,没有额外的注释。我知道您不应该“保持”数据库连接超过必要的时间,这正是我要解决的问题。一方面,我不知道如何以编程方式释放连接,我也不认为这是一个好主意,因为您仍然希望能够回滚整个事务。
所以?如何解决这个问题?我尝试了多种选择:
选项 1,使用 ManagedExecutorService:
@Resource
private ManagedExecutorService mes;
public void someBusinessMethod() {
someEntity = em.findSomeEntity();
this.mes.submit(() -> {
soap.callEndPoint(someEntity.getSomeProperty()); // may take up to 1 minute
em.update(someEntity);
cdiEvent.fire(finishedBusinessEvent);
});
}
选项 2,使用 @Asynchronous:
@Inject
private AsyncBean asyncBean;
public void someBusinessMethod() {
someEntity = em.findSomeEntity();
this.asyncBean.process(someEntity);
}
public class AsyncBean {
@Asynchronous
public void process() {
soap.callEndPoint(someEntity.getSomeProperty()); // may take up to 1 minute
em.update(someEntity);
cdiEvent.fire(finishedBusinessEvent);
}
}
这实际上解决了数据库连接池问题,例如soap.callEndPoint 发生后立即释放连接。但感觉不是很稳定(无法确定这里的问题)。当然,一旦你进入异步处理,事务就完成了,所以只要在soap调用过程中出现问题,就没有任何回滚。
结束... 我即将将长时间运行的 IO 任务(soap 和 http 调用)移动到通过队列卸载的应用程序的单独部分,并再次通过队列将结果反馈到应用程序中。在这种情况下,一切都是通过事务完成的,并且没有连接被阻止。但这是很多开销,因此在这样做之前,我想听听您的意见/如何解决这个问题的最佳实践!
【问题讨论】:
-
有多少并发 Web 请求在正常和高峰期执行?
-
大约 50 到 100,峰值约为 200。Wildfly 配置为在从池中获取连接失败之前等待大约 30 秒。没有重试。
-
处理同一实体的并发更改的策略是什么?
标签: database asynchronous jakarta-ee transactions