Проблема cвязи между двумя энтити

166
07 января 2019, 13:20

Имею две энтити: Train и Seat. У них есть реляция one-to-many:

UML

Train.java:

   @Entity
    @Table(name = "train")
    public class Train {
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        @Column(name = "id")
        private Long id;
        @Column(name = "name")
        private String name;
        // Проблема с реляцией!!!
        @OneToMany(mappedBy = "train", cascade = CascadeType.ALL)
        private Set<Seat> seats;
        @OneToOne
        private State state;
        @Column(name = "carriages")
        private Integer carriages;
        // Getters & Setters...
}

Seat.java:

@Entity
@Table(name = "seat")
public class Seat {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private Long id;
    @Column(name = "carriage")
    private Integer carriage;
    @Column(name = "seat")
    private Integer seat;
    // Реляция с поездом
    @ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    @JoinColumn(name = "train_id", nullable = false)
    private Train train;
    // Getters & Setters...
}

Как можно заметить, связка тут bi-directional:

@OneToMany(mappedBy = "train", cascade = CascadeType.ALL)
    private Set<Seat> seats;

И

@ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    @JoinColumn(name = "train_id", nullable = false)
    private Train train;

Собственно говоря, у меня произошла ошибка в бизнес-логике на уровне сервиса, когда я вытаскиваю из расписания JPA Train. Причём, проблемы начинаются лишь тогда, когда я вытаскиваю из поезда список сидений (Seat). В моём Spring MVC приложении вылетает такая ошибка:

org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.slandshow.models.Train.seats, could not initialize proxy - no Session

Затем, когда я понял первоисточник проблемы, решил дебажить в мейне эти два энтити.

С помощью SessionFactory я решил вытащить из БД поезд под конкретным айдишником записи и посмотреть:

session.beginTransaction();
Train train = session.get(Train.class, 5l); // Вытаскиваю поезд из базы
System.out.println(train); // Причина ошибки вылезает в переопределённом методе toString
session.getTransaction().commit();

Так как у меня toString переопределён, то я хватаю вот такой стек-трейс:

ERROR   2018-09-21 19:42:44,671 [main] org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl  - Connection leak detected: there are 1 unclosed connections upon shutting down pool jdbc:mysql://localhost:3306/RattlerStation
Exception in thread "main" java.lang.StackOverflowError
    at java.lang.Long.toString(Long.java:396)
    at java.lang.Long.toString(Long.java:1032)
    at java.lang.String.valueOf(String.java:2994)
    at java.lang.StringBuilder.append(StringBuilder.java:131)
    at com.slandshow.models.Train.toString(Train.java:74)
    at java.lang.String.valueOf(String.java:2994)
    at java.lang.StringBuilder.append(StringBuilder.java:131)
    at com.slandshow.models.Seat.toString(Seat.java:72)
    at java.lang.String.valueOf(String.java:2994)
    at java.lang.StringBuilder.append(StringBuilder.java:131)
    at java.util.AbstractCollection.toString(AbstractCollection.java:462)
    at org.hibernate.collection.internal.PersistentSet.toString(PersistentSet.java:303)
    at java.lang.String.valueOf(String.java:2994)
    at java.lang.StringBuilder.append(StringBuilder.java:131)
    at com.slandshow.models.Train.toString(Train.java:74)
    at java.lang.String.valueOf(String.java:2994)
    at java.lang.StringBuilder.append(StringBuilder.java:131)
    at com.slandshow.models.Seat.toString(Seat.java:72)
    at java.lang.String.valueOf(String.java:2994)
    at java.lang.StringBuilder.append(StringBuilder.java:131)
    at java.util.AbstractCollection.toString(AbstractCollection.java:462)
    at org.hibernate.collection.internal.PersistentSet.toString(PersistentSet.java:303)
    at java.lang.String.valueOf(String.java:2994)
    at java.lang.StringBuilder.append(StringBuilder.java:131)
    at com.slandshow.models.Train.toString(Train.java:74)
    at java.lang.String.valueOf(String.java:2994)
    at java.lang.StringBuilder.append(StringBuilder.java:131)
    at com.slandshow.models.Seat.toString(Seat.java:72)
    at java.lang.String.valueOf(String.java:2994)
    at java.lang.StringBuilder.append(StringBuilder.java:131)
    at java.util.AbstractCollection.toString(AbstractCollection.java:462)
    at org.hibernate.collection.internal.PersistentSet.toString(PersistentSet.java:303)
    at java.lang.String.valueOf(String.java:2994)
    at java.lang.StringBuilder.append(StringBuilder.java:131)
    at com.slandshow.models.Train.toString(Train.java:74)
    at java.lang.String.valueOf(String.java:2994)
    at java.lang.StringBuilder.append(StringBuilder.java:131)
    at com.slandshow.models.Seat.toString(Seat.java:72)
    at java.lang.String.valueOf(String.java:2994)
    at java.lang.StringBuilder.append(StringBuilder.java:131)
    at java.util.AbstractCollection.toString(AbstractCollection.java:462)
    at org.hibernate.collection.internal.PersistentSet.toString(PersistentSet.java:303)
    at java.lang.String.valueOf(String.java:2994)
    at java.lang.StringBuilder.append(StringBuilder.java:131)
    at com.slandshow.models.Train.toString(Train.java:74)
    at java.lang.String.valueOf(String.java:2994)
    at java.lang.StringBuilder.append(StringBuilder.java:131)
    at com.slandshow.models.Seat.toString(Seat.java:72)
    at java.lang.String.valueOf(String.java:2994)
    at java.lang.StringBuilder.append(StringBuilder.java:131)
    at java.util.AbstractCollection.toString(AbstractCollection.java:462)
    at org.hibernate.collection.internal.PersistentSet.toString(PersistentSet.java:303)
    at java.lang.String.valueOf(String.java:2994)
    at java.lang.StringBuilder.append(StringBuilder.java:131)
    at com.slandshow.models.Train.toString(Train.java:74)
    at java.lang.String.valueOf(String.java:2994)
    at java.lang.StringBuilder.append(StringBuilder.java:131)
    at com.slandshow.models.Seat.toString(Seat.java:72)
    at java.lang.String.valueOf(String.java:2994)
    at java.lang.StringBuilder.append(StringBuilder.java:131)
    at java.util.AbstractCollection.toString(AbstractCollection.java:462)
    at org.hibernate.collection.internal.PersistentSet.toString(PersistentSet.java:303)
    at java.lang.String.valueOf(String.java:2994)
    at java.lang.StringBuilder.append(StringBuilder.java:131)
    at com.slandshow.models.Train.toString(Train.java:74)
    at java.lang.String.valueOf(String.java:2994)
    at java.lang.StringBuilder.append(StringBuilder.java:131)
    at com.slandshow.models.Seat.toString(Seat.java:72)
    at java.lang.String.valueOf(String.java:2994)
    at java.lang.StringBuilder.append(StringBuilder.java:131)
    at java.util.AbstractCollection.toString(AbstractCollection.java:462)
    at org.hibernate.collection.internal.PersistentSet.toString(PersistentSet.java:303)
    at java.lang.String.valueOf(String.java:2994)
    at java.lang.StringBuilder.append(StringBuilder.java:131)
    at com.slandshow.models.Train.toString(Train.java:74)
    at java.lang.String.valueOf(String.java:2994)
    at java.lang.StringBuilder.append(StringBuilder.java:131)
    at com.slandshow.models.Seat.toString(Seat.java:72)
    at java.lang.String.valueOf(String.java:2994)
    at java.lang.StringBuilder.append(StringBuilder.java:131)
    at java.util.AbstractCollection.toString(AbstractCollection.java:462)
    at org.hibernate.collection.internal.PersistentSet.toString(PersistentSet.java:303)
    at java.lang.String.valueOf(String.java:2994)
    at java.lang.StringBuilder.append(StringBuilder.java:131)
    at com.slandshow.models.Train.toString(Train.java:74)
    at java.lang.String.valueOf(String.java:2994)
    at java.lang.StringBuilder.append(StringBuilder.java:131)
    at com.slandshow.models.Seat.toString(Seat.java:72)
    at java.lang.String.valueOf(String.java:2994)
    at java.lang.StringBuilder.append(StringBuilder.java:131)
    at java.util.AbstractCollection.toString(AbstractCollection.java:462)
    at org.hibernate.collection.internal.PersistentSet.toString(PersistentSet.java:303)
    at java.lang.String.valueOf(String.java:2994)
    at java.lang.StringBuilder.append(StringBuilder.java:131)
    at com.slandshow.models.Train.toString(Train.java:74)
    at java.lang.String.valueOf(String.java:2994)
    at java.lang.StringBuilder.append(StringBuilder.java:131)
    at com.slandshow.models.Seat.toString(Seat.java:72)
    at java.lang.String.valueOf(String.java:2994)
    at java.lang.StringBuilder.append(StringBuilder.java:131)
    at java.util.AbstractCollection.toString(AbstractCollection.java:462)
    at org.hibernate.collection.internal.PersistentSet.toString(PersistentSet.java:303)
    at java.lang.String.valueOf(String.java:2994)
    at java.lang.StringBuilder.append(StringBuilder.java:131)
    at com.slandshow.models.Train.toString(Train.java:74)
    at java.lang.String.valueOf(String.java:2994)
    at java.lang.StringBuilder.append(StringBuilder.java:131)
    at com.slandshow.models.Seat.toString(Seat.java:72)
    at java.lang.String.valueOf(String.java:2994)
    at java.lang.StringBuilder.append(StringBuilder.java:131)
    at java.util.AbstractCollection.toString(AbstractCollection.java:462)
    at org.hibernate.collection.internal.PersistentSet.toString(PersistentSet.java:303)
    at java.lang.String.valueOf(String.java:2994)
    at java.lang.StringBuilder.append(StringBuilder.java:131)
    at com.slandshow.models.Train.toString(Train.java:74)
    at java.lang.String.valueOf(String.java:2994)
    at java.lang.StringBuilder.append(StringBuilder.java:131)
    at com.slandshow.models.Seat.toString(Seat.java:72)
    at java.lang.String.valueOf(String.java:2994)
    at java.lang.StringBuilder.append(StringBuilder.java:131)
    at java.util.AbstractCollection.toString(AbstractCollection.java:462)
    at org.hibernate.collection.internal.PersistentSet.toString(PersistentSet.java:303)
    at java.lang.String.valueOf(String.java:2994)
    at java.lang.StringBuilder.append(StringBuilder.java:131)
    at com.slandshow.models.Train.toString(Train.java:74)
    at java.lang.String.valueOf(String.java:2994)
    at java.lang.StringBuilder.append(StringBuilder.java:131)
    at com.slandshow.models.Seat.toString(Seat.java:72)
    at java.lang.String.valueOf(String.java:2994)
    at java.lang.StringBuilder.append(StringBuilder.java:131)
    at java.util.AbstractCollection.toString(AbstractCollection.java:462)
    at org.hibernate.collection.internal.PersistentSet.toString(PersistentSet.java:303)
    at java.lang.String.valueOf(String.java:2994)
    at java.lang.StringBuilder.append(StringBuilder.java:131)
    at com.slandshow.models.Train.toString(Train.java:74)
    at java.lang.String.valueOf(String.java:2994)
    at java.lang.StringBuilder.append(StringBuilder.java:131)
    at com.slandshow.models.Seat.toString(Seat.java:72)
    at java.lang.String.valueOf(String.java:2994)
    at java.lang.StringBuilder.append(StringBuilder.java:131)
    at java.util.AbstractCollection.toString(AbstractCollection.java:462)
    at org.hibernate.collection.internal.PersistentSet.toString(PersistentSet.java:303)
    at java.lang.String.valueOf(String.java:2994)
    at java.lang.StringBuilder.append(StringBuilder.java:131)
    at com.slandshow.models.Train.toString(Train.java:74)
    at java.lang.String.valueOf(String.java:2994)
    at java.lang.StringBuilder.append(StringBuilder.java:131)
    at com.slandshow.models.Seat.toString(Seat.java:72)
    at java.lang.String.valueOf(String.java:2994)
    at java.lang.StringBuilder.append(StringBuilder.java:131)
    at java.util.AbstractCollection.toString(AbstractCollection.java:462)
    at org.hibernate.collection.internal.PersistentSet.toString(PersistentSet.java:303)
    at java.lang.String.valueOf(String.java:2994)
    at java.lang.StringBuilder.append(StringBuilder.java:131)
    at com.slandshow.models.Train.toString(Train.java:74)
    at java.lang.String.valueOf(String.java:2994)
    at java.lang.StringBuilder.append(StringBuilder.java:131)
    at com.slandshow.models.Seat.toString(Seat.java:72)
    at java.lang.String.valueOf(String.java:2994)
    at java.lang.StringBuilder.append(StringBuilder.java:131)
    at java.util.AbstractCollection.toString(AbstractCollection.java:462)
    at org.hibernate.collection.internal.PersistentSet.toString(PersistentSet.java:303)
    at java.lang.String.valueOf(String.java:2994)
    at java.lang.StringBuilder.append(StringBuilder.java:131)
    at com.slandshow.models.Train.toString(Train.java:74)
    at java.lang.String.valueOf(String.java:2994)
    at java.lang.StringBuilder.append(StringBuilder.java:131)
    at com.slandshow.models.Seat.toString(Seat.java:72)
    at java.lang.String.valueOf(String.java:2994)
    at java.lang.StringBuilder.append(StringBuilder.java:131)
    at java.util.AbstractCollection.toString(AbstractCollection.java:462)
    at org.hibernate.collection.internal.PersistentSet.toString(PersistentSet.java:303)
    at java.lang.String.valueOf(String.java:2994)
    at java.lang.StringBuilder.append(StringBuilder.java:131)
    at com.slandshow.models.Train.toString(Train.java:74)
    at java.lang.String.valueOf(String.java:2994)
    at java.lang.StringBuilder.append(StringBuilder.java:131)
    at com.slandshow.models.Seat.toString(Seat.java:72)
    at java.lang.String.valueOf(String.java:2994)
    at java.lang.StringBuilder.append(StringBuilder.java:131)
    at java.util.AbstractCollection.toString(AbstractCollection.java:462)
    at org.hibernate.collection.internal.PersistentSet.toString(PersistentSet.java:303)
    at java.lang.String.valueOf(String.java:2994)
    at java.lang.StringBuilder.append(StringBuilder.java:131)
    at com.slandshow.models.Train.toString(Train.java:74)
    at java.lang.String.valueOf(String.java:2994)
    at java.lang.StringBuilder.append(StringBuilder.java:131)
    at com.slandshow.models.Seat.toString(Seat.java:72)
    at java.lang.String.valueOf(String.java:2994)
    at java.lang.StringBuilder.append(StringBuilder.java:131)
    at java.util.AbstractCollection.toString(AbstractCollection.java:462)
    at org.hibernate.collection.internal.PersistentSet.toString(PersistentSet.java:303)
    at java.lang.String.valueOf(String.java:2994)
    at java.lang.StringBuilder.append(StringBuilder.java:131)
    at com.slandshow.models.Train.toString(Train.java:74)
    at java.lang.String.valueOf(String.java:2994)
    at java.lang.StringBuilder.append(StringBuilder.java:131)
    at com.slandshow.models.Seat.toString(Seat.java:72)
    at java.lang.String.valueOf(String.java:2994)
    at java.lang.StringBuilder.append(StringBuilder.java:131)
    at java.util.AbstractCollection.toString(AbstractCollection.java:462)
    at org.hibernate.collection.internal.PersistentSet.toString(PersistentSet.java:303)
    at java.lang.String.valueOf(String.java:2994)
    at java.lang.StringBuilder.append(StringBuilder.java:131)
    at com.slandshow.models.Train.toString(Train.java:74)
    at java.lang.String.valueOf(String.java:2994)
    at java.lang.StringBuilder.append(StringBuilder.java:131)
    at com.slandshow.models.Seat.toString(Seat.java:72)
    at java.lang.String.valueOf(String.java:2994)
    at java.lang.StringBuilder.append(StringBuilder.java:131)
    at java.util.AbstractCollection.toString(AbstractCollection.java:462)
    at org.hibernate.collection.internal.PersistentSet.toString(PersistentSet.java:303)
    at java.lang.String.valueOf(String.java:2994)
    at java.lang.StringBuilder.append(StringBuilder.java:131)
    at com.slandshow.models.Train.toString(Train.java:74)
    at java.lang.String.valueOf(String.java:2994)
    at java.lang.StringBuilder.append(StringBuilder.java:131)
    at com.slandshow.models.Seat.toString(Seat.java:72)
    at java.lang.String.valueOf(String.java:2994)
    at java.lang.StringBuilder.append(StringBuilder.java:131)
    at java.util.AbstractCollection.toString(AbstractCollection.java:462)
    at org.hibernate.collection.internal.PersistentSet.toString(PersistentSet.java:303)
    at java.lang.String.valueOf(String.java:2994)
    at java.lang.StringBuilder.append(StringBuilder.java:131)
    at com.slandshow.models.Train.toString(Train.java:74)
    at java.lang.String.valueOf(String.java:2994)
    at java.lang.StringBuilder.append(StringBuilder.java:131)
    at com.slandshow.models.Seat.toString(Seat.java:72)
    at java.lang.String.valueOf(String.java:2994)
    at java.lang.StringBuilder.append(StringBuilder.java:131)
    at java.util.AbstractCollection.toString(AbstractCollection.java:462)
    at org.hibernate.collection.internal.PersistentSet.toString(PersistentSet.java:303)
    at java.lang.String.valueOf(String.java:2994)
    at java.lang.StringBuilder.append(StringBuilder.java:131)
    at com.slandshow.models.Train.toString(Train.java:74)
    at java.lang.String.valueOf(String.java:2994)
    at java.lang.StringBuilder.append(StringBuilder.java:131)
    at com.slandshow.models.Seat.toString(Seat.java:72)
    at java.lang.String.valueOf(String.java:2994)
    at java.lang.StringBuilder.append(StringBuilder.java:131)
    at java.util.AbstractCollection.toString(AbstractCollection.java:462)
    at org.hibernate.collection.internal.PersistentSet.toString(PersistentSet.java:303)
    at java.lang.String.valueOf(String.java:2994)
    at java.lang.StringBuilder.append(StringBuilder.java:131)
    at com.slandshow.models.Train.toString(Train.java:74)
    at java.lang.String.valueOf(String.java:2994)
    at java.lang.StringBuilder.append(StringBuilder.java:131)
    at com.slandshow.models.Seat.toString(Seat.java:72)
    at java.lang.String.valueOf(String.java:2994)
    at java.lang.StringBuilder.append(StringBuilder.java:131)
    at java.util.AbstractCollection.toString(AbstractCollection.java:462)
    at org.hibernate.collection.internal.PersistentSet.toString(PersistentSet.java:303)
    at java.lang.String.valueOf(String.java:2994)
    at java.lang.StringBuilder.append(StringBuilder.java:131)
    at com.slandshow.models.Train.toString(Train.java:74)
    at java.lang.String.valueOf(String.java:2994)
    at java.lang.StringBuilder.append(StringBuilder.java:131)
    at com.slandshow.models.Seat.toString(Seat.java:72)
    at java.lang.String.valueOf(String.java:2994)

Когда я просто вывожу другие поля Train'а - то всё ок, проблему Connection leak detected: there are 1 unclosed connections upon shutting down pool jdbc:mysql://localhost:3306/RattlerStation вызывает именно train.getSeats();

Вот мой Hibernate конфи, просто вдруг дело в нём

 @Configuration
    @EnableTransactionManagement
    @ComponentScan({"com.slandshow"})
    @PropertySource(value = {"classpath:application.properties"})
    public class HibernateConfig {
        private static final String MODEL_PACKAGE = "com.slandshow.models";
        private static final String JDBC_DRIVER_CLASS_NAME_PROPERTY = "jdbc.driverClassName";
        private static final String JDBC_URL_PROPERTY = "jdbc.url";
        private static final String HIBERNATE_DIALECT_PROPERTY = "hibernate.dialect";
        private static final String HIBERNATE_SHOW_SQL_PROPERTY = "hibernate.show_sql";
        private static final String HIBERNATE_FORMAT_SQL_PROPERTY = "hibernate.format_sql";

        @Autowired
        private Environment environment;
        @Bean
        public LocalSessionFactoryBean sessionFactory() {
            LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
            sessionFactory.setDataSource(dataSource());
            sessionFactory.setPackagesToScan(MODEL_PACKAGE);
            sessionFactory.setHibernateProperties(hibernateProperties());
            Properties property = new Properties();
            property.put("hibernate.id.new_generator_mappings", "false");
            sessionFactory.setHibernateProperties(property);
            return sessionFactory;
        }
        @Bean
        public DataSource dataSource() {
            DriverManagerDataSource dataSource = new DriverManagerDataSource();
            dataSource.setDriverClassName(environment.getRequiredProperty(JDBC_DRIVER_CLASS_NAME_PROPERTY));
            dataSource.setUrl(environment.getRequiredProperty(JDBC_URL_PROPERTY));
            dataSource.setUsername("root");
            dataSource.setPassword("12345");
            return dataSource;
        }
        private Properties hibernateProperties() {
            Properties properties = new Properties();
            properties.put(HIBERNATE_DIALECT_PROPERTY, environment.getRequiredProperty(HIBERNATE_DIALECT_PROPERTY));
            properties.put(HIBERNATE_SHOW_SQL_PROPERTY, environment.getRequiredProperty(HIBERNATE_SHOW_SQL_PROPERTY));
            properties.put(HIBERNATE_FORMAT_SQL_PROPERTY, environment.getRequiredProperty(HIBERNATE_FORMAT_SQL_PROPERTY));
            return properties;
        }
        @Bean
        @Autowired
        public HibernateTransactionManager transactionManager(SessionFactory s) {
            HibernateTransactionManager txManager = new HibernateTransactionManager();
            txManager.setSessionFactory(s);
            return txManager;
        }
    }

Что же я сделал не так?

Answer 1

toString() плохо переопределен и зацикливается переходя по ссылкам.

@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)

поможет, если нужно вызывать getSeats() когда сессия уже не доступна

READ ALSO
Транспортный слой приложения

Транспортный слой приложения

Задумал реализовать клиент-серверное приложение на Android с применением архитектуры MVPТакже добавить транспортный слой в приложения, который...

193
HTML+JS+CSS.Как наложить div блок на другой div при нажатии на кнопку?

HTML+JS+CSS.Как наложить div блок на другой div при нажатии на кнопку?

Имеется вот такой шаблончик https://codepenio/psyapathy/pen/wENPgX

208
Проблема с jQuery в IE11

Проблема с jQuery в IE11

Не работает следующий код в IE11, а так же если повесить событие через onclickПри этом в chrome работает

165