无法延迟初始化角色集合:myapp.myapp.models.Contact.messages,无法初始化代理 - 没有会话

Posted

技术标签:

【中文标题】无法延迟初始化角色集合:myapp.myapp.models.Contact.messages,无法初始化代理 - 没有会话【英文标题】:failed to lazily initialize a collection of role: myapp.myapp.models.Contact.messages, could not initialize proxy - no Session 【发布时间】:2019-05-26 14:44:29 【问题描述】:

我遇到 org.hibernate.LazyInitializationException:。我已经研究了这些类似的问题Hibernate: LazyInitializationException: failed to lazily initialize a collection of role. Could not initialize proxy - no Session 和How to solve the “failed to lazily initialize a collection of role” Hibernate exception,但它们都没有帮助我的情况。我有 spring 自动配置我的数据源到我没有这个问题的地方,但是我添加了另一个数据源连接,然后为每个数据源创建了一个配置文件,现在一切正常,就像以前一样,但我一直收到这个错误抛出。我不知道该怎么办。任何帮助表示赞赏。

在我添加其他数据库之前,我的属性文件中的数据库信息如下所示

##############DBs##################
spring.jpa.database-platform=org.hibernate.dialect.mysql5InnoDBDialect
spring.jpa.hibernate.ddl-auto=update
spring.jpa.database=default

#Myapp DB
spring.datasource.driverClassName=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/myapp?        verifyServerCertificate=false&useSSL=false&requireSSL=false
spring.datasource.username=myusername
spring.datasource.password=mypassword

一切正常。

现在一切都是这样设置的。

属性文件

##############DBs##################
spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect
spring.jpa.hibernate.ddl-auto=update
spring.jpa.database=default

#Myapp DB
spring.datasource.driverClassName=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/myapp?        verifyServerCertificate=false&useSSL=false&requireSSL=false
spring.datasource.username=myusername
spring.datasource.password=mypassword

#Other DB
spring.seconddatasource.driverClassName = com.mysql.jdbc.Driver
spring.seconddatasource.url = jdbc:mysql://localhost:3306/other
spring.seconddatasource.username=myusername
spring.seconddatasource.password=mypassword
###################################

联系实体:

@Entity
@Table(name = "contact")
public class Contact 

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "contact")
    private List<Messages> messages;

    public long getId() 
        return this.id;
    

    public void setId(long id) 
        this.id = id;
    

    public List<Messages> getMessages() 
        return this.messages == null ? null : new ArrayList<>(this.messages);
    

    public void setMessages(List<Messages> messages) 
        this.messages = messages;
    

    public void addMessage(Messages message) 
        this.messages.add(message); // this is where the error is being thrown
    

消息实体:

@Entity
@Table(name = "message")
public class Contact 

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;

    @ManyToOne
    @JoinColumn(name = "contactId", nullable = false)
    private Contact contact;

    public long getId() 
        return this.id;
    

    public void setId(long id) 
        this.id = id;
    

    public Contact getContact() 
         return this.contact;
    

    public void setContact(Contact contact) 
         this.contact = contact;
    

New MyAppConfigClass(一旦与其他一起放入,错误就开始发生):

@ComponentScan
@Configuration
@EnableJpaRepositories(
    basePackages =  "myapp.myapp" ,
    entityManagerFactoryRef = "myappEntityManagerFactory",
    transactionManagerRef = "myappTransactionManager")
@EnableTransactionManagement
public class MyAppDBConfiguration 

    @Autowired private ApplicationContext applicationContext;

    @Bean(name = "myappExceptionTranslator")
    public HibernateExceptionTranslator personnelHibernateExceptionTranslator() 
        return new HibernateExceptionTranslator();
    

    @Bean(name = "myappTransactionManager")
    public PlatformTransactionManager personnelTransactionManager() 
        return new JpaTransactionManager(personnelEntityManagerFactory().getObject());
    

    @Bean(name = "myappEntityManagerFactory")
    public LocalContainerEntityManagerFactoryBean personnelEntityManagerFactory() 

        HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
        vendorAdapter.setGenerateDdl(true);

        LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
        factory.setJpaVendorAdapter(vendorAdapter);
        factory.setPackagesToScan("myapp.myapp");
        factory.setDataSource(myappDataSource());
        factory.afterPropertiesSet();

        return factory;

    

    @Primary
    @Bean(name = "myappDataConfig")
    @ConfigurationProperties("spring.datasource")
    public DataSourceProperties myappProperties() 
        return new DataSourceProperties();
    

    @Bean(name = "myappData", destroyMethod = "")
    public DataSource myappDataSource() 
        DataSourceProperties properties = myappProperties();
        if (null != properties.getJndiName()) 
            JndiDataSourceLookup lookup = new    JndiDataSourceLookup();
            DataSource source = lookup.getDataSource(properties.getJndiName());
            excludeMBeanIfNecessary(source, "myappData");
            return source;
         else 
            return properties.initializeDataSourceBuilder().build();
        
    

    private void excludeMBeanIfNecessary(Object candidate, String beanName) 
        try 
            MBeanExporter mbeanExporter = this.applicationContext.getBean(MBeanExporter.class);
            if (JmxUtils.isMBean(candidate.getClass())) 
                mbeanExporter.addExcludedBean(beanName);
            
         catch (NoSuchBeanDefinitionException ex) 
            // No exporter. Exclusion is unnecessary
        
    

这是OtherConfigClass(几乎完全一样):

@ComponentScan
@Configuration
@EnableJpaRepositories(
    basePackages =  "myapp.other" ,
    entityManagerFactoryRef = "otherEntityManagerFactory",
    transactionManagerRef = "otherTransactionManager")
@EnableTransactionManagement
public class OtherDBConfiguration 

    @Autowired private ApplicationContext applicationContext;

    @Bean(name = "otherExceptionTranslator")
    public HibernateExceptionTranslator personnelHibernateExceptionTranslator() 
        return new HibernateExceptionTranslator();
    

    @Bean(name = "otherTransactionManager")
    public PlatformTransactionManager personnelTransactionManager() 
        return new JpaTransactionManager(personnelEntityManagerFactory().getObject());
    

    @Bean(name = "otherEntityManagerFactory")
    public LocalContainerEntityManagerFactoryBean personnelEntityManagerFactory() 

        HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
        vendorAdapter.setGenerateDdl(true);

        LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
        factory.setJpaVendorAdapter(vendorAdapter);
        factory.setPackagesToScan("myapp.other");
        factory.setDataSource(otherDataSource());
        factory.afterPropertiesSet();

        return factory;

    

    @Bean(name = "otherDataConfig")
    @ConfigurationProperties("spring.seconddatasource")
    public DataSourceProperties otherProperties() 
        return new DataSourceProperties();
    

    @Bean(name = "otherData", destroyMethod = "")
    public DataSource textappotherDataSource() 
        DataSourceProperties properties = myappProperties();
        if (null != properties.getJndiName()) 
            JndiDataSourceLookup lookup = new    JndiDataSourceLookup();
            DataSource source = lookup.getDataSource(properties.getJndiName());
            excludeMBeanIfNecessary(source, "otherData");
            return source;
         else 
            return properties.initializeDataSourceBuilder().build();
        
    

    private void excludeMBeanIfNecessary(Object candidate, String beanName) 
        try 
            MBeanExporter mbeanExporter = this.applicationContext.getBean(MBeanExporter.class);
            if (JmxUtils.isMBean(candidate.getClass())) 
                mbeanExporter.addExcludedBean(beanName);
            
         catch (NoSuchBeanDefinitionException ex) 
            // No exporter. Exclusion is unnecessary
        
    

这是应用程序类:

@EnableAutoConfiguration
@SpringBootApplication
public class MyApplication 

    public static void main(String[] args) 
            SpringApplication.run(MyApplication.class, args);
    

所以我假设我在 AutoConfig 之外完成的新配置文件中遗漏了一些东西。这是我做的唯一改变,它开始抛出错误。就像我上面说的,数据已正确保存到数据库中,但仍然会抛出该错误。

我不知道为什么会这样,解释一下会很有帮助。

更新:

ContactRepository:

@Repository
public interface ContactRepository extends JpaRepository<Contact, Long> 


MessagesRepository:

@Repository
public interface MessagesRepository extends JpaRepository<Messages, Long> 


服务类:

@Service
public void serviceClass(long id) 
    Contact contact = contactRepository.findOne(id);
    Messages msg = new Messages();
    msg.setContact(contact);

    // do some work here

    Messages savedMessage = messagesRepository.save(msg);
    contact.addMessage(savedMessage);
    contactRepository.save(contact);

【问题讨论】:

您在 JPA 实体上缺少默认的无参数构造函数,所以我认为这是一个错字。您还可以分享您正在做什么来检索实体吗? – 通常在“服务”类 +“存储库”上。 @x80486 我的存储库只是扩展的 JpaRepositories。我发布了存储库和服务类。如果您需要更多信息,请告诉我。 好的,我回答的内容仍然是最新的。您有服务级别的@Transactional 吗? 【参考方案1】:

在 application.properties 文件中设置 enable_lazy_load_no_trans=true 解决了我的情况,而无需将提取类型从惰性更改为渴望。

【讨论】:

小修正:应该是spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true【参考方案2】:

您只能在事务上下文中进行延迟加载。 在您的服务类上使用 @Transactional 注释:

@Service
@Transactional
public class Service 
public void serviceClass(long id) 
 Contact contact = contactRepository.findOne(id);
 Messages msg = new Messages();
 msg.setContact(contact);

 // do some work here

 Messages savedMessage = messagesRepository.save(msg);
 contact.addMessage(savedMessage);
 contactRepository.save(contact);


【讨论】:

【参考方案3】:

如果您在 application.properties 配置文件中添加以下行,那么它应该可以工作

spring.jpa.open-in-view=false

【讨论】:

【参考方案4】:

有几种方法可以在 Hibernate 中初始化惰性关联,但归根结底,您应该能够通过 (1) 使用 FETCH JOIN(如果使用 Criteria API 或自定义、原生或非原生查询),或 (2) 使用命名/动态实体图

Contact 中尝试这样的事情:

@Entity
@Table(name = "contact")
@NamedEntityGraph(name = "graph.Contact.messages",
    attributeNodes = @NamedAttributeNode("messages"))
public class Contact  ... 

如果您有访问权(和时间)使用EntityManager,所有这一切都很简单。我记得 Spring Data JPA 在实体图方面遇到了一些问题,但我认为你的情况应该是开箱即用的。

您也可以尝试FETCH JOIN,例如:SELECT c FROM Contact AS c JOIN FETCH c.messages m WHERE c.id = :id" - 可能需要对其进行调整,我只是“即时”编写的。

注意:此外,由于您使用的是 Spring,请确保您的“服务”类使用 @Transactional 注释,因为延迟加载仅在(相同)事务上下文中有效.

请不要将您的 FetchType.LAZY 变成 FetchType.EAGER - 除非您将失去工作;)

同时,在映射关系上调用方法是一种 hack,会带你到所谓的N + 1 问题。

【讨论】:

以上是关于无法延迟初始化角色集合:myapp.myapp.models.Contact.messages,无法初始化代理 - 没有会话的主要内容,如果未能解决你的问题,请参考以下文章

无法写入 JSON:无法延迟初始化角色集合

org.hibernate.LazyInitializationException:无法延迟初始化角色集合:FQPropretyName,无法初始化代理 - 无会话

LazyInitializationException: 延迟初始化角色集合失败 无法初始化代理 - 没有会话

无法延迟初始化角色集合:myapp.myapp.models.Contact.messages,无法初始化代理 - 没有会话

未能延迟初始化角色集合:无法初始化代理 - Hibernate 中的 @ManyToMany 映射注释中没有会话错误? [复制]

延迟初始化:未能延迟初始化集合