Через EntityManager.flush () фиксирует транзакцию в веб-службе Java

редактировать: спасибо всем за ваши ответы, но проблема заключалась в моей конфигурации источника данных, которая фактически находилась в режиме автоматической фиксации. См.мой ответ ниже для сведения.

оба Javadoc EntityManager.flush () метод и поиск его в Google, похоже, предполагают, что flush метод только отправляет отложенные операторы в базу данных и не фиксирует транзакцию. Но простой тестовый веб-сервис, который я создал (в Java 7, Oracle 11gR2, JBoss 7.1 и веб-сервис упакован как файл jar), похоже, указывает на иное:

это сценарий создания таблицы:

CREATE TABLE test(
    id INTEGER NOT NULL,
    name VARCHAR2(20), 
    CONSTRAINT test_pk PRIMARY KEY ("ID")
);
CREATE SEQUENCE test_seq;

это соответствующая сущность:

@Entity @Table(name = "TEST")
public class Test implements Serializable {

    private static final long serialVersionUID = 9192814682033048425L;

    @Id @Column(name = "ID")
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "TEST_SEQ")
    @SequenceGenerator(name="TEST_SEQ",sequenceName="TEST_SEQ", allocationSize = 1)
    private Integer id;

    @Column(name = "NAME")
    private String name;

    // Getters and setters...
}

и тест web-сервиса:

@Stateless @WebService(serviceName = "TestService")
@TransactionManagement(TransactionManagementType.CONTAINER)
public class TestServiceBean implements TestService {

    @PersistenceContext
    private EntityManager entityManager;

    @Override
    public void createTest(String name) {
        Test test = new Test();
        test.setName(name);
        entityManager.persist(test);
        entityManager.flush();

        throw new RuntimeException();
    }
}

мое понимание таково:

  • когда createTest вызывается метод, приложение запускает новую транзакцию
  • на persist() метод генерирует инструкцию INSERT для отправки в базу данных
  • на flush() метод отправляет инструкцию INSERT в базу данных но не совершает транзакцию!
  • исключение RuntimeException вызывает откат транзакции.

но, очевидно, Мое понимание неверно: каждый раз, когда я запускаю метод веб-службы, я получаю одну новую строку в таблице. Кроме того, шаг в этот метод с отладчиком показывает, что строка вставлена при flush() вызывается метод (я могу "видеть" строку из другого сеанса БД с помощью SQL Developer).

может кто-нибудь объяснить это поведение?

3 ответов


Кажется, что нет ничего плохого с flush() в конце концов. Проблема заключалась в том, что я неправильно настроил источник данных в JBoss. Урок здесь заключается в том, что если вы хотите использовать управляемые транзакции контейнера в EBJs, вам нужно:

  • в JBoss, проверьте использовать JTA? флажок в конфигурации источника данных.
  • в Weblogic проверьте Поддерживает Глобальные Транзакции флажок на вкладке транзакции источника данных конфигурация.

кроме того, и для устранения любой путаницы управление транзакциями в моем коде является правильным. Бросок RuntimeException тут откат исключения. Почему так? Ну,из Java EE 6 учебник у нас есть:

Если возникает системное исключение, контейнер автоматически откатывает транзакцию.

но что такое системное исключение? Учебник, похоже, не трогает на эту тему дальше, так что давайте искать EJB spec. На странице 382 мы имеем:

системное исключение-это исключение, которое является java.РМО.RemoteException (или один из его суб- classes) или исключение RuntimeException, которое не является исключением приложения.

хорошо, может быть, исключение RuntimeException является исключением приложения? Нет, это не так, потому что на странице 380 мы имеем следующее:

исключения приложений, которые проверенные исключения могут быть определены как таковые, будучи перечисленными в предложениях throws методов бизнес-интерфейса компонента, представления без интерфейса, домашнего интерфейса, интерфейса компонента и конечной точки веб-службы. Исключение приложения, которое является непроверенным исключением, определяется как исключение приложения путем аннотирования его аннотацией метаданных ApplicationException или его обозначения в дескрипторе развертывания элементом application-exception.

Итак, потому что я не сделал ничего из перечисленного выше, исключение, которое я бросаю в свой код, действительно является системным исключением и действительно откатывает транзакцию если вы настроили источник данных для использования JTA.


для отката транзакции в методе EJB вы должны вызвать setRollbackOnly() метод, в противном случае выход из метода, даже бросая исключение, вызывает транзакцию. Для более подробного объяснения вы можете обратиться к учебник Java EE 6.


цитирование JSR-317 спецификации JPA страница 23:

во время выполнения исключения методов доступа к свойству вызовет текущей транзакции для отката. Исключения, создаваемые такими методами при использовании среды выполнения персистентности для загрузки или хранения персистентного состояния, приводят к тому, что среда выполнения персистентности помечает текущую транзакцию для отката и создает исключение PersistenceException, которое обертывает исключение приложения.

в К RuntimeException вы бросаете должен быть выброшен из сущности сеттер в зернах не из EJB.

Я уверен, что вы не получите упаковку PersistenceException - который указывает метка для отката вместо тебя к RuntimeException, который вас бросил.

попробуйте бросить RollbackException вместо RuntimeException из EJB!!!

или бросить к RuntimeException в сущности сеттеров в зернах как спецификация говорит.