Использование TransactionProxyFactoryBean в спящем режиме 4/spring 4?

У меня есть старый проект, который я пытаюсь обновить до spring 4/hibernate 4.

Мы используем этот подход к настройке наших транзакций.

То есть в XML мы определяем диспетчер транзакций, например:

<bean id="abstractTransactionProxy"
abstract="true"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager" ref="hibernateTransactionManager"/>
<property name="transactionAttributes">
    <props>
        <prop key="create*">PROPAGATION_REQUIRED</prop>
        <prop key="update*">PROPAGATION_REQUIRED</prop>
        <prop key="delete*">PROPAGATION_REQUIRED</prop>
        <prop key="*">PROPAGATION_SUPPORTS,readOnly</prop>
    </props>
</property>

и

<bean id="MySessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
    <property name="dataSource"     ref="myDataSource" />
    <property name="configLocation" value="WEB-INF/hibernate.cfg.xml" />
</bean>

а затем каждый из наших сервисов beans определяется следующим образом:

<bean id="customerService" parent="abstractTransactionProxy">
    <property name="target" ref="customerTarget"/>
    <property name="personDAO" ref="personDAO" />
</bean>

а DAO определяются следующим образом:

    <alias name="personDaoImpl" alias="personDAO"/>
<bean id="personDaoImpl" 
    class="com.foo.bar.hibernate.PersonDaoImpl">
    <property name="sessionFactory" ref="MySessionFactory" />
</bean>

PersonDaoImpl (и все другие DAO) имеют много методов, которые выглядят так (все DAO расширяют HibernateDaoSupport):

    public List<Person> getPersonByCriteria(final String criteria) {
    List<Person> results = 
        (List<Person>) this.getHibernateTemplate().executeFind(new HibernateCallback<List<Person>>(){

        public List<Person> doInHibernate(Session session) throws HibernateException, SQLException {
            List<Person> results = (List<Person>) session.createQuery(MYSQLHERE).setString("criteria", criteria).list();
            return results;
        }
    });
    return results;
}

Теперь проблема, с которой я сталкиваюсь в данный момент, избавляется от нашей зависимости от расширения наших DAO от HibernateDaoSupport и, в добавлении, от использования его вспомогательного объекта HibernateTemplate.

Вот шаги, которые я сделал:

  • Просто удалите их из методов DAO - не расширяйте HibernateDaoSupport, удалите обратный вызов HibernateTemplate. Это выглядит так:

        public List<Person> getPersonByCriteria(final String criteria) {
            List<Person> results = (List<Person>) getSessionFactory().getCurrentSession().createQuery(MYSQLHERE).setString("criteria", criteria).list();
    
            return results;
        }
    

Конечно, это дает мне ошибки во время компиляции, потому что "getSessionFactory" был частью базового класса "HibernateDaoSupport", который я только что удалил.

  • Итак, я реализовал класс "MyHibernateDaoSupport", и вместо этого расширил его DAO. Это выглядит так:

    public class MyHibernateDaoSupport {
    
        private SessionFactory sessionFactory;
        protected Session session;
        protected static Logger logger = Logger.getLogger(MyHibernateDaoSupport.class);
    
        public void setSessionFactory(SessionFactory sessionFactory) {
            this.sessionFactory = sessionFactory;
            session = this.sessionFactory.getCurrentSession();
        }
    
        public SessionFactory getSessionFactory() {
        return this.sessionFactory;
        }
    
        public Session getHibernateTemplate() {
            session = this.sessionFactory.getCurrentSession();
            return session;
        }
    
        public MyHibernateDaoSupport() {
        }
    

    }

Теперь я могу создавать, развертывать и запускать, и я нахожу это сообщение об ошибке:

No session available in this thread

Как я могу сделать эту работу?

  • Проще говоря, что такое "hibernateCallback()", и на самом деле он делает свой собственный класс?

  • Как я могу сделать мои транзакции проекта по-прежнему, не используя классы HibernateDaoSupport и HibernateTemplate?

Я пробовал пометить свой "CustomerService" (объект бизнес-логики, который вызывает "PersonDao" ) с помощью @transactional, но (A) я вижу ту же ошибку независимо и (B), я действительно предпочел бы иметь возможность делать это программно, чтобы уменьшить масштаб изменений в том, как работает код сейчас. Я также попытался разместить транзакции на уровне DAO и встретил ту же проблему.

Извините, если это слишком подробно для формата.

Ответ 1

  • Вам нужно ввести SessionFactory в свои классы DAO:

    @Repository
    public class PersonDAOImpl implements PersonDAO {
    
        @Autowired
        private SessionFactory sessionFactory;
    
        public List<Person> getPersonByCriteria(final String criteria) {
            List<Person> results = (List<Person>) getSessionFactory().getCurrentSession().createQuery(MYSQLHERE).setString("criteria", criteria).list();
            return results;
        }
    }
    
  • Добавьте @Transactional к вашим методам обслуживания

  • Добавить HibernateTransactionManager

  • Инструкции Spring использовать декларативные транзакции:

    <tx:annotation-driven transaction-manager="transactionManager"/>
    
  • Убедитесь, что вы используете LocalSessionFactoryBean для создания SessionFactory

Здесь приводится подробный шаг за шагом учебник по настройке Spring и Hibernate 4