事务不回滚

Joh*_*tts 8 java ejb rollback jboss7.x

我调用两个方法,第一个更新表,下一个在另一个表中插入记录.当第二个事务失败时,EJB不执行第一个事务的回滚.

这是我的支持bean:

@ManagedBean
@ViewScoped
public class TransactionTestBean implements Serializable {

    @EJB
    private TransactionTestService service;

    public String loadView() {
        return "/test/transactionTest";
    }

    public void test() {
        try {
            service.updateTest();
        } catch (Exception e) {
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

EJB接口:

@Local
public interface TransactionTestService {

    void updateTest() throws CustomException;
}
Run Code Online (Sandbox Code Playgroud)

EJB类:

@Stateless
@TransactionManagement
public class TransactionTestServiceImpl implements TransactionTestService {

    @Resource(mappedName = "java:jboss/datasources/xxxxxDS", shareable = true)
    public DataSource dataSource;

    private TransactionTestDAO dao;

    @PostConstruct
    public void init() {
        dao = new TransactionTestDAOImpl();
    }

    @PreDestroy
    public void destroy() {
        dao = null;
    }

    @Override
    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    public void updateTest() throws CustomException {

        try (Connection connection = dataSource.getConnection()) {
            dao.updateRecord(connection);
            // dao.saveRecord(connection);
        } catch (SQLException exception) {
            throw new CustomException(exception, exception.getMessage());
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我的自定义异常:

@ApplicationException(rollback = true)
public class CustomException extends Exception {

    public CustomException(Throwable cause, String message) {
        super(message, cause);
    }
}
Run Code Online (Sandbox Code Playgroud)

编辑:

添加了DAO类:

public class TransactionTestDAOImpl implements TransactionTestDAO {

    @Override
    public void updateRecord(Connection connection) throws CustomException {

        PreparedStatement preparedStatement = null;

        try {
            preparedStatement = connection.prepareStatement("UPDATE table_x SET field_x = ? WHERE field_y = 1");
            preparedStatement.setInt(1, 1);
            preparedStatement.executeUpdate();
        } catch (Exception exception) {
            throw new CustomException(exception, exception.getMessage());
        } finally {
            if (preparedStatement != null) {
                try {
                    preparedStatement.close();
                } catch (SQLException sqlException) {
                }
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

和DAO接口:

public interface TransactionTestDAO {

    void updateRecord(Connection connection) throws CustomException;
}
Run Code Online (Sandbox Code Playgroud)

Gas*_*Gas 8

这种情况下的关键问题是某些JBoss版本中数据源的默认值很差.原始代码很好,并且在其他应用程序服务器(WebSphere App Server和轻量级WebSphere Liberty)中正常工作.

在JBoss中创建的数据源不是JTA - 在管理控制台中,Use JTA设置未选中,并且在xml相关设置中 <datasource jta="false" ....更改此设置以true解决问题.(JohnB,你写的定义xa-datasource修复了,但由于我没有看到你的原始xml与数据源定义,我相信在更改数据源时你也改变了这个有缺陷的jta ="false"设置).它也适用于非xa数据源,正如Grzesiek测试的那样.

这是一个非常糟糕的默认值,因为它导致事务不由容器管理,并导致EJB组件中的连接中出现错误的事务行为.

非常感谢Grzesiek D.帮助我诊断这个问题.


G. *_*cki 5

请试试这个

@Override
public void updateTest() throws CustomException {

    Connection connection = dataSource.getConnection();
    try {
        connection.setAutoCommit(false);  // this should be the key

        dao.updateRecord(connection);
        dao.saveRecord(connection);

        connection.commit();

    } catch(Exception ex) {
        connection.rollback();
        throw new CustomException(ex, ex.getMessage());

    } finally {
        if(connection != null) {
            connection.close();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

希望这次会有所帮助.


更新
我上面的回答有一个错误,因为上面的代码假定使用了BMT(Bean管理事务).但正如我们所看到的,您正在使用CMT(容器管理事务).
因为@TransactionManagement相当于@TransactionManagement(TransactionManagementType.CONTAINER)).

以上代码段适用于BMT.使用CMT,您应该得到如下错误:

Caused by: java.sql.SQLException: You cannot set autocommit during a managed transaction!
Run Code Online (Sandbox Code Playgroud)

但是:-)我的错误最终变得很好,因为当你写作时

这非常有效(...)

然后我们找到了答案:您认为您的EJB bean 使用CMT和JTA,但由于某些错误,它没有.


在下面的评论中,我也建议你使用JPA,但在这个简单的例子中,JDBC就足够了.CMT事务也可以与JDBC一起使用.

此外,数据源的类型也无关紧要.CMT可以与非XA数据源(也称为本地数据源)和XA数据源一起使用.


更新2

用户@Gas解决了以下评论中的问题.感谢他.

基本上:原始代码没有任何问题.问题在于数据源的配置(必须启用JTA).因此,通过JBoss管理控制台编辑数据源配置,并设置一个复选框" 使用JTA ".

祝好运.

  • Grzesiek我可能最后的评论,不会打扰你了.既然看起来你已经准备就绪了,请你试试这个http://stackoverflow.com/a/16910818/3701228 - 通过JBoss管理控制台编辑数据源配置并设置一个复选框"使用JTA" - 在xml中它应该是`< datasource jta ="true"..`就像在某些JBoss版本中默认为false. (3认同)