【问题标题】:Spring JPA and LazyInitializationExceptionSpring JPA 和 LazyInitializationException
【发布时间】:2015-07-31 06:39:44
【问题描述】:

我正在使用 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;
  }
}

【问题讨论】:

  • 能把engineService.findAll()engineService.findOne()的代码发一下吗?
  • 它只是包装了 engineRepository 方法
  • 还要添加引擎实体的定义和jpa配置。
  • findAll() 正在返回一个分离实体的集合。然后当尝试遍历这些实体并访问惰性初始化集合时,
  • 或者尝试使用@OnetoMany f etch=FetchType.Eggar

标签: java hibernate spring-data-jpa


【解决方案1】:

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

【讨论】:

    【解决方案2】:

    使用 Spring 进行集成测试

    您似乎未能在您的 TestCase 中提供 Spring 上下文,这意味着什么? @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() {}
    
    }
    

    【讨论】:

    • 我的测试类中有@ContextConfiguration
    • TransactionSynchronizationManager.isActualTransactionActive() 在测试方法中是否输出 true?
    • 所以您的 TestCase 配置和 Spring 有问题,请查看链接文档。如果您发布了一个简短的、独立的、正确的(可编译的)示例或至少是完整的测试用例,将会很有帮助
    猜你喜欢
    • 2015-05-31
    • 1970-01-01
    • 1970-01-01
    • 2018-08-11
    • 2014-05-22
    • 1970-01-01
    • 1970-01-01
    • 2016-03-26
    • 2014-12-17
    相关资源
    最近更新 更多