懒惰的集合急切地初始化(事务性+延迟加载)

时间:2012-07-04 07:10:47

标签: spring hibernate lazy-loading transactional

城市类映射到数据库。

@Entity
@Table(name = "City")
public class City implements Serializable, IRelationsQualifier
{
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private int id;
    //-------------------------------------------------------
    @JsonIgnore
    @NotFound(action = NotFoundAction.IGNORE)
    @ManyToMany(
            fetch = FetchType.LAZY,
            cascade = {CascadeType.MERGE,CascadeType.PERSIST,CascadeType.REFRESH},
            targetEntity = Event.class
        )
        @JoinTable(
               name="CityEvent",
               joinColumns = @JoinColumn( name="city_id"),
               inverseJoinColumns = @JoinColumn( name="event_id")
        )
    private Set<Event> eventList = new HashSet<Event>();

    public int getId()
    {
    return id;
    }
    public void setId(int id)
    {
    this.id = id;
    }

    @JsonIgnore
    public Set<Event> getEvents()
    {
    return eventList;
    }
    @JsonIgnore
    public void setEvents(Set<Event> events)
    {
    this.eventList = events;
    }


}

城市的Dao层。

package com.globerry.project.dao;
// removing imports to  make it easier to read   

@Repository
public class CityDao implements ICityDao
{

    @Autowired
    SessionFactory sessionFactory;
    @Autowired

    @Override
    public City getCityById(int id)
    {
    City city = (City) sessionFactory.getCurrentSession().load(City.class, id);
    return city;
    }
}

测试:

package com.globerry.project.dao;
// removing time imports to make it easier to read.

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:/META-INF/spring/daoTestContext.xml")
@TestExecutionListeners({
    DependencyInjectionTestExecutionListener.class,
    DirtiesContextTestExecutionListener.class, ContextLoaderListener.class
})
public class CityDaoTest {

    @Test
    @Transactional(readOnly=false)
    public void LazyTest()
    {
        City city1 = new City();
        city1.setName("Bobryjsk1");
        try
        {
        cityDao.addCity(city1);
        }
        catch (MySqlException e) 
        {
        e.printStackTrace(System.err);
        }
        Event ev = new Event();
        ev.setName("Disnayland");
        eventDao.addEvent(ev, city1);
        ev = new Event();
        ev.setName("Disnayland5");
        eventDao.addEvent(ev, city1);
        System.err.println("1");
        city1 = cityDao.getCityById(city1.getId());//there i saw in debug that events have been already inizialized 
        System.err.println("2");
        System.err.println(Hibernate.isInitialized(city1.getEvents()));//returns true
        Iterator<Event> it = city1.getEvents().iterator();
        System.err.println("3");
        ev = it.next();
        System.err.println(ev.getName());
        ev = new Event();
        ev.setName("Disnayland55");
        eventDao.addEvent(ev, city1);
    }

}

根上下文:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jdbc="http://www.springframework.org/schema/jdbc"
    xsi:schemaLocation="
        http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.1.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">


    <!-- <jdbc:embedded-database id="dataSource" type="H2"/> -->
    <context:annotation-config />
    <context:component-scan base-package="com.globerry.project.domain" />
    <context:component-scan base-package="com.globerry.project.dao" /> 
    <context:component-scan base-package="com.globerry.project.service" />


        <!-- Файл с настройками ресурсов для работы с данными (Data Access Resources) -->
        <tx:annotation-driven transaction-manager="transactionManager" /> 
    <!-- Менеджер транзакций -->


    <!-- Настройки бина dataSource будем хранить в отдельном файле -->
  <bean id="propertyConfigurer"
        class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
        p:location="classpath:/META-INF/jdbc.properties" />

    <!-- Непосредственно бин dataSource -->
    <bean id="dataSource"
        class="org.springframework.jdbc.datasource.DriverManagerDataSource"
        p:driverClassName="com.mysql.jdbc.Driver" 
        p:url="${jdbc.databaseurl}"
        p:username="${jdbc.username}" 
        p:password="${jdbc.password}" />

    <!-- Настройки фабрики сессий Хибернейта -->
    <bean id="sessionFactory"
        class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"
        p:packagesToScan="com.globerry.project.Dao">

        <property name="dataSource" ref="dataSource" />
        <property name="configLocation">
            <value>classpath:hibernate.cfg.xml</value>
        </property>
        <property name="configurationClass">
            <value>org.hibernate.cfg.AnnotationConfiguration</value>
        </property>
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.show_sql">true</prop>
                <prop key="hibernate.transaction.factory_class">org.hibernate.transaction.JDBCTransactionFactory</prop> 
                <prop key="hibernate.dialect">org.hibernate.dialect.MySQLInnoDBDialect</prop>
                <prop key="hibernate.connection.charSet">UTF-8</prop>
            </props>
        </property>
    </bean>

    <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"
          p:sessionFactory-ref="sessionFactory">
        <qualifier value="transactionManager"/>
    </bean>
</beans>

当我在调试模式的'LazyTest()'中使用方法'getCityById()'时,我得到了奇怪的结果。在调试中,我看到我的事件集合已初始化,在我第一次使用它之前。但我正在使用Lazy Fetch Strategy。有什么问题?

1 个答案:

答案 0 :(得分:1)

那是因为它已经在会话中了。 Load返回刚刚创建的City对象 - 而不是从数据库中提取它。

在getCityById调用之前添加以下代码 - 您将获得您期望的结果。

sessionFactory.getCurrentSession().flush()
sessionFactory.getCurrentSession().clear()