我有一种方法可以将数据从一个数据库传输到另一个数据库,并在此过程中在目标数据库中创建新表。该方法是无状态EJB(Java EE 6,GF 3.1)的一部分,因此默认情况下,容器在调用方法时启动分布式事务。
数据传输过程基本上作为两个单独的步骤运行1.从源数据库读取2.写入目标数据库。如果读取步骤失败,那么我不希望写入步骤发生,但如果写入步骤失败并且已经提交了读取,我并不在意 - 我只是将数据丢弃。
最初,我遇到的问题是我的数据源不是XADataSource,因此容器抱怨了这一点。然后我将它们转换为XADataSource但它仍然失败,因为写入过程(进入MySQL数据库)包含导致隐式提交的create table语句,而你不能在分布式事务中这样做。
我最终得到的解决方案是将传输方法标记为TransactionAttributeType.NOT_SUPPORTED,然后将读取和写入过程放入由父传输方法调用的自己的方法中。
我的问题是:读取和写入方法是在自己的事务中运行还是NOT_SUPPORTED传播给它们?我的猜测是他们有一个隐含的TransactionAttributeType.REQUIRED,所以会开始他们自己的交易,但我不确定,我认为他们在交易中运行很重要。
这是解决这个问题的最佳方法吗?
答案 0 :(得分:1)
分离读取和写入步骤的更大问题是,如果某个其他线程/进程正在改变从读取步骤获得的数据,是否仍应执行写入步骤。换句话说,您确定读写不应该在同一个事务中吗?也许您有一些外部保证,不会出现单独写入数据的问题。
如何调用读写方法?如果它们被称为本地方法,则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方法运行时暂时挂起。