не удалось лениво инициализировать коллекцию ролей: myapp.myapp.models.Contact.messages, не удалось инициализировать прокси - нет сеанса - PullRequest
0 голосов
/ 28 декабря 2018

Я сталкиваюсь с org.hibernate.LazyInitializationException: не удалось лениво инициализировать коллекцию ролей: myapp.myapp.models.Contact.messages, не удалось инициализировать прокси - нет сеанса.Я рассмотрел эти похожие вопросы Hibernate: LazyInitializationException: не удалось лениво инициализировать коллекцию ролей.Не удалось инициализировать прокси-сервер - нет сеансов и Как решить «не удалось лениво инициализировать коллекцию ролей», исключение Hibernate , но ни одно из них не помогло моей ситуации.У меня была весенняя автоматическая конфигурация моего источника данных, где у меня не было этой проблемы, но я добавил другое соединение с источником данных, а затем создал файл конфигурации для каждого источника данных, к которому теперь все работает как обычно, как и раньше, но я продолжаю получать эту ошибкувыброшены.Я не знаю что делатьЛюбая помощь приветствуется.

Информация о моей БД в моем файле свойств выглядела так до того, как я добавил другую БД

##############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);
    }
}

Итак, я предполагаю, что мне чего-то не хватает с новыми файлами конфигурации, которые были сделаны отдельно от AutoConfig.Это было единственное изменение, которое я сделал, и он начал выдавать ошибку.Как я уже говорил выше, данные правильно сохраняются в базе данных, но эта ошибка по-прежнему выдается.

Я не знаю, почему это так, объяснение было бы очень полезно.

Обновление:

Хранилище контактов:

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

Ответы [ 3 ]

0 голосов
/ 30 декабря 2018

Если вы добавили строку ниже в файл конфигурации application.properties, то он должен работать

spring.jpa.open-in-view=false
0 голосов
/ 30 декабря 2018

Вы можете выполнять отложенную загрузку только в контексте транзакции.Используйте аннотацию @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);
}
}
0 голосов
/ 29 декабря 2018

Есть несколько способов инициализировать ленивые ассоциации в 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 были некоторые проблемы с чем-то, в частности, с Entity Graphs, но я думаю, что для вашего случая должно работать из коробки.

Вы также можете попробовать FETCH JOIN вроде: SELECT c FROM Contact AS c JOIN FETCH c.messages m WHERE c.id = :id" - можетнужно настроить это, я просто написал это "на лету".

ПРИМЕЧАНИЕ: Кроме того, поскольку вы используете Spring, убедитесь, что у вас есть аннотации к классу "обслуживания".с @Transactional, поскольку отложенная загрузка работает только в (том же) контексте транзакции.

Пожалуйста, не превращайте ваш FetchType.LAZY в FetchType.EAGER - если вы не потеряете работу;)

В то же время вызов метода для сопоставленного отношения является хаком и приведет вас к так называемой проблеме N + 1.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...