【问题标题】:Transactions not Persisting In Time in JettyJetty 中的交易没有及时持续
【发布时间】:2012-08-16 13:26:30
【问题描述】:

我继承了一些代码,当我尝试添加一些功能时,这些代码无法正常工作。我不是 Java 网络方面的专家,所以如果我需要任何额外的帮助来为您提供所需的信息,我提前道歉。

我正在开发一个 GWT 应用程序,它在后端使用 Hibernate 和 Guice-Persist 来持久保存到 MySQL。不幸的是,我遇到了一个奇怪的问题——在一台服务器上——put 事务没有及时保存到数据库中以被后续的get 事务识别。 在 Windows 中嵌入 GWT Eclipse 插件(可能是 6.1.11?)的任何版本的 Jetty 和 Linux 中的 Tomcat6 中,一切都可以完美运行,但是当我尝试在 Linux 中使用 jetty-maven-plugin 版本 8.1.0 运行它时(也在8.1.5 中,我尝试过的唯一两个版本),我遇到了交易未及时完成的​​问题。(或者,我会很高兴有一个解决方案可以让我正确地使用 Jetty 以外的其他工具在 Maven 中运行我的集成测试,以完全回避这个问题。似乎代码在我尝试过的所有其他服务器上下文中都有效)。

这是我用来持久化对象的代码:

public T put(T entity) {
    EntityManager entityManager = entityManager();
    EntityTransaction transaction = entityManager.getTransaction();        
    transaction.begin();
    try {
        entity = entityManager.merge(entity);
        entityManager.persist(entity);
        transaction.commit();

    } catch (Exception e) {
        //do exception handling, including rollback
    }


    return entity;
}

还有获取代码:

public List<T> getAll() {
    Query query = entityManager().createQuery("select c from " + clazz.getSimpleName() + " c");

    return (List<T>) query.getResultList();
}

再次,发生的事情是我对getAll() 进行(间接)调用以允许客户端查看数据。然后,如果他们做出选择,请从客户端拨打put 电话。然后,一旦我得到响应,请致电 getAll() 以更新显示给用户的数据。不幸的是,我从数据库返回的数据并没有反映更新的数据,而是在put() 调用之前存在的数据。数据库最终会更新,当我自己检查数据库时,它似乎会立即更新。如果我重新加载数据几次,Web 应用程序最终也会更新以显示正确的数据。所以我怀疑某些缓存层可能会在没有实际检查数据库的情况下响应我的getAll() 请求,但我真的不确定如何继续——事务和实体管理器对我来说相当新。

我已经尝试flush()ing 和close()ing 我的实体管理器而不是提交我的事务,并且行为没有任何变化。

我在构造函数中注入了我的 EntityManager Provider:

private final Class<T> clazz;
private final Provider<EntityManager> entityManagerProvider;

public BaseDao(final Class<T> clazz, final Provider<EntityManager> entityManagerProvider) {
    this.clazz = clazz;
    this.entityManagerProvider = entityManagerProvider;
}

并获得这样的实体管理器:

protected EntityManager entityManager() {
    return entityManagerProvider.get();
}

谢谢!

为了后代,这是我的 GuiceServletContextListener:

public class GuiceServletConfig extends GuiceServletContextListener {
@Override
protected Injector getInjector() {
    DispatchServletModule dispatchServletModule = new DispatchServletModule();
    Injector injector = Guice.createInjector(new ServerModule(), new JpaPersistModule(getPersistenceUnit()),
            dispatchServletModule);

    PersistService persistService = injector.getInstance(PersistService.class);
    persistService.start();

    BootStrapper bootStrapper = injector.getInstance(BootStrapper.class);
    bootStrapper.init();



    return injector;
}

private String getPersistenceUnit() {
    InputStream inputStream = getClass().getResourceAsStream("/database.properties");

    if (inputStream == null) {
        throw new RuntimeException();
    }

    try {
        Properties properties = new Properties();
        properties.load(inputStream);

        return properties.getProperty("persistenceUnit");
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
}


}

还有我的 ServletModule:

public class DispatchServletModule extends ServletModule {      
  @Override
  public void configureServlets() {
    serve("/" + ActionImpl.DEFAULT_SERVICE_NAME + "*").with(DispatchServiceImpl.class);
  }
}

我尝试在 configureServlets() 中添加一个过滤器,而不是手动启动持久性会话,以尝试使用 session-per-http-request(根据 this page)但没有成功。

【问题讨论】:

  • 好吧,你应该先向我们提供任何信息......
  • 同意... 输入标签时按回车键太快。我的错。给我一点时间...
  • 只是好奇:调试输出告诉你什么?通常您应该看到执行的 SQL。你确定它没有抛出你刚刚捕获并默默忽略的异常吗?
  • 我没有启用 Hibernate 的 SQL 输出。我可以尝试一下,以确保一切都以正确的顺序执行。另外,我很犹豫是否认为put() 有任何错误,因为数据库 is 最终是一致的。所以一切正常,只是顺序不正确(在一个环境中)。
  • 一个奇怪的条目:2012-08-23 13:07:04.510:INFO:oejpw.PlusConfiguration:No Transaction manager found - if your webapp requires one, please configure one. 我没有在我的其他服务器日志中注意到这一点(尽管我可能会错过它)。

标签: java hibernate gwt jpa guice


【解决方案1】:

首先,您可能应该回滚catch 块中的事务,并且不要忽略异常(至少记录它)。但是guice-persist 支持@Transactional 注释,所以实际上您根本不需要进行手动事务管理。见Transactions - google-guice

【讨论】:

  • 谢谢。隐藏在“做异常处理”中的其实是一个rollback() 调用。我会调查你提到的那个链接。
  • 只是为了确保我理解您的 cmets...您是否建议 @Transactional 注释将改变代码的行为并解决问题?还是更容易维护?引入 UnitOfWork 系统是否有助于确保及时回写我的数据?
  • @Jeff:我不确定它是否能解决你的问题,但是当你让图书馆为你做事时,以正确的方式做事总是更容易。请注意,@Transactional 需要位于由 Guice 注入的类的方法上。
【解决方案2】:

您是否希望关闭与事务关联的会话?

public T put(T entity) {
    EntityManager entityManager = entityManager();
    EntityTransaction transaction = entityManager.getTransaction();        
    transaction.begin();
    try {
        entity = entityManager.merge(entity);
        entityManager.persist(entity);
        transaction.commit();

    } catch (Exception e) {
        //do exception handling, including rollback
    } finally {
        entityManager.close();
    }

    return entity;
}

但您可以强制事务与刷新同步:

public T put(T entity) {
    EntityManager entityManager = entityManager();
    EntityTransaction transaction = entityManager.getTransaction();        
    transaction.begin();
    try {
        entity = entityManager.merge(entity);
        entityManager.persist(entity);
        entityManager.flush();
        transaction.commit();

    } catch (Exception e) {
        //do exception handling, including rollback
    }

    return entity;
}

问候,

【讨论】:

  • 还没有运气,但我认为我们可能会朝着正确的方向前进...我在我的一个put() 电话中收到了EntityManager is closed 的错误——它看起来像我的@987654326 @ 正在返回使用过的 EntityManagers 实例,而不是丢弃它们并制作新实例。我应该以不同的方式创建我的 EntityManagers 吗?
  • 您能更具体地使用该链接吗?我没有看到任何可以立即解决这个问题的东西。在发现EntityManagers 被回收后,我意识到也许在返回之前clear()ing entityManager 可能会解决其中的一些问题。确实,它现在更加稳定,但我必须在每个函数的末尾手动 clear() 每个 EntityManager。关于如何使用它的任何想法?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-27
  • 2016-01-12
  • 2015-04-27
  • 1970-01-01
  • 2016-07-27
相关资源
最近更新 更多