Недавно я настроил второе соединение с БД в своем приложении, и все работает нормально, пока я не попытался получить лениво инициализированную коллекцию из одного объекта (IncomeTariff). У меня есть два отдельных источника данных, менеджеры сущностей и т. Д. Важно то, что LazyInitializationException возникает только тогда, когда я получаю сущность из недавно добавленной БД. Более того, когда я переместил таблицу с IncomeTariff в старую БД, я смог получить эту коллекцию без каких-либо проблем. Я пробовал много вещей: добавив @Transactional, используя Hibernate.initialize() и т. Д. В журналах просто выглядит, что hibernate закрывает сессию слишком рано, и я просто не могу заставить ее работать. Надеюсь, что фрагменты кода сделают это более понятным. КонфигурацияLazyInitializationException при подключении к двум базам данных
Источники данных:
<!-- 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.first.repository"})
@EnableTransactionManagement
public class JpaConfig {
@Autowired
@Qualifier("dataSource1")
private DataSource dataSource;
@Bean
@Primary
public EntityManagerFactory entityManagerFactory() {
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
vendorAdapter.setGenerateDdl(false);
vendorAdapter.setShowSql(false);
vendorAdapter.setDatabasePlatform("MYSQL");
LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();
factoryBean.setDataSource(dataSource);
factoryBean.setPersistenceUnitName("unit1");
factoryBean.setJpaProperties(prepareProperties());
factoryBean.afterPropertiesSet();
return factoryBean.getObject();
}
@Bean
@Primary
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");
return prop;
}
}
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;
}
}
BillingAccount объект класса из старой БД, которая работает отлично:
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "type", discriminatorType = DiscriminatorType.STRING)
@Table(name = "api_billing_account")
public class BillingAccount extends Entity {
@OneToMany(mappedBy = "billingAccount")
private List<User> users = new ArrayList<>();
public List<User> getUsers() {
return users;
}
public void setUsers(List<User> users) {
this.users = users;
}
}
И IncomeTariffService, как вы можете видеть сейчас метод findAllTariffs() не имеет никакого смысла, я изменил его, чтобы показать, что выборка пользователей из BillingAccount отлично работает. Хранилища только обычные пружинные данных хранилища на основе:
@Service
@Transactional
public class IncomeTariffService {
@Autowired
private final IncomeTariffRepository incomeTariffRepository; // fetching data from new DB
@Autowired
private BillingAccountRepository billingAccountRepository; //fetching data from old DB
private static final Logger logger = LoggerFactory.getLogger(IncomeTariffService.class);
public List<IncomeTariff> findAllTariffs() {
BillingAccount findOne = billingAccountRepository.findOne(666000);
logger.info("TEST");
logger.info("" + findOne.getUsers().size());
return null;
}
public List<IncomeTariffEntry> findPositions(Integer tariffId) {
IncomeTariff findOne = incomeTariffRepository.findOne(tariffId);
logger.info("TEST");
List<IncomeTariffEntry> incomeTariffEntries = findOne.getIncomeTariffEntries();
logger.info("" + incomeTariffEntries.size());
return incomeTariffEntries;
}
}
А вот что происходит в журналах, когда я выборка пользователей Список frombilling счет:
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 [[email protected]]
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
Я могу получить размер сбора пользователей и, похоже, сделка закрыта в конце метода
Вот что происходит, когда я выборка IncomeTariff (без @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 [[email protected]]
13:09:31.316 [http-nio-8080-exec-51] DEBUG o.s.orm.jpa.JpaTransactionManager - Closing JPA EntityManager [[email protected]] 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
и с аннотацией @Transactional:
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 [[email protected]]
12:24:14.601 [http-nio-8080-exec-42] DEBUG o.s.orm.jpa.JpaTransactionManager - Closing JPA EntityManager [[email protected]] 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 [[email protected]]
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
Сделка была закрыта до «TEST» даже вошел, а затем это просто невозможно, чтобы получить коллекцию от лица. Как я уже упоминал ранее, когда я переместил доход в старую БД, все работало, поэтому, возможно, что-то не так с моей конфигурацией, но я борюсь с этим в течение двух дней, и у меня нет идей.
присоединиться принести свою коллекцию в запросе непосредственно –