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



我遇到了org.hibernate.LazyInitializationException:未能懒惰地初始化角色集合:myapp.myapp.models.Contact.messages,无法初始化代理 - 没有会话。我已经研究了这些类似的问题 Hibernate:LazyInitializationException:未能延迟初始化角色集合。无法初始化代理 - 没有会话和如何解决"无法延迟初始化角色集合"休眠异常,但它们都没有帮助我的情况。我让 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;
}
}

新的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);
}
}

所以我假设我在自动配置之外完成的新配置文件中缺少一些东西。这是我所做的唯一更改,它开始抛出错误。就像我上面说的,数据被正确地保存到数据库中,但该错误仍在抛出。

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

更新:

联系人存储库:

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

消息存储库:

@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);

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

只能在事务上下文中延迟加载。 在服务类上使用@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);
}
}

有几种方法可以在 Hibernate 中初始化惰性关联,但最重要的是,您应该能够通过 (1) 使用FETCH JOIN(如果使用条件 API 或自定义,本机或非本机查询)或(2)使用命名/动态实体图来解决这个问题。

Contact中尝试这样的事情:

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

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

您也可以尝试以下FETCH JOINSELECT c FROM Contact AS c JOIN FETCH c.messages m WHERE c.id = :id"- 可能需要调整,我只是"即时"编写的。

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

请不要把你的FetchType.LAZY变成FetchType.EAGER——除非你会失去工作;)

同时,在映射关系上调用方法是一种黑客攻击,将带您进入所谓的N + 1问题。

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

spring.jpa.open-in-view=false

最新更新