在我正在处理的应用程序中,我们需要在用户进入“编辑页面”之前启动事务(以锁定当前编辑的数据库记录)并在他单击按钮或离开页面时结束事务。
为此,我使用@Stateful
管理事务的 EJB bean 和@ViewScoped
在“编辑页面”上使用的 CDI bean。
当然,用户可以在编辑页面上执行许多操作,这些操作应该在同一个事务中调用。这是示例代码:
@Stateful
@LocalBean
@TransactionManagement(TransactionManagementType.BEAN)
public class TransactionService {
@Resource
private UserTransaction utx;
@PostConstruct
private void postConstruct() {
System.out.println(this + " postConstruct");
}
@PreDestroy
private void preDestroy() {
System.out.println(this + " preDestroy");
utx.rollback();
}
public void start() {
utx.begin();
//lock db records with select ... for update
}
@Remove
public void commit() {
utx.commit();
}
@Remove
public void rollback() {
utx.rollback();
}
}
@Named
@ViewScoped
public class TestBean implements Serializable {
@Inject
private TransactionService ts;
@Inject
private SqlService sql; //stateless session bean
@PostConstruct
private void postConstruct() {
System.out.println(this + " postConstruct");
ts.start();
}
@PreDestroy
private void preDestroy() {
System.out.println(this + " preDestroy");
ts.rollback();
}
public void methodA() {
//do some db operation
sql.insert();
}
public void methodB() {
//do some db operation
sql.update();
}
public String save() {
ts.commit();
return "otherView";
}
public String cancel() {
ts.rollback();
return "otherView";
}
}
理论上它看起来不错,但我们有一些问题:
- 我们能否确定所有操作都在同一个事务中调用?
- 如果用户通过输入地址栏或 http 会话超时关闭选项卡/浏览器/转到另一个 URL 怎么办。我们如何检测它并回滚事务?起初我们尝试过,
@PreDestroy
但看起来它从未被调用过!
我们使用 Java EE 6 技术:JSF、EJB。在 Glassfish 3.1.2 Web 配置文件上部署。我们使用 MyBatis 代替 JPA。感谢帮助