0

在我正在处理的应用程序中,我们需要在用户进入“编辑页面”之前启动事务(以锁定当前编辑的数据库记录)并在他单击按钮或离开页面时结束事务。

为此,我使用@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";
  }
}

理论上它看起来不错,但我们有一些问题:

  1. 我们能否确定所有操作都在同一个事务中调用?
  2. 如果用户通过输入地址栏或 http 会话超时关闭选项卡/浏览器/转到另一个 URL 怎么办。我们如何检测它并回滚事务?起初我们尝试过,@PreDestroy但看起来它从未被调用过!

我们使用 Java EE 6 技术:JSF、EJB。在 Glassfish 3.1.2 Web 配置文件上部署。我们使用 MyBatis 代替 JPA。感谢帮助

4

1 回答 1

0

恕我直言,这是非常糟糕的方法。你锁定你的桌子并等待希望用户做点什么。可能需要几分钟。所有其他用户将不得不等待这个 - 在大多数应用程序中这是不可接受的。你不应该跨越多个http请求之间的事务。

但是,如果您坚持,回滚不能依赖于某些外部事件。只需设置事务超时

于 2012-09-29T18:57:21.863 回答