Java 交易不';t回滚

Java 交易不';t回滚,java,ejb,jboss7.x,rollback,Java,Ejb,Jboss7.x,Rollback,我调用了两种方法,第一种方法更新一个表,第二种方法在另一个表中插入一条记录。当第二个事务失败时,EJB不会回滚第一个事务 这是我的后盾: @ManagedBean @ViewScoped public class TransactionTestBean implements Serializable { @EJB private TransactionTestService service; public String loadView() { ret

我调用了两种方法,第一种方法更新一个表,第二种方法在另一个表中插入一条记录。当第二个事务失败时,
EJB
不会回滚第一个事务

这是我的后盾:

@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) {
        }
    }
}
@Local
public interface TransactionTestService {

    void updateTest() throws CustomException;
}
@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());
        }
    }
}
@ApplicationException(rollback = true)
public class CustomException extends Exception {

    public CustomException(Throwable cause, String message) {
        super(message, cause);
    }
}
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) {
                }
            }
        }
    }
}
public interface TransactionTestDAO {

    void updateRecord(Connection connection) throws CustomException;
}
EJB接口:

@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) {
        }
    }
}
@Local
public interface TransactionTestService {

    void updateTest() throws CustomException;
}
@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());
        }
    }
}
@ApplicationException(rollback = true)
public class CustomException extends Exception {

    public CustomException(Throwable cause, String message) {
        super(message, cause);
    }
}
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) {
                }
            }
        }
    }
}
public interface TransactionTestDAO {

    void updateRecord(Connection connection) throws CustomException;
}
EJB类:

@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) {
        }
    }
}
@Local
public interface TransactionTestService {

    void updateTest() throws CustomException;
}
@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());
        }
    }
}
@ApplicationException(rollback = true)
public class CustomException extends Exception {

    public CustomException(Throwable cause, String message) {
        super(message, cause);
    }
}
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) {
                }
            }
        }
    }
}
public interface TransactionTestDAO {

    void updateRecord(Connection connection) throws CustomException;
}
和我的自定义异常:

@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) {
        }
    }
}
@Local
public interface TransactionTestService {

    void updateTest() throws CustomException;
}
@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());
        }
    }
}
@ApplicationException(rollback = true)
public class CustomException extends Exception {

    public CustomException(Throwable cause, String message) {
        super(message, cause);
    }
}
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) {
                }
            }
        }
    }
}
public interface TransactionTestDAO {

    void updateRecord(Connection connection) throws CustomException;
}
编辑:

@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) {
        }
    }
}
@Local
public interface TransactionTestService {

    void updateTest() throws CustomException;
}
@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());
        }
    }
}
@ApplicationException(rollback = true)
public class CustomException extends Exception {

    public CustomException(Throwable cause, String message) {
        super(message, cause);
    }
}
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) {
                }
            }
        }
    }
}
public interface TransactionTestDAO {

    void updateRecord(Connection connection) throws CustomException;
}
添加了DAO类:

@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) {
        }
    }
}
@Local
public interface TransactionTestService {

    void updateTest() throws CustomException;
}
@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());
        }
    }
}
@ApplicationException(rollback = true)
public class CustomException extends Exception {

    public CustomException(Throwable cause, String message) {
        super(message, cause);
    }
}
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) {
                }
            }
        }
    }
}
public interface TransactionTestDAO {

    void updateRecord(Connection connection) throws CustomException;
}
和DAO接口:

@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) {
        }
    }
}
@Local
public interface TransactionTestService {

    void updateTest() throws CustomException;
}
@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());
        }
    }
}
@ApplicationException(rollback = true)
public class CustomException extends Exception {

    public CustomException(Throwable cause, String message) {
        super(message, cause);
    }
}
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) {
                }
            }
        }
    }
}
public interface TransactionTestDAO {

    void updateRecord(Connection connection) throws CustomException;
}

我几乎可以肯定,您的问题是由手动创建DAO造成的,因为您使用
new
关键字:

@PostConstruct
public void init() {
    dao = new XxxxDAOImpl();
}
当您执行这些操作时,ejb容器无法管理对象生命周期和事务边界。您应该让容器来创建和管理dao(并为您注入它)。这样,您将在所有EJB方法中获得适当的事务传播,从而解决您的问题

要实现这一点,您只需使用
@Stateless
注释DAO类,并使用以下内容将其注入
TransactionTestServiceImpl
类中:

@EJB
private XxxxDAO dao;
当然,然后删除initdestroy方法

个人建议 为什么要使用一个单独的、附加的dao层呢?在JavaEE世界中,最方便的选择是只使用
EntityManager
。实体管理器在大多数用例中很好地扮演dao的角色。虽然您的示例中的JDBC已经足够好了,但JPA(IMHO)更简单

更新 这是一个错误的猜测,请查看我的更新。

请尝试此选项

@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();
        }
    }
}

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

上面的代码片段将只与BMT一起使用。使用CMT时,您应该得到如下错误:

Caused by: java.sql.SQLException: You cannot set autocommit during a managed transaction!
但是,我的错误最终变成了好事,因为当你写信的时候

这很有效(…)

然后我们找到了答案:您认为您的ejbbean将CMT与JTA一起使用,但是由于一些错误,它没有使用


在下面的评论中,我也建议您使用JPA,但在这个简单的例子中,JDBC已经足够好了。CMT事务也可以与JDBC一起自由使用

在这里,数据源的类型也无关紧要。CMT可以自由地与非XA数据源(也称为本地数据源)和XA数据源一起使用

更新2 User@Gas解决了中的问题。他真了不起


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

我认为问题在于连接/数据源根本不是当前事务的一部分。与其注入JDBC连接,我建议:

  • 为JTA类型的
    persistence.xml
    中定义的数据创建PersistenceUnit
  • 在EJB中注入相应的
    EntityManager
  • 从步骤2中插入的
    EntityManager
    打开
    连接。没有标准的方法,请检查

  • 本例中的关键问题是某些JBoss版本中数据源的错误默认值。原始代码很好,在其他应用服务器(WebSphereAppServer和轻量级WebSphereLiberty)中正常工作


    在JBoss中创建的数据源不是JTA-在管理控制台中,
    使用JTA
    设置未选中,在xml相关设置中为
    请为您的数据源提供JBoss配置DAO实现是什么?如果您在DAO中只使用普通JDBC,那么就没有第二个事务。在
    单个
    事务中调用了
    updateRecord()
    saveRecord()
    两种方法,该事务应在异常时回滚。我添加了DAOJohn,您能提供堆栈跟踪吗?您如何知道有两个事务?正如我所写的,您应该只有一个事务。这两种方法都是在一个事务中调用的。这不一定是真的。他的连接来自数据源,因此由容器管理。您不知道dao实现,因此不知道使用
    new
    创建是否有任何影响。@当然,我可能错了,我不知道dao impl(以及事务类型)。但是您的假设:它是由容器管理的,这是完全错误的。作者可能正在使用
    transaction type=“RESOURCE\u LOCAL”
    。然后在每个DAO方法中,他可能正在“手动”开始一个新的事务。这很好地解释了他的问题。再说一遍,你太快了:-)-
    transaction type=“RESOURCE\u LOCAL”
    假设使用JPA和
    persistence.xml
    。作者并没有使用它,因为他正在传递JPA没有使用的
    连接
    对象。在CMT管理的EJB中,从数据源获得的连接总是使用JTA。在CMTBean中,您不能手动启动连接上的新事务。所以,让我们停止争论我们看不见的事情。@GrzesiekD。这一更改加上xa数据源解决了我的问题这很好,但我需要在standalone.xml中而不是在java中管理这一点你是说“manage
    autocommit
    ”?如果是这样,那么在
    standalone.xml
    文件中尝试将其设置为
    false
    ,好吗?是的,我在standalone.xml中编辑它,但我不想通过代码管理提交和回滚,我希望EJB这样做automatically@JohnB为什么要玩自动提交?您不需要像下面这样设置任何事务逻辑
    connection.setAutoCommit()