javax.persistence.TransactionRequiredException Jboss eap

#hibernate #jpa #jboss

#переход в спящий режим #jpa #jboss

Вопрос:

У меня есть класс сущности, который выглядит следующим образом:

 @Entity
@Table(name = "MY_TABLE")
public class MyEntity implements Serializable {

    @Id
    @Column(name = "ID")
    @XmlAttribute
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private String id;

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

    public String getId() {
        return id;
    }

    public void setId(final String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(final String name) {
        this.name= name;
    }
}
  

Этот объект сохраняется этим классом:

 public class MyStarter {

    @PersistenceContext(unitName = "myUnit")
    private EntityManager manager;

    public void insertIntodb() {
        final MyEntity entity = new MyEntity();
        entity.setName("Sample");
        manager.persist(entity);
    }
}
  

Однако всякий раз, когда код сохранения выполняется выше, я получаю исключение:

 javax.persistence.TransactionRequiredException: JBAS011469: Transaction is required to perform this operation (either use a transaction or extended persistence context)
  

Чтобы попытаться это исправить, вот я делаю bcktrack вещей, чтобы проверить, что работает, а что нет:

  • Я проверил, что пользовательское подключение к базе данных имеет разрешения на запись.

  • Я проверил, что собственный запрос, который выбирает данные, действительно может выполняться из JPA и возвращать результаты.

  • Я добавил, тип = javax.persistence .PersistenceContextType .РАСШИРЕНО) до аннотации @PersistanceContext

  • Я обновил persistance.xml файл, содержащий эти строки:

     <jta-data-source>java:jboss/datasources/Mysource</jta-data-source>
    
    <properties>
        <property name="hibernate.dialect"  value="org.hibernate.dialect.SQLServerDialect" />
        <property name="hibernate.max_fetch_depth" value="3" />
        <property name="hibernate.hbm2ddl.auto" value="validate" />
        <property name="hibernate.show_sql" value="true" />
        <property name="hibernate.format_sql" value="true" />
        <property name="hibernate.id.new_generator_mappings" value="true" />
        <property name="hibernate.connection.isolation" value="2" />
        <property name="hibernate.default_schema" value="dbo" />
        <property name="hibernate.transaction.flush_before_completion"
            value="true" />
        <property name="hibernate.transaction.jta.platform"
            value="org.hibernate.service.jta.platform.internal.JBossAppServerJtaPlatform" />
    </properties>
      

Однако я все еще не могу избавиться от проблемы. Что-нибудь очевидное, чего мне здесь не хватает?

Ответ №1:

Используйте @Transactional , как показано ниже

 @Transactional
public class MyStarter {
...
  

ИЛИ как

 @Transactional
public void insertIntodb() {
    final MyEntity entity = new MyEntity();
    entity.setName("Sample");
    manager.persist(entity);
}
  

Это потому, persist() что гарантирует, что он не выполнит INSERT/UPDATE оператор, если он вызывается за пределами границ транзакции.
Следовательно, вам нужна транзакция для сохранения объекта в БД при использовании persist() .

В контекстный файл Spring необходимо добавить приведенный ниже код:

 <beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd 
http://www.springframework.org/schema/tx 
http://www.springframework.org/schema/tx/spring-tx.xsd">

<tx:annotation-driven />
  

Вместо persist() этого вы можете использовать save() . save() Метод может выполняться внутри или вне транзакции. Использование save() не подходит для длительного диалога с расширенным контекстом сеанса / сохранения.

Комментарии:

1. что считается границами транзакций? вне класса сущности?

2. вы имеете в виду @Transactional применяется к классу? Итак, тогда @Transactional применяется к каждому отдельному методу вашего класса MyStarter. И запускается вызов insertIntodb() -> транзакция. Когда insertIntodb() вызывает другой метод, новая транзакция не запускается, поскольку она уже существует. Помните, вы не можете использовать persist() внешнюю транзакцию. Он не будет выполнен.

3. ах, я понимаю. Самое странное, что я видел некоторые проекты, которые явно не используют эту аннотацию и вызывают метод .persist() без проблем.

4. Да, могут быть такие проекты, но управление транзакциями, выполняемое в этих проектах, будет declarative использовать <tx:advice /> конфигурацию тегов и AOP. И это хорошая практика.