在我的Java进程中,我正在使用以下Spring配置连接到MySQL:
@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),但我没有找到任何官方文档来描述连接是如何被管理的。有人可以为我解释一下,或者提供一个好的参考资料来解释在使用这种配置时何时会将连接返回到池中吗?
更新:
我能够找到的最佳相关信息(摘自此处):
实现EntityManager的持久性上下文代理不是使声明式事务管理生效所需的唯一组件。其实需要三个单独的组件:
EntityManager代理本身
事务性方面
事务管理器
让我们逐个细看,并看看它们如何互动。
事务性方面
事务性方面是一个环绕切面,在注释的业务方法之前和之后都被调用。实现该方面的具体类是TransactionInterceptor。
事务性方面有两个主要职责:
在'before'时刻,该方面提供了一个钩子点,用于确定即将调用的业务方法是否应在正在进行的数据库事务范围内运行,或者是否应启动新的独立事务。
在'after'时刻,方面需要决定事务是应该提交、回滚还是保持运行。
在'before'时刻,事务性方面本身不包含任何决策逻辑,必要时启动新事务的决定委托给事务管理器。
事务管理器
事务管理器需要回答两个问题:
应该创建一个新的EntityManager吗?
应该启动一个新的数据库事务吗?
这需要在调用事务性方面之前做出决定。事务管理器将根据以下因素做出决策:
已经存在一个事务还是不存在
事务性方法的传播属性(例如,REQUIRES_NEW始终会启动一个新事务)
如果事务管理器决定创建一个新事务,那么它将:
创建一个新的实体管理器
将实体管理器绑定到当前线程
从DB连接池中获取一个连接
将连接绑定到当前线程
实体管理器和连接都使用ThreadLocal变量绑定到当前线程中。
它们在事务运行时存储在线程中,当不再需要时,由事务管理器清理。程序中需要当前实体管理器或连接的任何部分都可以从线程中检索它们。一个恰好如此的程序组件就是EntityManager代理。