EntityManager.flush()在Java Web服务中提交事务

mav*_*ato 7 java oracle jpa jax-ws ejb-3.0

编辑:感谢大家的答案,但问题出在我的数据源配置,实际上是在自动提交模式.请参阅下面答案了解详情.

EntityManager.flush()方法的Javadoc 和在Google中搜索它似乎都暗示该flush方法只将挂起的语句发送到数据库并且不提交事务.但是我创建的一个简单的测试Web服务(在Java 7中,Oracle 11gR2,JBoss 7.1和Web服务打包为jar文件)似乎表示不同:

这是表创建脚本:

CREATE TABLE test(
    id INTEGER NOT NULL,
    name VARCHAR2(20), 
    CONSTRAINT test_pk PRIMARY KEY ("ID")
);
CREATE SEQUENCE test_seq;
Run Code Online (Sandbox Code Playgroud)

这是相应的实体:

@Entity @Table(name = "TEST")
public class Test implements Serializable {

    private static final long serialVersionUID = 9192814682033048425L;

    @Id @Column(name = "ID")
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "TEST_SEQ")
    @SequenceGenerator(name="TEST_SEQ",sequenceName="TEST_SEQ", allocationSize = 1)
    private Integer id;

    @Column(name = "NAME")
    private String name;

    // Getters and setters...
}
Run Code Online (Sandbox Code Playgroud)

和测试Web服务:

@Stateless @WebService(serviceName = "TestService")
@TransactionManagement(TransactionManagementType.CONTAINER)
public class TestServiceBean implements TestService {

    @PersistenceContext
    private EntityManager entityManager;

    @Override
    public void createTest(String name) {
        Test test = new Test();
        test.setName(name);
        entityManager.persist(test);
        entityManager.flush();

        throw new RuntimeException();
    }
}
Run Code Online (Sandbox Code Playgroud)

我的理解是:

  • createTest调用该方法时,应用程序将启动一个新事务
  • persist()方法生成要发送到数据库的INSERT语句
  • flush()方法将INSERT语句发送到数据库,但不提交事务!
  • RuntimeException导致事务回滚.

但显然我的理解是错误的:每次运行Web服务方法时,我都会在表中获得一个新行.此外,使用调试器进入此方法会显示在flush()调用方法时插入行(我可以使用SQL Developer"查看"来自另一个db会话的行).

有人可以解释一下这种行为吗?

mav*_*ato 7

flush()毕竟似乎没有任何问题.问题是我没有在JBoss中正确设置数据源.这里的教训是,如果要在EBJ中使用容器管理的事务,则需要:

  • 在JBoss中,检查使用JTA?数据源配置中的复选框.
  • 在Weblogic中,选中数据源配置的"事务"选项卡中的" 支持全局事务"复选框.

此外,为了清除任何混淆,我的代码中的事务管理是正确的.抛出一个RuntimeException 回滚异常.这是为什么?那么,从Java EE 6教程我们得到:

如果抛出系统异常,容器将自动回滚事务.

但什么是系统异常?该教程似乎没有进一步涉及该主题,因此让我们搜索EJB规范.在页面382中,我们有:

系统异常是一个异常,它是java.rmi.RemoteException(或其子类之一)或RuntimeException,它不是应用程序异常.

好的,那么RuntimeException可能是一个应用程序异常呢?不,不是,因为在第380页我们有:

检查异常的应用程序异常可以通过在bean的业务接口,无接口视图,home接口,组件接口和Web服务端点的方法的throws子句中列出来定义.作为未经检查的异常的应用程序异常通过使用ApplicationException元数据批注对其进行批注或使用application-exception元素在部署描述符中表示它来定义为应用程序异常.

因此,因为我没有执行上面列出的任何事情,所以我在代码中抛出的异常确实是系统异常,如果您已设置数据源以使用JTA,则确实会回滚事务.