Hibernate session.flush с spring @transactional

Я использую Spring и Hibernate в своем приложении и использую Spring Transaction.

Итак, у меня есть сервисный уровень с аннотацией @Transaction для методов, а уровень DAO имеет методы для запроса к базе данных.

@Transactional(readOnly = false)
public void get(){

}

Проблема в том, что когда я хочу сохранить объект в базе данных, я должен использовать session.flush() в конце метода уровня DAO. Почему?

Я думаю, что если я аннотировал @Transaction, то Spring должен автоматически зафиксировать транзакцию после завершения метода обслуживания.

Уровень DAO:

public BaseEntity saveEntity(BaseEntity entity) throws Exception {
        try {
            Session session = sessionFactory.getCurrentSession();
            session.saveOrUpdate(entity);
            session.flush();
        } catch (HibernateException he) {
            throw new Exception("Failed to save entity " + entity);
        }
        return entity;
    }

Сервисный уровень:

    @Transactional(readOnly = false)
    public BaseEntity saveEntity(BaseEntity entity) throws Exception {
        return dao.saveEntity(entity);
    }

весенний конфиг:

<context:property-placeholder properties-ref="deployProperties" />

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

    <!-- Activate Spring Data JPA repository support -->
    <jpa:repositories base-package="com" />

    <!-- Declare a datasource that has pooling capabilities-->   
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
        destroy-method="close"
        p:driverClass="${app.jdbc.driverClassName}"
        p:jdbcUrl="${app.jdbc.url}"
        p:user="${app.jdbc.username}"
        p:password="${app.jdbc.password}"
        p:acquireIncrement="5"
        p:idleConnectionTestPeriod="60"
        p:maxPoolSize="100"
        p:maxStatements="50"
        p:minPoolSize="10" />

    <!-- Declare a JPA entityManagerFactory -->
    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" 
        p:persistenceXmlLocation="classpath*:META-INF/persistence.xml"
        p:persistenceUnitName="hibernatePersistenceUnit"
        p:dataSource-ref="dataSource"
        p:jpaVendorAdapter-ref="hibernateVendor"/>

    <bean id="sessionFactory"
        class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"
        p:dataSource-ref="dataSource" p:configLocation="${hibernate.config}"
        p:packagesToScan="com" />

    <!-- Specify our ORM vendor -->
    <bean id="hibernateVendor" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"
                p:showSql="false"/>

    <!-- Declare a transaction manager-->
    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager" 
        p:entityManagerFactory-ref="entityManagerFactory"/>

Ответ 1

Да, если у вас есть @Transactional для вашего метода DAO, вам не нужно вручную очищать сеанс, hibernate позаботится о том, чтобы очистить сеанс как часть совершения транзакции, если операции в этом методе успешны.

Посмотрите эту ссылку, чтобы узнать, как работает @Transactional - Spring - @Transactional - Что происходит в фоновом режиме?

Ответ 2

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

Точка дыры флеша - это очистить этот стек и выполнить его в транзакции в базе данных. Вы покидаете "сохранить" дом jvm и выполняете свой запрос в большой странной базе данных.

Вот почему вы не можете выбрать то, что вы только что сохранили, без флеша. Это просто не в базе данных.

Значение commit заканчивается после транзакции и делает изменения базы данных видимыми для других. После того, как фиксация выполнена, возврат невозможен.

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

Если вы хотите, чтобы java оптимизировал вашу транзакцию, вам придется добавить ее в свой сервисный уровень. Но помните, что вам не нужно решать проблемы производительности, когда их нет! Сбрасывание всего кода в сервисный уровень не подходит для чтения кода. Держите его простым и глупым;)