В моем java-процессе я подключаюсь к MySql, используя следующую конфигурацию spring:
@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();
}
}
Entity-Manager вводится на уровень доступа к данным контейнером:
@PersistenceContext(type = PersistenceContextType.TRANSACTION, unitName = "my-pu")
private EntityManager myEntityManager;
И мои общедоступные бизнес-логические методы аннотируются аннотацией @Transactional
.
Насколько я понимаю, контейнер отвечает за то, что сущность-менеджер возвращает соединения с пулом (в моем случае HikariCP) после выполнения транзакции, но я не нашел официальной документации, описывающей управление подключениями. Может ли кто-нибудь объяснить это мне или предоставить хорошую ссылку, которая может объяснить, когда именно соединения возвращаются в пул при использовании такой конфигурации?
UPDATE:
Лучшая связанная информация, которую я мог бы найти до сих пор (взято здесь):
Прокси-сервер контекста persistence, который реализует EntityManager, не является единственным компонентом, необходимым для выполнения декларативного управления транзакциями. На самом деле необходимы три отдельных компонента:
Прокси-сервер EntityManager Транзакционный аспект Менеджер транзакций Перейдем к каждому из них и посмотрим, как они взаимодействуют.
Трансакционный аспект
Transactional Aspect является аспектом "вокруг", который вызывается как до, так и после аннотированного бизнес-метода. Конкретным классом для реализации аспекта является TransactionInterceptor.
Транзакционный аспект имеет две основные обязанности:
В момент "до" этот аспект предоставляет точку привязки для определения того, должен ли бизнес-метод, который должен быть вызван, запускаться в рамках текущей транзакции базы данных или если необходимо начать новую отдельную транзакцию.
В момент "after" аспект должен решить, следует ли совершить транзакцию, откат или оставление на ходу.
В момент "до" сам Transactional Aspect не содержит логики принятия решения, решение о начале новой транзакции при необходимости делегируется диспетчеру транзакций.
Менеджер транзакций
Менеджер транзакций должен предоставить ответ на два вопроса:
должен ли быть создан новый Entity Manager? должна ли быть запущена новая транзакция базы данных? Это необходимо решить в момент, когда вызывается логика Transactional Aspect "before". Менеджер транзакций примет решение на основе:
тот факт, что одна транзакция уже продолжается или нет атрибут распространения транзакционного метода (например, REQUIRES_NEW всегда запускает новую транзакцию) Если менеджер транзакций решает создать новую транзакцию, он будет:
создать новый менеджер объектов привязать менеджер объектов к текущему потоку захватить соединение из пула соединений DB привязать соединение к текущему потоку Диспетчер объектов и соединение привязаны к текущему потоку с использованием переменных ThreadLocal.
Они сохраняются в потоке во время выполнения транзакции, и до диспетчера транзакций они очищают их, когда они больше не нужны.
Любые части программы, которые нуждаются в текущем менеджере или соединении сущностей, могут извлекать их из потока. Один программный компонент, который выполняет именно это прокси-сервер EntityManager.