1

我有一种方法可以将数据从一个数据库传输到另一个数据库,并在此过程中在目标数据库中创建新表。该方法是无状态 EJB(Java EE 6,GF 3.1)的一部分,因此默认情况下,容器会在调用该方法时启动分布式事务。

数据传输过程本质上分为两个独立的步骤 1. 从源数据库读取 2. 写入目标数据库。如果读取步骤失败,那么我不希望写入步骤发生,但如果写入步骤失败并且读取已经提交,我真的不在乎 - 我只是把数据扔掉。

最初我遇到了我的数据源不是 XADataSource 的问题,所以容器抱怨了这一点。然后我将它们转换为 XADataSource,但它仍然失败,因为写入过程(在 MySQL 数据库中)包含导致隐式提交的创建表语句,而您不能在分布式事务中执行此操作。

我最终得出的解决方案是将传输方法标记为TransactionAttributeType.NOT_SUPPORTED,然后将读写过程放入父传输方法调用的自己的方法中。

不过我的问题是:读写方法是在它们自己的事务中运行还是 NOT_SUPPORTED 传播给它们?我的猜测是他们有一个隐式的 TransactionAttributeType.REQUIRED ,因此会开始他们自己的事务,但我不确定,我认为它们在事务中运行很重要。

这是解决这个问题的最佳方法吗?

4

1 回答 1

1

分离读取和写入步骤的更大问题是,如果其他线程/进程正在改变从读取步骤获得的数据,是否仍应执行写入步骤。换句话说,您确定读取和写入不应该在同一个事务中吗?也许您有一些外部保证,即单独写入数据不会有问题。

read 和 write 方法是如何调用的?如果它们被称为本地方法,则 NOT_SUPPORTED 将传播。如果它们是通过会话 bean 代理对象调用的,那么默认的 REQUIRED 将适用:

@Stateless
@Local(MyIntf.class)
public class MyBean {
    @EJB
    private MyIntf ivMyBean; // Self-injection

    @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
    public void method() {
        // Use the injected proxy rather than "this.read()" to ensure that the
        // default REQUIRED transaction attribute is used for the DB operations.
        MyResults results = ivMyBean.read();
        ivMyBean.write(results);
    }

    public MyResults read() { ... }
    public void write(MyResults results) { ... }
}

您必须根据读取的数据创建表似乎有些问题。真的没有办法将其作为单独的操作吗?我建议使用一个外部 REQUIRED 方法来执行读取操作,然后调用 NOT_SUPPORTED 方法来创建表,最后在与读取相同的事务中执行写入操作,该事务在 NOT_SUPPORTED 方法运行时被暂时挂起。

于 2011-07-22T06:03:09.020 回答