Hibernate transaction manager configurations in Spring

╄→гoц情女王★ 提交于 2019-12-05 01:08:31

Ok, finally i realized what was the problem. In code above i used load instead of get. Session.load did not actually hit the databased. That's the reason why i get lazy-initialization exception outside of @Transactional method

If i use openSession instead of getCurrentSession, session is opened outside of scope spring container. As result session was not close and it allow me to read object properties outside of @Transactional method

The reason Hibernate does not perform any SQL queries until you call the getters is because I believe the FetchType is set to LAZY. To fix this problem you will need to change the FetchType to EAGER in your POJO:

@Entity
@Table(name = "user")
public class User {

    /*Other data members*/

    @Basic(fetch = FetchType.EAGER)
    private String email;

}

I personally never had to specify Basic types to have an EAGER FetchType so I'm not entirely sure why your configuration requires this. If its only in your tests it could be due to the way you have your JUnit tests configured. It should have something like this on the class declaration:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"/test-app-config.xml"})
@Transactional
public class UserServiceTest {

}

As for a good resource I always find SpringByExample to be helpful.

EDIT

So I'm not entirely sure what is wrong with your configuration. It does differ from the way I have mine set up so here is my typical configuration in hopes that it helps. The hibernate.transaction.factory_class could be a key property you are missing. I also use the AnnotationSessionFactoryBean:

<!-- DataSource -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"
    p:driverClassName="com.mysql.jdbc.Driver" 
    p:url="jdbc:mysql://localhost/dbname"
    p:username="root"
    p:password="password"/>

<!-- Hibernate session factory -->
<bean id="sessionFactory"
    class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"
    p:dataSource-ref="dataSource">
    <property name="packagesToScan" value="com.beans"/>
    <property name="hibernateProperties">
        <props>
            <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</prop>
            <prop key="hibernate.show_sql">true</prop>
            <prop key="hibernate.transaction.factory_class">org.hibernate.transaction.JDBCTransactionFactory</prop>
        </props>
    </property>
</bean> 

<!-- Transaction Manager -->
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
    <property name="sessionFactory">
        <ref bean="sessionFactory" />
    </property>
</bean>

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

From Hibernate documentation https://docs.jboss.org/hibernate/orm/4.2/manual/en-US/html/ch11.html#objectstate-loading:

Be aware that load() will throw an unrecoverable exception if there is no matching database row. If the class is mapped with a proxy, load() just returns an uninitialized proxy and does not actually hit the database until you invoke a method of the proxy. This is useful if you wish to create an association to an object without actually loading it from the database. It also allows multiple instances to be loaded as a batch if batch-size is defined for the class mapping.

From above documentation in your case bean is mapped with spring proxy so load just returns. Hence you need to use get() instead of load() which always hits the database.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!