Аннотации на основе транзакций не работают - весна 3 - PullRequest
1 голос
/ 19 сентября 2011

Я пытаюсь интегрировать hibernate в мой первый веб-проект Spring с использованием транзакций на основе аннотаций.Однако это не работает, поскольку я заметил, что запрос сохранения не фиксируется.

Это aop-конфигурация:

<context:annotation-config />
<context:component-scan base-package="package.names.project.controller" />
<context:component-scan base-package="package.names.project.model" />
<context:component-scan base-package="package.names.common.util" />

<aop:aspectj-autoproxy>
    <aop:include name="Logger" />
</aop:aspectj-autoproxy>

<!-- the transactional advice (what 'happens'; see the <aop:advisor/> bean 
    below) -->
<tx:advice id="txAdvice" transaction-manager="txManager">
    <!-- the transactional semantics... -->
    <tx:attributes>
        <!-- other methods use the default transaction settings (see below) -->
        <tx:method name="save" read-only="false"/>
        <tx:method name="*" rollback-for="Exception" />
    </tx:attributes>
</tx:advice>

<!-- ensure that the above transactional advice runs for any execution of 
    an operation defined by a service in the service package -->
<aop:config>
    <aop:pointcut id="serviceOperations" expression="execution(* package.names.project.dao.*.*(..))" />
    <aop:advisor advice-ref="txAdvice" pointcut-ref="serviceOperations" />
</aop:config>

<!-- similarly, don't forget the PlatformTransactionManager -->
<bean id="txManager"
    class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource" />
</bean>


<bean id="Logger" class="package.names.common.aop.Logger" />
<tx:annotation-driven transaction-manager="txManager" />

У меня есть следующая конфигурация гибернации:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
    <property name="hibernate.connection.driver_class">org.postgresql.Driver</property>
    <property name="hibernate.connection.url">jdbc:postgresql://localhost:5432/db</property>
    <property name="hibernate.connection.username">user</property>
    <property name="connection.password">pass</property>
    <property name="connection.pool_size">1</property>
    <property name="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</property>
    <property name="show_sql">true</property>
    <property name="hbm2ddl.auto">update</property>
            <property name="connection.autocommit">true</property> 

    <mapping class="package.names.model.Person" />
</session-factory>
</hibernate-configuration>

Объявления bean-компонентов:

<bean id="personDao" class="package.names.project.dao.PersonDaoImpl"></bean>
<bean id="dbService" class="package.names.project.service.DbService"></bean>

Мой сервисный слой выглядит следующим образом

@Service("Service")

public class DbService {
    @Autowired
    private PersonDao personDao;

    public void setPersonDao(PersonDao personDao){
        this.personDao=personDao;
    }

    @Transactional(readOnly = false)
    public void save(Person person){
        personDao.save(person.getName(), person.getAge());
    }
    @Transactional
    public List<String> listPerson(){
        return personDao.listPerson();
    }
}

Изменил sessionFactory в моем дао на автопроводный:

public class PersonDaoImpl implements PersonDao {
    @Autowired
    SessionFactory factory;

    public void setFactory(SessionFactory factory){
        this.factory = factory;
    }

    public Long save(String personName, Integer personAge) {
        Long personId = null;
        Session session = factory.openSession();
        System.out.println( TransactionSynchronizationManager.isActualTransactionActive());
        Person person = new Person();
        person.setName(personName);
        person.setAge(personAge);
        session.saveOrUpdate(person);
        session.close();
        return personId;
    }..

Нет никаких признаков совершения транзакций.(Операторы вставки не отображаются, пока show-sql имеет значение true) Нет сообщений об ошибках, чтобы прояснить это.

(если я добавлю 'session.beginTransaction (). Commit ()' в мою функцию save (),это будет работать. Но это противоречит принципам декларативного управления транзакциями.)

ОБНОВЛЕНИЕ:

Соединение с базой данных работает нормально, как и метод listPerson ().

Я могу подтвердить, что транзакция активна в методе сохранения и что метод сохранения используется с помощью

logger.info(TransactionSynchronizationManager.isActualTransactionActive())

И я вижу, что для автоматической фиксации в журнале задано значение true:

INFO: autocommit mode: true

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

@Transactional(readOnly = false)

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

ОБНОВЛЕНИЕ 2: Исправлена ​​проблема.Это было вызвано открытием нового сеанса каждый раз, когда вызывался метод save.Теперь я просто использую factory.openSession () один раз, после этого я использую factory.getCurrentSession () и не закрываю сессию.

Ответы [ 2 ]

1 голос
/ 19 сентября 2011

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

<context:component-scan base-package="package.names"/>

, либо

<bean class="package.names.PersonDaoImpl"/>

И тогда вам нужно будет получить боб из контейнера либо через автоматическую разводку, либо getBean().

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

1 голос
/ 19 сентября 2011

Поведение по умолчанию для ApplicationContext реализаций с нетерпением предварительно создайте все экземпляры синглтона при запуске.

Поскольку ваше исключение жалуется на готовность к загрузке, попробуйте добавить атрибут lazy-init="true" к своим бобам Spring.

Пример:

<bean id="transactionManager"
    class="org.springframework.orm.hibernate3.HibernateTransactionManager" lazy-init="true">
    <property name="sessionFactory" ref="mySessionFactory" />
</bean>

Подробнее о Ленивая инициализация см. .

EDIT

Также, чтобы решить проблему с фиксацией, попробуйте добавить ниже к вашим datasource настройкам:

<property name="defaultAutoCommit" value="true" />
...