#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. И это хорошая практика.