«ни одна сессия или сессия не была закрыта» с JPA 2 и EJB 3.1 - PullRequest
0 голосов
/ 09 марта 2012

У меня есть сессионный компонент без сохранения состояния с этим методом:

@Override
public List<Character> getUserCharacters(int userId) {
    User user = em.find(User.class, userId);
    if(user != null)
        return user.getCharacters();
    else
        return null;
}

, где User class, если определен таким образом:

@Entity
@Table(name="Users")
public class User implements Serializable{

    /**  */

private static final long serialVersionUID = 8119486011976039947L;

@Id
@GeneratedValue(strategy=GenerationType.SEQUENCE)
private int id;

@ManyToMany(fetch=FetchType.EAGER)
private Set<Role> roles;

@OneToMany(mappedBy="owner",fetch=FetchType.LAZY)
private List<com.AandP.game.model.characters.Character> characters;

public User() {
    creationDate = new Date();
    roles = new HashSet<Role>();
    }
}

Но когда я выполняю этот метод (из моего@Named bean) я получаю исключение:

 org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.AandP.game.model.User.characters, no session or session was closed

В соответствии со спецификацией JPA 2.0 сеанс должен оставаться в живых в течение всей транзакции.В этой ситуации транзакция (на мой взгляд) продолжается для всего вызова метода (нет дополнительных атрибутов транзакции для класса или метода).

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

Ответы [ 4 ]

1 голос
/ 09 марта 2012

В соответствии со спецификацией JPA 2.0 сеанс должен оставаться в живых в течение всей транзакции.В этой ситуации транзакция (на мой взгляд) продолжается для всего вызова метода (нет дополнительных атрибутов транзакции для класса или метода).

Это правда, но это не включает сериализацию возвращаемогоobjects.

У меня была такая же проблема при экспорте сессионного компонента в качестве веб-службы.Узнайте больше о проблеме здесь .

Если у вас есть подобное использование, настоятельно рекомендуем вам возвращать простые объекты, а не объекты.Вы можете использовать некоторую инфраструктуру отображения бинов, как мы это делали.Мы использовали Dozer .

0 голосов
/ 25 июля 2013

2013-07-24 19: 47: 07,387 ОШИБКА: - не удалось лениво инициализировать коллекцию роли: com.xxxx.domain.DenialMaster.denialDetails, ни один сеанс или сеанс не был закрыт null

Моя конфигурация:

<tx:annotation-driven transaction-manager="transactionManagerDL" />

<bean id="transactionManagerDL" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="emfDL" />
</bean>

<bean id="emfDL" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="dataSource" ref="dataSourceDL" />
    <property name="jpaVendorAdapter">
        <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
    </property>
    <property name="mappingResources">
        <value>META-INF/orm.xml</value>
    </property>
    <property name="packagesToScan" value="${dl.entity.packages}" />
    <property name="jpaProperties">
        <props>
            <prop key="hibernate.dialect">${catalog.org.hibernate.dialect}</prop>
            <prop key="hibernate.max_fetch_depth">${catalog.org.hibernate.jdbc.max.fetchdepth}</prop>
            <prop key="hibernate.jdbc.fetch_size">${catalog.org.hibernate.jdbc.fetchsize}</prop>
            <prop key="hibernate.jdbc.batch_size">${catalog.org.hibernate.jdbc.batchsize}</prop>
            <prop key="hibernate.show_sql">${catalog.org.hibernate.showsql}</prop>
            <prop key="hibernate.connection.autocommit">${catalog.org.hibernate.connection.autocommit}
            </prop>

        </props>
    </property>
</bean>

РЕШЕНИЕ: В свой класс ServiceImpl добавьте @Transactional (readOnly = true) Пример:

@Override
@Transactional(readOnly = true)
public YourBean findById(long id) throws Exception {
    return yourDAO.findOne(id);
}

и @LazyCollection (LazyCollectionOption.FALSE):

  @OneToMany(fetch=FetchType.LAZY)
  @JoinColumn(name = "idMaster")
  @LazyCollection(LazyCollectionOption.FALSE)
  public List<DenialDetail> getDenialDetails() {
    return denialDetails;
  }
0 голосов
/ 01 мая 2012

pWoz: То, что говорит Божо, правильно.Единственное предостережение, которое я бы добавил, если вы не входите в этот метод через интерфейс (локальный или удаленный), эта аннотация не имеет значения.Если ваш компонент выглядит так:

@Stateless
public class MyUserBean implements UserBeanLocal {
...

  public void doSomeStuffWithUserCharactersById(int id) {
     List<Character>userCharacters = getUserCharacters(id);
  }

  @Override
  @TransactionAttribute(TransactionAttributeType.REQUIRED)
  public List<Character> getUserCharacters(int userId) {
   User user = em.find(User.class, userId);
   if(user != null)
     return user.getCharacters();
    else
     return null;
  }
}

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

0 голосов
/ 09 марта 2012

Вам необходимо указать @TransactionAttribute, чтобы ваш метод был транзакционным. В противном случае транзакция только для чтения и новый базовый сеанс запускаются для каждой операции диспетчера сущностей. Это в сочетании с отложенной коллекцией означает, что при извлечении коллекции исходный сеанс закрывается.

...