我在编写JavaDB(Derby)事务时出现性能问题。每笔交易花费超过500毫秒,我每天可能有数十万。我期待在MySql上部署,我不知道我是否会遇到同样的问题,但我在尝试之前尝试提高Derby的性能。
一个事务涉及更新一串记录 - 多达6个如此:
public void update(List<Tally> list) {
try {
utx.begin();
for (Tally tally : list) em.merge(tally);
utx.commit();
// etc
我想看看UPDATE查询是否能更好地工作,因为JPA不必跟踪更新和组成SQL查询的列(附带问题:这是一个很好的理论吗?)
所以我编写了一个看起来像这样的命名查询:
@NamedQuery(name="TallyUpdate",
query="UPDATE Tally t SET t.vote = t.vote + 1 WHERE t.id IN :idSet"
这样操作:
@PersistenceContext protected EntityManager em;
@Resource protected UserTransaction utx;
public void incrementVote(List<Long> idList) {
Query q = em.createNamedQuery("TallyUpdate");
q.setParameter("idSet", idList);
try {
utx.begin();
q.executeUpdate();
utx.commit();
//etc
executeUpdate()调用始终抛出异常:
SEVERE: javax.persistence.TransactionRequiredException: executeUpdate is not supported for a Query object obtained through non-transactional access of a container-managed transactional EntityManager
at com.sun.enterprise.container.common.impl.QueryWrapper.executeUpdate(QueryWrapper.java:225)
JPA实现是EclipseLink 2.3.0
这个词 - 沙拉例外是什么意思,我该如何运行更新?
关于相对表现还没有结果,但我上面的帖子有误导性。在计算投票时,它会以24-36种不同的方式计算,而不是6.所以有六次调用原始的 update()方法(使用 merge() )每个都有一个约6条记录的列表。这个调用集合需要超过500毫秒。如果Tally表是空的,那么该基准测试只有大约27ms,这大约是我希望看到的速度。当表填充到50,000行或更多行时,我看到500ms +数字。
如果有人对我发布我最终结果的结果感兴趣,请评论这样说。
P.S。这是在GlassFish下运行的JSF应用程序,而不是EJB。我不确定这与性能有关。
答案 0 :(得分:5)
由于你有一个容器管理实体管理器,我猜你有把东西注入到EJB中。由于这种情况意味着事务由容器管理,即您不需要在代码中明确地启动它们。默认情况下,事务在EJB方法启动时启动,在该方法完成时结束。这适用于无状态EJB。对于有状态EJB,事务可以跨越多个方法调用,并在调用EJB“destroy”方法时结束。所以你应该决定:你要么使用一个容器管理的实体管理器(一个注入EJB,就像你在这里一样),你让容器管理trasactions(通过JTA),或者你做一个应用程序管理的实体管理器,你处理自己在代码中的交易。
关于性能,Apache的人说Derby在某些情况下对于生产,匹配甚至有时甚至超过MySQL和PostgreSQL都是非常好的,正如你在这个Apache文档中看到的那样:
http://home.online.no/~olmsan/publications/pres/apachecon05us/apachecon05.pdf
以一粒盐为例,德比因其表现而闻名世界。甚至这个文档也表明在某些情况下Derby比MySQL慢得多。此外,Derby上的CPU使用率更高。
我的建议:做一个概念验证,并在该数据库上进行基准测试。如果您将在生产中使用它,那么在不同的数据库上对您的应用进行性能调整没有多大意义。