Java EE 6 - Pessimistic Locking - ViewScoped bean

2019-08-22 23:02发布

问题:

In application I'm working on we need to start transaction before user enters 'edit page' (to lock DB records currently edited) and end it when he clicks the button or left the page.

For this purpose I use @Stateful EJB bean which manages the transaction and CDI @ViewScoped bean which is used on the 'edit page'.

Of course user can take many actions on edit page, which are supposed to be invoked within the same transaction. Here's sample code:

@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";
  }
}

In theory it looks fine, but we have some questions:

  1. Can we be sure that all operations are invoked in the same transaction?
  2. What if user closes tab/browser/goes to another URL by typing in address bar or http session times out. How can we detect it and rollback the transaction? At first we tried with @PreDestroy but it looks like it's never called!

We use Java EE 6 technologies: JSF, EJB. Deploy on Glassfish 3.1.2 Web Profile. We use MyBatis instead JPA. Thanks for help

回答1:

IMHO it's very bad approach. you lock your table and wait hoping that user does something. it may take minutes. all other users will have to wait for this one - in most applications it's unacceptable. you shouldn't span transaction between between multiple http requests.

however, if you insist, rollback must not depends on some external events. simply set a transaction timeout