之前的文章介绍了SpringBoot下整合Hibernate,详见:https://blog.terrynow.com/2021/07/08/springboot-integrate-hibernate-include-transaction-how-to/
一般来说是针对单个数据源(数据库)的,不过有时候,需求是要让SpringBoot接多个数据库(也可能是不同的类型的数据库)
实现方法
我们假设会连接2个数据源,一个是默认的(名字就是dataSource),另一个dataSource02,首先在SpringBoot下配置如下(注意默认的dataSource需要加@Primary,另外还需要配置sessionFactory和transactionManager)
MyManageApplication.java
import com.zaxxer.hikari.HikariDataSource;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
import org.springframework.core.env.Environment;
import org.springframework.orm.hibernate5.HibernateTransactionManager;
import org.springframework.orm.hibernate5.LocalSessionFactoryBean;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.sql.DataSource;
import java.util.Properties;
// 排除 DataSource, JPARepositories, HibernateJpa 的自动配置
@SpringBootApplication(exclude = {
// DataSourceAutoConfiguration.class,
JpaRepositoriesAutoConfiguration.class,
HibernateJpaAutoConfiguration.class})
// 开启事务管理
@EnableTransactionManagement(proxyTargetClass = true)
public class MyManageApplication extends SpringBootServletInitializer {
@Autowired
private Environment env;
// @Autowired
// DataSourceProperties dataSourceProperties;
public static void main(String[] args) {
SpringApplication.run(MyManageApplication.class, args);
}
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return builder.sources(MyManageApplication.class);
}
@Bean
@ConfigurationProperties(prefix="spring.datasource02")
public DataSource dataSource02() {
return DataSourceBuilder.create()
.type(HikariDataSource.class)
// .driverClassName(dataSourceProperties.determineDriverClassName())
// .url(dataSourceProperties.determineUrl())
// .username(dataSourceProperties.determineUsername())
// .password(dataSourceProperties.determinePassword())
.build();
}
@Bean
@Primary
// @Bean(name = "dataSource")
@ConfigurationProperties(prefix="spring.datasource")
public DataSource getDataSource() {
// DriverManagerDataSource dataSource = new DriverManagerDataSource();
//
// // See: application.properties
// dataSource.setDriverClassName(env.getProperty("spring.datasource.driver-class-name"));
// dataSource.setUrl(env.getProperty("spring.datasource.url"));
// dataSource.setUsername(env.getProperty("spring.datasource.username"));
// dataSource.setPassword(env.getProperty("spring.datasource.password"));
//
// System.out.println("## getDataSource: " + dataSource);
//
// return dataSource;
// return DataSourceBuilder.create().build();
return DataSourceBuilder.create()
.type(HikariDataSource.class)
// .driverClassName(dataSourceProperties.determineDriverClassName())
// .url(dataSourceProperties.determineUrl())
// .username(dataSourceProperties.determineUsername())
// .password(dataSourceProperties.determinePassword())
.build();
}
@Bean(name = "sessionFactory")
public SessionFactory getSessionFactory() throws Exception {
Properties properties = new Properties();
// See: application.properties
properties.put("hibernate.dialect", env.getProperty("spring.jpa.properties.hibernate.dialect"));
properties.put("hibernate.show_sql", env.getProperty("spring.jpa.show-sql"));
properties.put("current_session_context_class", env.getProperty("spring.jpa.properties.hibernate.current_session_context_class"));
// Fix Postgres JPA Error:
// Method org.postgresql.jdbc.PgConnection.createClob() is not yet implemented.
// properties.put("hibernate.temp.use_jdbc_metadata_defaults",false);
LocalSessionFactoryBean factoryBean = new LocalSessionFactoryBean();
// Package contain entity classes
factoryBean.setPackagesToScan("net.leizsoft.pdcgpx.entity");
factoryBean.setDataSource(getDataSource());
factoryBean.setHibernateProperties(properties);
factoryBean.afterPropertiesSet();
return factoryBean.getObject();
}
@Bean(name = "sessionFactory02")
public SessionFactory getSessionFactory02() throws Exception {
Properties properties = new Properties();
// See: application.properties
properties.put("hibernate.dialect", env.getProperty("spring.jpa.properties.hibernate.dialect"));
properties.put("hibernate.show_sql", env.getProperty("spring.jpa.show-sql"));
properties.put("current_session_context_class", env.getProperty("spring.jpa.properties.hibernate.current_session_context_class"));
// Fix Postgres JPA Error:
// Method org.postgresql.jdbc.PgConnection.createClob() is not yet implemented.
// properties.put("hibernate.temp.use_jdbc_metadata_defaults",false);
LocalSessionFactoryBean factoryBean = new LocalSessionFactoryBean();
// Package contain entity classes
factoryBean.setPackagesToScan("com.terrynow.test.entity");
factoryBean.setDataSource(dataSource02());
factoryBean.setHibernateProperties(properties);
factoryBean.afterPropertiesSet();
return factoryBean.getObject();
}
@Autowired
@Primary
@Bean
public HibernateTransactionManager transactionManager(@Qualifier("sessionFactory") SessionFactory sessionFactory) {
return new HibernateTransactionManager(sessionFactory);
}
@Autowired
@Bean
public HibernateTransactionManager transactionManager02(@Qualifier("sessionFactory02") SessionFactory sessionFactory) {
return new HibernateTransactionManager(sessionFactory);
}
}
SpringBoot的配置文件如下(只摘抄和数据库相关的部分,当然datasource02也可以使用其他数据库如Oracle的连接)
application.yml
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/db1?allowPublicKeyRetrieval=true&autoReconnect=true&useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=GMT%2B8
username: root
password: 123456
datasource02:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:8203/db2?allowPublicKeyRetrieval=true&autoReconnect=true&useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=GMT%2B8
username: root
password: 654321
jpa:
show-sql: false
hibernate:
ddl-auto: none
properties:
hibernate:
dialect: org.hibernate.dialect.MySQLDialect
current_session_context_class: org.springframework.orm.hibernate5.SpringSessionContext
下面测试要service中调用datasource02
TestServiceImpl.java
@Service("testService")
@Transactional(readOnly = false, value = "transactionManager02")
@Repository
public class TestServiceImpl implements ITestService {
@Resource(name = "testDao")
private ITestDao testDao;
@Override
public void test() {
System.out.println("applyInfo count: "+testDao.test());
}
}
DAO操作类如下(使用了sessionFactory02):
TestDaoImpl.java
@Component("testDao")
public class TestDaoImpl implements ITestDao {
@Autowired
private SessionFactory sessionFactory02;
@Override
public int test() {
NativeQuery nativeQuery = sessionFactory.getCurrentSession().createNativeQuery("select count(*) as cnt from t_test");
nativeQuery.addScalar("cnt", new LongType());
return (Long) nativeQuery.uniqueResult();
}
}
文章评论