2014-12-15 1 views
8

В моем процессе Java Я подключения к MySql, используя следующую конфигурацию пружины:Когда соединения возвращаются в пул подключений с помощью диспетчера сущностей Spring JPA (Hibernate)?

@Configuration 
@EnableTransactionManagement 
@PropertySources({ @PropertySource("classpath:/myProperties1.properties"), @PropertySource("classpath:/myProperties2.properties") }) 
public class MyConfiguration { 

    @Autowired 
    protected Environment env; 

    /** 
    * @return EntityManagerFactory for use with Hibernate JPA provider 
    */ 
    @Bean(destroyMethod = "destroy") 
    public LocalContainerEntityManagerFactoryBean entityManagerFactory() { 
    LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean(); 
    em.setDataSource(dataSource()); 
    em.setJpaVendorAdapter(jpaVendorAdapter()); 
    em.setPersistenceUnitManager(persistenceUnitManager()); 

    return em; 
    } 

    /** 
    * 
    * @return jpaVendorAdapter that works in conjunction with the 
    *   persistence.xml 
    */ 
    @Bean 
    public JpaVendorAdapter jpaVendorAdapter() { 
    HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter(); 
    vendorAdapter.setDatabase(Database.valueOf(env.getProperty("jpa.database"))); 
    vendorAdapter.setDatabasePlatform(env.getProperty("jpa.dialect")); 
    vendorAdapter.setGenerateDdl(env.getProperty("jpa.generateDdl", Boolean.class, false)); 
    vendorAdapter.setShowSql(env.getProperty("jpa.showSql", Boolean.class, false)); 

    return vendorAdapter; 
    } 

    @Bean 
    public PersistenceUnitManager persistenceUnitManager() { 
    DefaultPersistenceUnitManager pum = new DefaultPersistenceUnitManager(); 
    pum.setPackagesToScan("com.app.dal"); 
    pum.setDefaultPersistenceUnitName("my-pu"); 
    pum.setPersistenceXmlLocations("classpath:/META-INF/persistence.xml"); 
    pum.setDefaultDataSource(dataSource()); 

    return pum; 
    } 

    @Bean(destroyMethod = "close") 
    public DataSource dataSource() { 
    Properties dsProps = new Properties(); 
    dsProps.put("driverClassName", env.getProperty("hikari.driverClassName")); 
    dsProps.put("username", env.getProperty("hikari.username")); 
    dsProps.put("password", env.getProperty("hikari.password")); 
    dsProps.put("jdbcUrl", env.getProperty("hikari.source.data.jdbcUrl")); 
    dsProps.put("connectionTimeout", env.getProperty("hikari.connectionTimeout", Integer.class)); 
    dsProps.put("idleTimeout", env.getProperty("hikari.idleTimeout", Integer.class)); 
    dsProps.put("maxLifetime", env.getProperty("hikari.maxLifetime", Integer.class)); 
    dsProps.put("maximumPoolSize", env.getProperty("hikari.maximumPoolSize.rtb.source", Integer.class)); 
    dsProps.put("leakDetectionThreshold", env.getProperty("hikari.leakDetectionThreshold", Integer.class)); 
    dsProps.put("jdbc4ConnectionTest", env.getProperty("hikari.jdbc4ConnectionTest", Boolean.class)); 

    HikariConfig config = new HikariConfig(dsProps); 
    HikariDataSource ds = new HikariDataSource(config); 

    return ds; 
    } 

    @Bean(name = "sourceTxMgr") 
    public PlatformTransactionManager sourceDatatransactionManager() { 
    JpaTransactionManager transactionManager = new JpaTransactionManager(); 
    transactionManager.setPersistenceUnitName("my-pu"); 
    transactionManager.setDataSource(dataSource()); 

    return transactionManager; 
    } 

    @Bean 
    public PersistencyManager persistencyManager() { 
    return new JpaPersistencyManager(); 
    } 

    @Bean 
    public PersistenceExceptionTranslationPostProcessor exceptionTranslation() { 
    return new PersistenceExceptionTranslationPostProcessor(); 
    } 

} 

субъект-менеджер впрыскивается в слой доступа к данным с помощью контейнера:

@PersistenceContext(type = PersistenceContextType.TRANSACTION, unitName = "my-pu") 
private EntityManager myEntityManager; 

И мой общедоступный методы бизнес-логики аннотируются с аннотацией @Transactional.

Насколько я понимаю, контейнер несет ответственность за то, что объект-менеджер возвращает соединения с пулом (в моем случае HikariCP) после выполнения транзакции, но я не нашел официальную документацию, описывающую, как соединения удалось. Может ли кто-нибудь объяснить это мне или предоставить хорошую ссылку, которая может объяснить, когда именно соединения возвращаются в пул при использовании такой конфигурации?

UPDATE:

Лучшая родственная информацию я мог придумать до сих пор (taken from here):

Сохранения контекста прокси, который реализует EntityManager не единственный компонент, необходимый для создания декларативной работы управления транзакциями , На самом деле необходимы три отдельных компонента:

Сам Транзакционная Аспект Менеджер транзакций Давайте рассмотрим каждый из них и посмотреть, как они взаимодействуют EntityManager Proxy.

Транзакционная Аспект

Транзакционная аспект является «вокруг» аспект, который вызывается до и после аннотированных методов бизнеса. Конкретным классом для реализации аспекта является TransactionInterceptor.

Транзакционная аспект имеет две основные функции:

В «до» момент, аспект обеспечивает точку крюка для определения, если бизнес метод собирается назвать должен работать в рамках текущей транзакции базы данных, или если необходимо начать новую отдельную транзакцию.

В момент «после» аспект должен решить, следует ли совершить транзакцию, откат или оставление на ходу.

В момент «до» сам Transactional Aspect не содержит логики решения, решение о начале новой транзакции при необходимости делегируется диспетчеру транзакций.

Сделка менеджер

Сделка менеджер должен дать ответ на два вопроса:

должен быть создан новый менеджер Entity? Следует ли начать новую транзакцию базы данных? Это необходимо решить в тот момент, когда вызывается логика Transactional Aspect 'before'.Менеджер транзакций будет принимать решение на основании:

тот факт, что одна транзакция уже продолжается или не устанавливается атрибут распространения транзакционного метода (например REQUIRES_NEW всегда начинает новую транзакцию) Если менеджер транзакций решает создать новый сделка, то это будет:

создать новый диспетчер сущностей связать менеджер сущности к текущей нити захватить соединение из пула соединений DB привязывания к текущему потоку диспетчера объектов и связи являются связанные с текущим потоком с использованием переменных ThreadLocal.

Они хранятся в потоке во время выполнения транзакции, и Менеджер транзакций должен очистить их, когда они больше не нужны.

Любые части программы, которым нужен текущий менеджер или соединение с узлом, могут извлекать их из потока. Один программный компонент, который выполняет именно это прокси-сервер EntityManager.

+0

Сомневаюсь, что контейнер отвечает за возврат соединений. Это Spring, которая отвечает за управление транзакциями через JPATransactionManager. Хорошим способом подтверждения было бы включить весну и журналы HikariCP и проверить ее. –

+0

Когда я говорю «Контейнер», я весенний контейнер, или, если быть более конкретным, Entity-Manager, которым управляет пружинный контейнер. http://docs.spring.io/spring/docs/current/spring-framework-reference/html/beans.html – forhas

ответ

15

Это совсем не сложно.

  1. Прежде всего вам нужно понять, что менеджер транзакций весны - это только transaction management abstraction. В вашем случае фактические транзакции происходят на уровне соединения JDBC.

  2. Все вызовы метода обработки @Transactional перехватываются Aspect TransactionInterceptor.

  3. TransactionIntreceptor делегирует управление транзакциями текущей конфигурации AbstractPlatformTransactionManager (JpaTransactionManager в вашем случае).

  4. JpaTransactionManager свяжет текущую текущую транзакцию Spring с EntityManager, поэтому все DAO, участвующие в текущей транзакции, имеют один и тот же контекст устойчивости.

  5. JpaTransactionManager просто использует EntityManager Transaction API для контроля операций:

    EntityTransaction tx = txObject.getEntityManagerHolder().getEntityManager().getTransaction(); 
    tx.commit(); 
    

    Транзакция API JPA просто делегирует вызов базового JDBC Connection совершать методы/отката.

  6. Когда операция выполняется (фиксации/отката), то org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction называет:

    transactionCoordinator().getTransactionContext().managedClose(); 
    

    который вызывает Hibernate Session (Entity Manager) близко.

  7. Соединение основного JDBC, поэтому срабатывает должны быть закрыто, а также:

    jdbcCoordinator.close(); 
    
  8. спящего режим имеет логический дескриптор соединения JDBC:

    @Override 
    public Connection close() { 
        LOG.tracev("Closing JDBC container [{0}]", this); 
        if (currentBatch != null) { 
        LOG.closingUnreleasedBatch(); 
         currentBatch.release(); 
        } 
        cleanup(); 
        return logicalConnection.close(); 
    } 
    
  9. Логическая связь обработка делегатов волоска к существующему настроенному провайдеру соединений (DataSourceConnectionProvider в вашем случае), который просто вызывает метод закрытия в соединении JDBC:

    @Override 
    public void closeConnection(Connection connection) throws SQLException { 
        connection.close(); 
    } 
    
  10. Как и любое другое connection pooling DataSource, соединение JDBC close просто возвращает соединение с пулом и не закрывает физическое соединение с базой данных. Это связано с тем, что объединение данных DataSource возвращает прокси-сервер JDBC Connection, который перехватывает все вызовы и делегирует закрытие логики управления пулом соединений.

+0

Приятно, но откуда вы получили эту информацию? Как я могу получить официальную документацию, объясняющую этот процесс, или, по крайней мере, объявить обязанности каждого компонента в цепочке? – forhas

+1

Я только что просмотрел исходный код. Я думаю, что это самая обновленная документация. –

+0

Я не совсем доволен, так как я искал официальную документацию, но, похоже, это лучший ответ, который я могу получить. Спасибо – forhas

Смежные вопросы