2013-09-12 3 views
2

я изменил свое приложение для работы с Hibernate EntityManager (от Hibernate сессии),
, но у меня есть некоторые старые коды (я не могу изменить эти коды), которые используются в ниже код:Hibernate EntityManager с getSessionFactoryGetCurrentSession()

getSessionFactory().getCurrentSession().

я есть боб SessionFactory поэтому код выше должен работать, но во время исполнения у меня есть
HibernateException("No Session found for current thread"), даже выше код был выполнен в блоке транзакции.

FYI: Я проверил ресурсы транзакций (в режиме отладки) и с ключом EntityManagerFactory, сессия существует, но не под SessionFactory ключа

+0

пожалуйста, напишите код, связанный с управлением транзакциями (часть контекста XML-приложений, примеры кода с @Transactional annotation или xml-объявление транзакционных методов, если вы используете это) – ben75

+0

Я написал в своем вопросе ** даже код, приведенный выше, был выполнен в транзакционном блоке. ** Таким образом, исключение происходит даже с кодом @Transactional annotation или xml-декларированием транзакционных методов – nir

+0

Да ... но вы проверили, что транзакция действительно началась?- вы можете проверить это, просто включив соответствующий логгер (возможно, что @Transactional ничего не делает, если что-то плохо конфигурирует где-то в другом месте.) – ben75

ответ

8

Я предлагаю вам сделать это (кажется Hacky, но с унаследованным кодом, это иногда требуется)

Это решение использует весну TransactionSynchronizationManager и Hibernate 4, но может быть адаптирована к другой версии Hibernate.

Вот эта идея: использование пользовательской реализации CurrentSessionContext в вашем SessionFactoryBean, и эта пользовательская реализация будет искать в транзакционных ресурсах для менеджера сущностей текущей транзакции; когда он найден, просто вызывает код, отправленный IIla для получения сеанса спящего режима.

Чтобы сделать это:

1.Define Свойство hibernate.current_session_context_class в hibernateProperties:

<bean id="sessionFactory" 
     class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"> 
    ... 
    <property name="hibernateProperties"> 
     <props> 
      ... 
      <prop key="hibernate.current_session_context_class"> 
       com.example.jpa.HibernateSessionInEntityManager 
      </prop> 
     </props> 
    </property> 
</bean> 

<!-- for completness : here are the other relevant beans --> 

<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> 
    <property name="jpaVendorAdapter"> 
     <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/> 
    </property> 
    <property name="dataSource" ref="dataSource"/> 
    <property name="packagesToScan" value="com.example.jpa.validator"/> 
</bean> 

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

2.Implement ваш собственный CurrentSessionContext: HibernateSessionInEntityManager.java

import org.hibernate.HibernateException; 
import org.hibernate.Session; 
import org.hibernate.SessionFactory; 
import org.hibernate.context.spi.CurrentSessionContext; 
import org.hibernate.ejb.EntityManagerImpl; 
import org.hibernate.engine.spi.SessionFactoryImplementor; 
import org.springframework.orm.jpa.EntityManagerHolder; 
import org.springframework.transaction.support.TransactionSynchronizationManager; 

import javax.persistence.EntityManager; 
import java.util.Map; 

public class HibernateSessionInEntityManager implements CurrentSessionContext { 

    public HibernateSessionInEntityManager() { 
    } 

    public HibernateSessionInEntityManager(SessionFactory sessionFactory) { 
    } 

    public HibernateSessionInEntityManager(SessionFactoryImplementor sessionFactory) { 
    } 

    public Session currentSession() throws HibernateException { 
     Map<Object, Object> resourceMap = TransactionSynchronizationManager.getResourceMap(); 
     for(Object v:resourceMap.values()){ 
      if(v instanceof EntityManagerHolder){ 
       return getSessionFromEM(((EntityManagerHolder)v).getEntityManager()); 
      } 
     } 
     return null; 
    } 

    private static Session getSessionFromEM(final EntityManager entityManager) 
    { 
     final Object emDelegate = entityManager.getDelegate(); 
     if (emDelegate instanceof EntityManagerImpl) 
     { 
      return ((EntityManagerImpl) emDelegate).getSession(); 
     } 
     else if (emDelegate instanceof Session) 
     { 
      return (Session) emDelegate; 
     } 
     throw new HibernateException("No Session found"); 
    } 
} 

Примечание все эти конструкторы: Hibernat e-4 нуждается в одном с SessionFactoryImplementor, и я думаю, что Hibernate-3 нуждается в одном с SessionFactory. (Конструктор не-арг, вероятно, не требуется)

3.Here простой тест, чтобы проверить, что он работает

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration(locations = { "classpath:ApplicationContext.xml" }) 
public class HibernateSessionInEntityManagerTest { 

    @Autowired 
    public SessionFactory sessionFactory; 

    @Test 
    @Transactional 
    public void testGetHibernateSession(){ 
     Session session = sessionFactory.getCurrentSession(); 
     Assert.assertNotNull(session); 
    } 
} 

Я надеюсь, что это поможет. (BTW: хороший вопрос)

Важное замечание: если у вас есть несколько EntityManagerFactoryBean, вы можете выбрать хороший, изучая транзакционные ресурсы. (То есть, например, посмотреть на persistenceUnitName присоединенной EntityManagerFactory)

+0

Спасибо за ваш ответ! – nir

+0

@nir вы попробовали? это работает для вас? – ben75

+0

Я пробовал, и эта работа замечательная !!! – nir

0

Шортер реализация метода «getSessionFromEM»:

private static Session getSessionFromEM(final EntityManager entityManager){ 
    return entityManager.unwrap(Session.class); 
} 
Смежные вопросы