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)
这种情况下的关键问题是某些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.帮助我诊断这个问题.
请试试这个
@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 ".
祝好运.
归档时间: |
|
查看次数: |
5504 次 |
最近记录: |