Java EE 6 — пессимистическая блокировка — bean-компонент ViewScoped + bean-компонент с отслеживанием состояния с UserTransaction, PreDestroy и другими проблемами

В приложении, над которым я работаю, нам нужно начать транзакцию до того, как пользователь войдет на «страницу редактирования» (чтобы заблокировать редактируемые записи БД) и завершить ее, когда он нажмет кнопку или покинет страницу.

Для этой цели я использую компонент EJB @Stateful, который управляет транзакцией, и компонент CDI @ViewScoped, который используется на «странице редактирования».

Конечно, пользователь может выполнять множество действий на странице редактирования, которые должны выполняться в рамках одной и той же транзакции. Вот пример кода:

@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. Что, если пользователь закроет вкладку/браузер/перейдет к другому URL-адресу, набрав адресную строку или время сеанса HTTP истекло. Как мы можем обнаружить это и откатить транзакцию? Сначала мы пытались использовать @PreDestroy, но, похоже, он так и не был вызван!

Мы используем технологии Java EE 6: JSF, EJB. Развертывание в веб-профиле Glassfish 3.1.2. Мы используем MyBatis вместо JPA. Спасибо за помощь


person karolkpl    schedule 29.09.2012    source источник
comment
CDI не имеет компонента View Scoped. Вероятно, вы используете управляемый компонент JSF. Надеюсь, вы не смешиваете аннотации между двумя типами bean-компонентов, потому что это нарушит область действия bean-компонента.   -  person perissf    schedule 01.10.2012
comment
Я использую швы версии 3.0, в которой реализована CDI viewscoped.   -  person karolkpl    schedule 02.10.2012


Ответы (1)


ИМХО это очень плохой подход. вы блокируете свой стол и ждете, надеясь, что пользователь что-то сделает. это может занять несколько минут. всем остальным пользователям придется ждать этого — в большинстве приложений это неприемлемо. вы не должны распределять транзакцию между несколькими HTTP-запросами.

однако, если вы настаиваете, откат не должен зависеть от каких-то внешних событий. просто установите время ожидания транзакции

person piotrek    schedule 29.09.2012
comment
В нашей ситуации это желательное поведение. Пользовательское редактирование может длиться даже 1 час, и мы должны быть уверены, что БД не изменилась за это время, чтобы он мог безопасно сохранить свою работу. Есть несколько приложений, использующих одну и ту же базу данных, мы должны запретить другим редактировать одни и те же данные. И мы не блокируем всю таблицу, а только одну строку. - person karolkpl; 29.09.2012