SpringBoot+Hibernate配置多个数据源(数据库)的方式实现

2022-01-28 65点热度 0人点赞 0条评论

之前的文章介绍了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();
    }
}

 

admin

这个人很懒,什么都没留下

文章评论

*

code