Java LazyInitializationException连接到两个数据库时发生异常

Java LazyInitializationException连接到两个数据库时发生异常,java,spring,hibernate,jpa,spring-data,Java,Spring,Hibernate,Jpa,Spring Data,最近,我在我的应用程序中配置了第二个DB连接,在我尝试从一个实体(IncomeTariff)获取延迟初始化的集合之前,一切都正常工作。我有两个独立的数据源,实体管理器等。重要的是,LazyInitializationException只有在我从新添加的数据库中获取实体时才会发生。更重要的是,当我将带有IncomeTariff的表移动到旧数据库时,我能够毫无问题地获得这个集合。我尝试了很多方法:添加@Transactional,使用Hibernate.initialize()等等。在日志中,Hib

最近,我在我的应用程序中配置了第二个DB连接,在我尝试从一个实体(IncomeTariff)获取延迟初始化的集合之前,一切都正常工作。我有两个独立的数据源,实体管理器等。重要的是,LazyInitializationException只有在我从新添加的数据库中获取实体时才会发生。更重要的是,当我将带有IncomeTariff的表移动到旧数据库时,我能够毫无问题地获得这个集合。我尝试了很多方法:添加@Transactional,使用Hibernate.initialize()等等。在日志中,Hibernate似乎太早关闭了会话,我就是无法让它工作。我希望代码片段能让这一点更清楚

数据源配置:

    <!-- data source 1 -->
<bean id="dataSource1" class="org.apache.tomcat.jdbc.pool.DataSource" destroy-method="close">
    <property name="driverClassName" value="${mysql.jdbc.driver}" />
    <property name="url" value="${mysql.jdbc.uri}" />
    <property name="username" value="${mysql.jdbc.username}" />
    <property name="password" value="${mysql.jdbc.password}" />
    <property name="maxActive" value="${mysql.jdbc.maxActive}" />
    <property name="testOnBorrow" value="true" />
    <property name="testOnReturn" value="true" />
    <property name="testWhileIdle" value="true" />
    <property name="timeBetweenEvictionRunsMillis" value="30000" />
    <property name="validationQuery" value="select 1" />
    <property name="validationInterval" value="30000" />
    <property name="jdbcInterceptors"
        value="org.apache.tomcat.jdbc.pool.interceptor.ConnectionState;org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer" />
    <property name="jmxEnabled" value="true" />
    <property name="logAbandoned" value="true" />
    <property name="maxWait" value="10000" />
    <property name="minEvictableIdleTimeMillis" value="30000" />
    <property name="removeAbandoned" value="true" />
    <property name="removeAbandonedTimeout" value="1200" />
</bean>

<bean id="defaultJdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"
    p:dataSource-ref="dataSource1" primary="true" />

<bean id="defaultNamedParameterJdbcTemplate"
    class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate">
    <constructor-arg ref="dataSource1" />
</bean>

<!-- data source 2 -->
<bean id="dataSource2" class="org.apache.tomcat.jdbc.pool.DataSource" destroy-method="close">
    <property name="driverClassName" value="${mysql.jdbc.driver}" />
    <property name="url" value="${mysql.ds2.uri}" />
    <property name="username" value="${mysql.ds2.username}" />
    <property name="password" value="${mysql.ds2.password}" />
    <property name="maxActive" value="${mysql.jdbc.maxActive}" />
    <property name="testOnBorrow" value="true" />
    <property name="testOnReturn" value="true" />
    <property name="testWhileIdle" value="true" />
    <property name="timeBetweenEvictionRunsMillis" value="30000" />
    <property name="validationQuery" value="select 1" />
    <property name="validationInterval" value="30000" />
    <property name="jdbcInterceptors"
        value="org.apache.tomcat.jdbc.pool.interceptor.ConnectionState;org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer" />
    <property name="jmxEnabled" value="true" />
    <property name="logAbandoned" value="true" />
    <property name="maxWait" value="10000" />
    <property name="minEvictableIdleTimeMillis" value="30000" />
    <property name="removeAbandoned" value="true" />
    <property name="removeAbandonedTimeout" value="1200" />
</bean>
新数据库的JPA配置:

@Configuration
@EnableJpaRepositories(basePackages = {
    "pl.application.second.repository" }, entityManagerFactoryRef = "secondEntityManagerFactory", transactionManagerRef = "secondTransactionManager")
@EnableTransactionManagement
public class NewJpaConfig {

@Autowired
@Qualifier("dataSource2")
private DataSource dataSource;

@Bean(name = "secondEntityManagerFactory")
public EntityManagerFactory entityManagerFactory() {
    HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
    vendorAdapter.setGenerateDdl(false);
    vendorAdapter.setShowSql(true);
    vendorAdapter.setDatabasePlatform("MYSQL");

    LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();
    factoryBean.setDataSource(dataSource);
    factoryBean.setJpaProperties(prepareProperties());
    factoryBean.setPackagesToScan("pl.application.operator", "pl.application.common.db.converters");
    factoryBean.setPersistenceUnitName("unit2");
    factoryBean.setPersistenceProviderClass(HibernatePersistenceProvider.class);
    factoryBean.afterPropertiesSet();

    return factoryBean.getObject();
}

@Bean(name = "secondTransactionManager")
public PlatformTransactionManager transactionManager() {
    JpaTransactionManager txManager = new JpaTransactionManager();
    txManager.setEntityManagerFactory(entityManagerFactory());
    return txManager;
}

private Properties prepareProperties() {
    Properties prop = new Properties();
    prop.put("hibernate.cache.use_second_level_cache", true);
    prop.put("hibernate.cache.use_query_cache", false);
    prop.put("hibernate.cache.region.factory_class", "org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory");
    prop.put("hibernate.cache.provider_class", "org.hibernate.cache.SingletonEhCacheProvider");
    prop.put("javax.persistence.validation.mode", "none");
    prop.put("hibernate.connection.autocommit", "false");
    prop.put("javax.persistence.lock.timeout", "90000");
    return prop;
}

}
导致问题的IncomeTariff类:

@Entity
@Table(name = "income_tariff")
public class IncomeTariff extends Entity {

@OneToMany(mappedBy = "incomeTariff")
private List<IncomeTariffEntry> incomeTariffEntries;

public List<IncomeTariffEntry> getIncomeTariffEntries() {
    return incomeTariffEntries;
}

public void setIncomeTariffEntries(List<IncomeTariffEntry> incomeTariffEntries) {
    this.incomeTariffEntries = incomeTariffEntries;
}

    @Override
public int hashCode() {
    int hash = 7;
    hash = 23 * hash + Objects.hashCode(this.getId());
    return hash;
}

@Override
public boolean equals(Object obj) {
    if (obj == null) {
        return false;
    }
    if (getClass() != obj.getClass()) {
        return false;
    }
    final IncomeTariff other = (IncomeTariff) obj;
    if (!Objects.equals(this.getId(), other.getId())) {
        return false;
    }
    return true;
}

}
我能够得到用户集合的大小,并且看起来事务在方法的末尾被关闭了

下面是我获取IncomeTariff(不带@Transactional注释)时发生的情况:

并使用@Transactional注释:

13:09:31.285 [http-nio-8080-exec-51] TRACE org.hibernate.type.CollectionType - Created collection wrapper: [pl.application.operator.pricelist.income.IncomeTariff.incomeTariffEntries#1]
13:09:31.288 [http-nio-8080-exec-51] DEBUG o.s.orm.jpa.JpaTransactionManager - Initiating transaction commit
13:09:31.288 [http-nio-8080-exec-51] DEBUG o.s.orm.jpa.JpaTransactionManager - Committing JPA transaction on EntityManager [org.hibernate.jpa.internal.EntityManagerImpl@427c27e2]
13:09:31.316 [http-nio-8080-exec-51] DEBUG o.s.orm.jpa.JpaTransactionManager - Closing JPA EntityManager [org.hibernate.jpa.internal.EntityManagerImpl@427c27e2] after transaction
13:09:31.317 [http-nio-8080-exec-51] DEBUG o.s.o.jpa.EntityManagerFactoryUtils - Closing JPA EntityManager
13:09:31.317 [http-nio-8080-exec-51] INFO  p.s.a.c.t.s.IncomeTariffService - TEST
13:09:31.342 [http-nio-8080-exec-51] ERROR p.s.a.r.c.e.GlobalExceptionHandler - failed to lazily initialize a collection of role: pl.application.operator.pricelist.income.IncomeTariff.incomeTariffEntries, could not initialize proxy - no Session
12:24:14.599 [http-nio-8080-exec-42] TRACE org.hibernate.type.CollectionType - Created collection wrapper: [pl.application.operator.pricelist.income.IncomeTariff.incomeTariffEntries#1]
12:24:14.600 [http-nio-8080-exec-42] DEBUG o.s.orm.jpa.JpaTransactionManager - Initiating transaction commit
12:24:14.600 [http-nio-8080-exec-42] DEBUG o.s.orm.jpa.JpaTransactionManager - Committing JPA transaction on EntityManager [org.hibernate.jpa.internal.EntityManagerImpl@4b5b7e77]
12:24:14.601 [http-nio-8080-exec-42] DEBUG o.s.orm.jpa.JpaTransactionManager - Closing JPA EntityManager [org.hibernate.jpa.internal.EntityManagerImpl@4b5b7e77] after transaction
12:24:14.601 [http-nio-8080-exec-42] DEBUG o.s.o.jpa.EntityManagerFactoryUtils - Closing JPA EntityManager
12:24:14.601 [http-nio-8080-exec-42] DEBUG o.s.orm.jpa.JpaTransactionManager - Resuming suspended transaction after completion of inner transaction
12:24:14.601 [http-nio-8080-exec-42] INFO  p.s.a.c.t.s.IncomeTariffService - TEST
12:24:14.604 [http-nio-8080-exec-42] DEBUG o.s.orm.jpa.JpaTransactionManager - Initiating transaction rollback
12:24:14.604 [http-nio-8080-exec-42] DEBUG o.s.orm.jpa.JpaTransactionManager - Rolling back JPA transaction on EntityManager [org.hibernate.jpa.internal.EntityManagerImpl@5e7c4044]
12:24:14.606 [http-nio-8080-exec-42] DEBUG o.s.orm.jpa.JpaTransactionManager - Not closing pre-bound JPA EntityManager after transaction
12:24:14.612 [http-nio-8080-exec-42] ERROR p.s.a.r.c.e.GlobalExceptionHandler - failed to lazily initialize a collection of role: pl.application.operator.pricelist.income.IncomeTariff.incomeTariffEntries, could not initialize proxy - no Session

事务在“测试”被记录之前就被关闭了,这样就不可能从实体中获取集合。正如我之前提到的,当我将收入税转移到旧DB时,一切都正常,因此,我的配置可能有问题,但我已经为此挣扎了两天,我已经没有主意了。

由于您使用的是两个事务管理器,您可能需要在@Transactional注释中指定要使用的事务管理器(请参阅)

例如,我将在类级别删除@Transactional,并在每个find方法上方添加特定于事务管理器的@Transactional()

比如:

@Transactional("secondTransactionManager)
public List<IncomeTariff> findAllTariffs() {}
@Transactional(“secondTransactionManager)
公共列表findAllTariffs(){}
对于服务级别的事务,如果集合到达事务边界之外,则会出现此类异常。请尝试将集合设置为非惰性或将事务向上移动,如业务层

希望这有帮助


A.

直接在查询中加入获取您的集合非常感谢!将事务管理器添加到@Transactional helped:)
11:33:48.988 [http-nio-8080-exec-33] TRACE org.hibernate.type.CollectionType - Created collection wrapper: [pl.application.billing.model.BillingAccount.users#666000]
11:33:48.989 [http-nio-8080-exec-33] INFO  p.s.a.c.t.s.IncomeTariffService - TEST
11:33:48.990 [http-nio-8080-exec-33] TRACE o.h.type.descriptor.sql.BasicBinder - binding parameter [1] as [INTEGER] - [666000]
11:33:48.997 [http-nio-8080-exec-33] INFO  p.s.a.c.t.s.IncomeTariffService - 0
11:33:48.997 [http-nio-8080-exec-33] DEBUG o.s.orm.jpa.JpaTransactionManager - Initiating transaction commit
11:33:48.997 [http-nio-8080-exec-33] DEBUG o.s.orm.jpa.JpaTransactionManager - Committing JPA transaction on EntityManager [org.hibernate.jpa.internal.EntityManagerImpl@72eaf768]
11:33:48.999 [http-nio-8080-exec-33] DEBUG o.s.orm.jpa.JpaTransactionManager - Not closing pre-bound JPA EntityManager after transaction
11:33:49.001 [http-nio-8080-exec-33] DEBUG o.s.o.j.s.OpenEntityManagerInViewFilter - Closing JPA EntityManager in OpenEntityManagerInViewFilter
11:33:49.001 [http-nio-8080-exec-33] DEBUG o.s.o.jpa.EntityManagerFactoryUtils - Closing JPA EntityManager
13:09:31.285 [http-nio-8080-exec-51] TRACE org.hibernate.type.CollectionType - Created collection wrapper: [pl.application.operator.pricelist.income.IncomeTariff.incomeTariffEntries#1]
13:09:31.288 [http-nio-8080-exec-51] DEBUG o.s.orm.jpa.JpaTransactionManager - Initiating transaction commit
13:09:31.288 [http-nio-8080-exec-51] DEBUG o.s.orm.jpa.JpaTransactionManager - Committing JPA transaction on EntityManager [org.hibernate.jpa.internal.EntityManagerImpl@427c27e2]
13:09:31.316 [http-nio-8080-exec-51] DEBUG o.s.orm.jpa.JpaTransactionManager - Closing JPA EntityManager [org.hibernate.jpa.internal.EntityManagerImpl@427c27e2] after transaction
13:09:31.317 [http-nio-8080-exec-51] DEBUG o.s.o.jpa.EntityManagerFactoryUtils - Closing JPA EntityManager
13:09:31.317 [http-nio-8080-exec-51] INFO  p.s.a.c.t.s.IncomeTariffService - TEST
13:09:31.342 [http-nio-8080-exec-51] ERROR p.s.a.r.c.e.GlobalExceptionHandler - failed to lazily initialize a collection of role: pl.application.operator.pricelist.income.IncomeTariff.incomeTariffEntries, could not initialize proxy - no Session
12:24:14.599 [http-nio-8080-exec-42] TRACE org.hibernate.type.CollectionType - Created collection wrapper: [pl.application.operator.pricelist.income.IncomeTariff.incomeTariffEntries#1]
12:24:14.600 [http-nio-8080-exec-42] DEBUG o.s.orm.jpa.JpaTransactionManager - Initiating transaction commit
12:24:14.600 [http-nio-8080-exec-42] DEBUG o.s.orm.jpa.JpaTransactionManager - Committing JPA transaction on EntityManager [org.hibernate.jpa.internal.EntityManagerImpl@4b5b7e77]
12:24:14.601 [http-nio-8080-exec-42] DEBUG o.s.orm.jpa.JpaTransactionManager - Closing JPA EntityManager [org.hibernate.jpa.internal.EntityManagerImpl@4b5b7e77] after transaction
12:24:14.601 [http-nio-8080-exec-42] DEBUG o.s.o.jpa.EntityManagerFactoryUtils - Closing JPA EntityManager
12:24:14.601 [http-nio-8080-exec-42] DEBUG o.s.orm.jpa.JpaTransactionManager - Resuming suspended transaction after completion of inner transaction
12:24:14.601 [http-nio-8080-exec-42] INFO  p.s.a.c.t.s.IncomeTariffService - TEST
12:24:14.604 [http-nio-8080-exec-42] DEBUG o.s.orm.jpa.JpaTransactionManager - Initiating transaction rollback
12:24:14.604 [http-nio-8080-exec-42] DEBUG o.s.orm.jpa.JpaTransactionManager - Rolling back JPA transaction on EntityManager [org.hibernate.jpa.internal.EntityManagerImpl@5e7c4044]
12:24:14.606 [http-nio-8080-exec-42] DEBUG o.s.orm.jpa.JpaTransactionManager - Not closing pre-bound JPA EntityManager after transaction
12:24:14.612 [http-nio-8080-exec-42] ERROR p.s.a.r.c.e.GlobalExceptionHandler - failed to lazily initialize a collection of role: pl.application.operator.pricelist.income.IncomeTariff.incomeTariffEntries, could not initialize proxy - no Session
@Transactional("secondTransactionManager)
public List<IncomeTariff> findAllTariffs() {}