Spring JPA和LazyInitializationException

时间:2015-05-19 12:25:12

标签: java hibernate spring-data-jpa

我正在使用spring-jpa。我有2个测试。

@Test
@Transactional
public void testFindAll() {
    List<Engine> eList = engineService.findAll();
    Engine e = eList.get(0); //this engine id=3
    List<Translation> tList = e.getTranslations();
    for(Translation t : tList) {
        ...
    }
}

此方法因以下异常而失败:

  

org.hibernate.LazyInitializationException:懒得初始化   角色集合:xxx.Engine.translations,无法初始化   代理 - 没有会话

但是,这种方法效果很好:

@Test
@Transactional
public void testFindOne() {
    Engine e = engineService.findOne(3);
    List<Translation> tList = e.getTranslations();
    for(Translation t : tList) {
        ...
    }
}

为什么翻译列表在一个案例中成功加载,而在另一个案例中没有成功加载?

编辑:服务/回购代码:

public interface EngineRepository extends JpaRepository<Engine, Integer>
{   
}

@Service
@Transactional
public class EngineService
{
    @Autowired
    private EngineRepository engineRepository;

    public List<Engine> findAll()
    {
        return engineRepository.findAll();
    }

    public Engine findOne(Integer engId)
    {
        return engineRepository.findOne(engId);
    }
}

public class Engine implements Serializable {
    ...
    @OneToMany
    @JoinColumn(name="ID", referencedColumnName="TRAN_ID",  insertable=false, updatable=false, nullable=true)
    @LazyCollection(LazyCollectionOption.EXTRA)
    private List<Translation> translations;
    ...
}

配置:

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(basePackages = {"xxx.dao"})
@ComponentScan(basePackages = {"xxx.dao", "xxx.service", "xxx.bean"})
@PropertySource("classpath:application.properties")
public class SpringDataConfig {

  @Autowired
  private Environment environment;

  @Bean
  public DataSource dataSource() {
    DriverManagerDataSource dataSource = new DriverManagerDataSource();
    dataSource.setUrl(environment.getProperty("db.url"));
    dataSource.setDriverClassName(environment.getProperty("db.driverClass"));
    dataSource.setUsername(environment.getProperty("db.username"));
    dataSource.setPassword(environment.getProperty("db.password"));
    return dataSource;
  }

  @Bean
  public LocalContainerEntityManagerFactoryBean entityManagerFactory() throws NamingException {
    HibernateJpaVendorAdapter hibernateJpaVendorAdapter = new HibernateJpaVendorAdapter();
    hibernateJpaVendorAdapter.setDatabase(Database.POSTGRESQL);

    Properties properties = new Properties();


    properties.put("hibernate.dialect", environment.getProperty("hibernate.dialect"));
    properties.put("hibernate.show_sql", environment.getProperty("hibernate.showSQL"));
    properties.put("hibernate.format_sql", environment.getProperty("hibernate.formatSQL"));

    LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
    entityManagerFactoryBean.setDataSource(dataSource());
    entityManagerFactoryBean.setPackagesToScan("xxx.model");
    entityManagerFactoryBean.setJpaVendorAdapter(hibernateJpaVendorAdapter);
    entityManagerFactoryBean.setJpaProperties(properties);

    return entityManagerFactoryBean;
  }

  @Bean
  public JpaTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
    JpaTransactionManager transactionManager = new JpaTransactionManager();
    transactionManager.setEntityManagerFactory(entityManagerFactory);

    return transactionManager;
  }
}

2 个答案:

答案 0 :(得分:0)

我认为这里的问题是会话在第一种情况下的第一行之后关闭。您应该查看findAll()的JpaRepository实现。

答案 1 :(得分:0)

使用Spring进行集成测试

您的TestCase中似乎没有提供Spring Context,这意味着什么? @Transactional被忽略了。因此,您最终会遇到关闭的会话异常,因为没有事务。

了解如何使用Spring Context here

配置TestCase
@RunWith(SpringJUnit4ClassRunner.class)
// ApplicationContext will be loaded from AppConfig and TestConfig
@ContextConfiguration(classes = {AppConfig.class, TestConfig.class})
public class MyTest {

     @Autowired
     EngineService engineService;

     @Test
     @Transactional
     public void testFindOne() {}

     @Test
     @Transactional
     public void testFindAll() {}

}