2016-09-29 8 views
0

У меня есть следующая служба, которая просто регистрирует сообщение об ошибке в базе данных. Когда у меня нет метода @Transactional, соединение остается активным до тех пор, пока все соединения не будут исчерпаны. Все вызовы StoredProcedureQuery, которые возвращают результат, не имеют этой проблемы.Соединение не выпущено для StoredProcedureQuery без @Transactional

Зачем мне нужно отметить метод как @Transactional, чтобы он освободил соединение?

@Service 
public class SSOErrorLogServiceImpl implements SSOErrorLogService { 

    @PersistenceContext 
    private EntityManager em; 

    @Override 
    @Transactional 
    public void logError(String errorMessage, String request){ 
     StoredProcedureQuery proc = em.createNamedStoredProcedureQuery("dbo.spSSOLogError"); 
     proc.setParameter("errorMessage", errorMessage); 
     proc.setParameter("request", request); 
     proc.execute(); 
    } 
} 

DataConfig

public LocalContainerEntityManagerFactoryBean entityManagerFactory() { 
    LocalContainerEntityManagerFactoryBean entityManagerFactory 
      = new LocalContainerEntityManagerFactoryBean(); 

    entityManagerFactory.setDataSource(reflexDataSource()); 
    entityManagerFactory.setPackagesToScan("com.company.platform.jpa"); 
    entityManagerFactory.setJpaVendorAdapter(jpaVendorAdapter()); 

    Properties additionalProperties = new Properties(); 
    additionalProperties.put("eclipselink.weaving", "false"); 

    entityManagerFactory.setJpaProperties(additionalProperties); 

    return entityManagerFactory; 
} 

@Bean 
public HikariDataSource reflexDataSource() { 
    HikariDataSource dataSource = new HikariDataSource(); 

    dataSource.setLeakDetectionThreshold(20000); 
    dataSource.setMaximumPoolSize(20); 
    dataSource.setConnectionTimeout(5000); 
    dataSource.setRegisterMbeans(false); 
    dataSource.setInitializationFailFast(false); 
    dataSource.setDriverClassName(driver); 
    dataSource.setJdbcUrl(url); 
    dataSource.setUsername(user); 
    dataSource.setPassword(password); 
    return dataSource; 
} 

Бревна без операции (выдержка)

[EL Finer]: connection: 2016-09-30 14:33:16.955--ServerSession(317574415)--Thread(Thread[Test worker,5,main])--client acquired: 1151058631 
[EL Finer]: transaction: 2016-09-30 14:33:16.962--ClientSession(1151058631)--Thread(Thread[Test worker,5,main])--acquire unit of work: 544160013 
[EL Finest]: query: 2016-09-30 14:33:16.962--UnitOfWork(544160013)--Thread(Thread[Test worker,5,main])--Execute query ResultSetMappingQuery(name="dbo.spSSOLogError") 
[EL Finest]: connection: 2016-09-30 14:33:16.963--ServerSession(317574415)--Connection(1107704332)--Thread(Thread[Test worker,5,main])--Connection acquired from connection pool [read]. 
[EL Finest]: connection: 2016-09-30 14:33:16.963--ServerSession(317574415)--Thread(Thread[Test worker,5,main])--reconnecting to external connection pool 
[EL Fine]: sql: 2016-09-30 14:33:16.963--ServerSession(317574415)--Connection(539538496)--Thread(Thread[Test worker,5,main])--EXECUTE dbo.spSSOLogError @errorMessage = ?, @request = ? 
    bind => [Message, Request] 
2016-09-30 14:33:16,984 | TRACE | org.springframework.test.context.TestContextManager:394 - afterTestMethod(): instance [[email protected]314c32e8], method [public void com.somecompany.platform.jpa.ssoerrorlog.SSOErrorLogServiceTest.test_logError()], exception [null] 
2016-09-30 14:33:16,985 | DEBUG | org.springframework.test.context.support.DirtiesContextTestExecutionListener:94 - After test method: context [[email protected] testClass = SSOErrorLogServiceTest, testInstance = [email protected]314c32e8, testMethod = [email protected], testException = [null], mergedContextConfiguration = [[email protected] testClass = SSOErrorLogServiceTest, locations = '{}', classes = '{class com.somecompany.platform.jpa.ssoerrorlog.SSOErrorLogServiceTest$Config}', contextInitializerClasses = '[]', activeProfiles = '{}', contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader', parent = [null]]], class dirties context [false], class mode [null], method dirties context [false]. 
2016-09-30 14:33:16,985 | TRACE | org.springframework.test.context.TestContextManager:437 - afterTestClass(): class [class com.somecompany.platform.jpa.ssoerrorlog.SSOErrorLogServiceTest] 
2016-09-30 14:33:16,986 | DEBUG | org.springframework.test.context.support.DirtiesContextTestExecutionListener:126 - After test class: context [[email protected] testClass = SSOErrorLogServiceTest, testInstance = [null], testMethod = [null], testException = [null], mergedContextConfiguration = [[email protected] testClass = SSOErrorLogServiceTest, locations = '{}', classes = '{class com.somecompany.platform.jpa.ssoerrorlog.SSOErrorLogServiceTest$Config}', contextInitializerClasses = '[]', activeProfiles = '{}', contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader', parent = [null]]], dirtiesContext [false]. 

Бревна с @Transaction

[EL Finer]: transaction: 2016-09-30 14:30:50.747--UnitOfWork(1448667590)--Thread(Thread[Test worker,5,main])--begin unit of work flush 
[EL Finer]: transaction: 2016-09-30 14:30:50.747--UnitOfWork(1448667590)--Thread(Thread[Test worker,5,main])--end unit of work flush 
[EL Finest]: query: 2016-09-30 14:30:50.747--UnitOfWork(1448667590)--Thread(Thread[Test worker,5,main])--Execute query ResultSetMappingQuery(name="dbo.spSSOLogError") 
[EL Finest]: connection: 2016-09-30 14:30:50.748--ServerSession(1432568628)--Connection(708660831)--Thread(Thread[Test worker,5,main])--Connection acquired from connection pool [default]. 
[EL Finer]: transaction: 2016-09-30 14:30:50.748--ClientSession(287210054)--Connection(708660831)--Thread(Thread[Test worker,5,main])--begin transaction 
[EL Finest]: connection: 2016-09-30 14:30:50.748--ClientSession(287210054)--Thread(Thread[Test worker,5,main])--reconnecting to external connection pool 
[EL Fine]: sql: 2016-09-30 14:30:50.75--ClientSession(287210054)--Connection(29007067)--Thread(Thread[Test worker,5,main])--EXECUTE dbo.spSSOLogError @errorMessage = ?, @request = ? 
    bind => [Message, Request] 
2016-09-30 14:30:50,772 | TRACE | org.springframework.transaction.interceptor.TransactionAspectSupport:519 - Completing transaction for [com.somecompany.platform.jpa.ssoerrorlog.SSOErrorLogServiceImpl.logError] 
2016-09-30 14:30:50,772 | TRACE | org.springframework.transaction.support.AbstractPlatformTransactionManager:926 - Triggering beforeCommit synchronization 
2016-09-30 14:30:50,772 | TRACE | org.springframework.transaction.support.AbstractPlatformTransactionManager:939 - Triggering beforeCompletion synchronization 
2016-09-30 14:30:50,772 | DEBUG | org.springframework.transaction.support.AbstractPlatformTransactionManager:755 - Initiating transaction commit 
2016-09-30 14:30:50,773 | DEBUG | org.springframework.orm.jpa.JpaTransactionManager:512 - Committing JPA transaction on EntityManager [[email protected]] 
[EL Finer]: transaction: 2016-09-30 14:30:50.773--UnitOfWork(1448667590)--Thread(Thread[Test worker,5,main])--begin unit of work commit 
[EL Finer]: transaction: 2016-09-30 14:30:50.773--ClientSession(287210054)--Connection(29007067)--Thread(Thread[Test worker,5,main])--commit transaction 
[EL Finest]: connection: 2016-09-30 14:30:50.775--ServerSession(1432568628)--Connection(708660831)--Thread(Thread[Test worker,5,main])--Connection released to connection pool [default]. 
[EL Finer]: transaction: 2016-09-30 14:30:50.775--UnitOfWork(1448667590)--Thread(Thread[Test worker,5,main])--end unit of work commit 
[EL Finer]: transaction: 2016-09-30 14:30:50.775--UnitOfWork(1448667590)--Thread(Thread[Test worker,5,main])--resume unit of work 
2016-09-30 14:30:50,775 | TRACE | org.springframework.transaction.support.AbstractPlatformTransactionManager:952 - Triggering afterCommit synchronization 
2016-09-30 14:30:50,775 | TRACE | org.springframework.transaction.support.AbstractPlatformTransactionManager:968 - Triggering afterCompletion synchronization 
2016-09-30 14:30:50,775 | TRACE | org.springframework.transaction.support.TransactionSynchronizationManager:331 - Clearing transaction synchronization 
2016-09-30 14:30:50,776 | TRACE | org.springframework.transaction.support.TransactionSynchronizationManager:243 - Removed value [[email protected]] for key [org[email protected]33d8b566] from thread [Test worker] 
2016-09-30 14:30:50,776 | TRACE | org.springframework.transaction.support.TransactionSynchronizationManager:243 - Removed value [[email protected]] for key [JDBC URL = jdbc:sqlserver://somehost:1433;databaseName=Database, Username = test, partitions = 1, max (per partition) = 10, min (per partition) = 0, idle max age = 60 min, idle test period = 240 min, strategy = DEFAULT] from thread [Test worker] 
2016-09-30 14:30:50,776 | DEBUG | org.springframework.orm.jpa.JpaTransactionManager:600 - Closing JPA EntityManager [[email protected]] after transaction 
2016-09-30 14:30:50,776 | DEBUG | org.springframework.orm.jpa.EntityManagerFactoryUtils:432 - Closing JPA EntityManager 
[EL Finer]: transaction: 2016-09-30 14:30:50.776--UnitOfWork(1448667590)--Thread(Thread[Test worker,5,main])--release unit of work 
[EL Finer]: connection: 2016-09-30 14:30:50.776--ClientSession(287210054)--Thread(Thread[Test worker,5,main])--client released 
2016-09-30 14:30:50,776 | TRACE | org.springframework.test.context.TestContextManager:394 - afterTestMethod(): instance [[email protected]314c32e8], method [public void com.somecompany.platform.jpa.ssoerrorlog.SSOErrorLogServiceTest.test_logError()], exception [null] 
2016-09-30 14:30:50,777 | DEBUG | org.springframework.test.context.support.DirtiesContextTestExecutionListener:94 - After test method: context [[email protected] testClass = SSOErrorLogServiceTest, testInstance = [email protected]314c32e8, testMethod = [email protected], testException = [null], mergedContextConfiguration = [[email protected] testClass = SSOErrorLogServiceTest, locations = '{}', classes = '{class com.somecompany.platform.jpa.ssoerrorlog.SSOErrorLogServiceTest$Config}', contextInitializerClasses = '[]', activeProfiles = '{}', contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader', parent = [null]]], class dirties context [false], class mode [null], method dirties context [false]. 
2016-09-30 14:30:50,777 | TRACE | org.springframework.test.context.TestContextManager:437 - afterTestClass(): class [class com.somecompany.platform.jpa.ssoerrorlog.SSOErrorLogServiceTest] 
2016-09-30 14:30:50,778 | DEBUG | org.springframework.test.context.support.DirtiesContextTestExecutionListener:126 - After test class: context [[email protected] testClass = SSOErrorLogServiceTest, testInstance = [null], testMethod = [null], testException = [null], mergedContextConfiguration = [[email protected] testClass = SSOErrorLogServiceTest, locations = '{}', classes = '{class com.somecompany.platform.jpa.ssoerrorlog.SSOErrorLogServiceTest$Config}', contextInitializerClasses = '[]', activeProfiles = '{}', contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader', parent = [null]]], dirtiesContext [false]. 
+0

Как вы указали источник данных, может ли он иметь ограничение на повторное использование соединения? 366102 упоминает что-то подобное, но я ранее под впечатлением кода закрывал все соединения в блоках finally. Можете ли вы включить отладку, которая отпечатывается там, где стеки были получены из-за ошибочных соединений? Некоторые серверы могут обрабатывать его, но я не знаю, является ли это вариантом в вашей настройке. – Chris

+0

Я не думаю, что это предел повторного использования, потому что самое первое соединение не освобождается, когда я запускаю его в тесте. Установив порог обнаружения утечки на источнике данных, я могу довольно быстро увидеть выход журнала, соединения которого не выпущены, но не смогли получить какой-либо вывод, который может указывать на причину. Я предполагаю, что это потому, что SP вставляет данные и требует @Transaction для фиксации. – blur0224

+0

Если нет внешней транзакции, она должна автоматически фиксироваться и освобождаться. Установите регистрацию на лучший и посмотрите, что может быть зарегистрировано. – Chris

ответ

2

ли попытаться изменить @PersistenceContext к @PersistanceUnit?

EntityManagers, полученный с помощью @PersistenceContext является Контейнером управляемого объект менеджер, как контейнер будет нести ответственность за управление «Entity Manager» в то время как EntityManagers, полученный с помощью @PersistenceUnit/entityManagerFactory.createEntityManager() является Применением управляемого объекта менеджер и разработчик должен управлять определенными вещами в коде (например, дл освобождая ресурсы, полученные EntityManager).