如何在没有分布式事务的情况下使用JPA将同一对象持久化到两个不同的db?

时间:2013-10-05 05:03:46

标签: jpa eclipselink jta glassfish-4

我想将同一个实体持久化到MySQL数据库和Postgres数据库(实际上一个是另一个的实时克隆)。从概念上讲,我想用一种方法做到这一点:

EntityManager mysql = ...;
EntityManager postgres = ...;
MyEntity e = new MyEntity();
e.setStuff();
mysql.persist(e);
postgres.persist(e);

MyEntity类为其@GeneratedValue字段指定IDENTITY @Id策略,两个数据源为非XA数据源。

JPA / JTA似乎想在分布式事务中执行此操作,我认为这是由于如何为容器管理的事务确定事务边界,并且因为数据源是非XA而出现错误。我可以将数据源定义为XA源,因此上述工作作为分布式事务,但是对于迫切需要,这实际上是不必要的。我真的不在乎这两个持续存在于同一个事务中 - 事实上,如果一个失败而另一个失败,那也没关系(至少目前为止)。

有没有办法将同一个对象持久化到具有非XA数据源的多个数据库,仍然使用容器管理的事务?相关的,如果我想在一个方法中对多个对象和多个数据源进行一系列持久化,是否有办法使用非XA数据源?我正在使用带有GlassFish 4.0的EclipseLink。

1 个答案:

答案 0 :(得分:0)

嗯,没有发现如何使用容器管理的事务来完成它,而是使用bean管理的事务来完成它。注入一个UserTransaction资源,并将每个持久化包装在开始/提交对之间:

@Stateless
@TransactionManagement(TransactionManagementType.BEAN)
public class MyClass 
{
  @Resource private UserTransaction utx;

  public void doStuff() 
  {
    EntityManager mysql = ...;
    EntityManager postgres = ...;
    MyEntity e = new MyEntity();
    e.setStuff();
    try {
      utx.begin();
      mysql.persist(e);
      utx.commit();
      utx.begin();
      postgres.persist(e);
      utx.end();
    } catch (...) {
    ...
    }
  }
}

我之前从未尝试过使用bean管理的事务,即使这不是生产用途而且不是特别优雅,如果这有一些根本性的错误,我会感谢有人指出正确的方法。