springboot+hibernate两个数据源的配置

之前的项目使用的是SpringMVC+Spring+Hibernate的框架,在dao层上的配置是这样的

<!-- 读取用的数据库session工厂 -->
    <bean id="readSessionFactory"
        class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
        <property name="dataSource" ref="readDataSource" />
        <property name="packagesToScan">
            <list>
                <value>com.xxx.xxxx.xxxx.persistence.entities</value>
            </list>
        </property>
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop>
                <prop key="hibernate.dialect">${hibernate.dialect}</prop>
                <prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
            </props>
        </property>
    </bean>

    <!-- 读取的数据库映射 -->
    <bean id="readDataSource"
        class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="${read.jdbc.driverClassName}" />
        <property name="url" value="${read.jdbc.url}" />
        <property name="username" value="${read.jdbc.user}" />
        <property name="password" value="${read.jdbc.pass}" />
    </bean>

    <!-- 写出用的数据库session工厂 -->
    <bean id="writeSessionFactory"
        class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
        <property name="dataSource" ref="writeDataSource" />
        <property name="packagesToScan">
            <list>
                <value>com.xxx.xxxx.xxxx.persistence.entities</value>
            </list>
        </property>
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop>
                <prop key="hibernate.dialect">${hibernate.dialect}</prop>
                <prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
            </props>
        </property>
    </bean>

    <!-- 写出的数据库映射 -->
    <bean id="writeDataSource"
        class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="${write.jdbc.driverClassName}" />
        <property name="url" value="${write.jdbc.url}" />
        <property name="username" value="${write.jdbc.user}" />
        <property name="password" value="${write.jdbc.pass}" />
    </bean>

    <!-- 配置事务管理器 -->
    <bean id="txManager"
        class="org.springframework.orm.hibernate4.HibernateTransactionManager">
        <property name="sessionFactory" ref="writeSessionFactory" />
    </bean>
    <!-- 配置切入点 -->
    <aop:config>
        <aop:pointcut id="allMethods"
            expression="execution(* com.xxx.xxxx.xxxx.service.impl.*.*(..))" />
        <aop:advisor advice-ref="txAdvice" pointcut-ref="allMethods" />
    </aop:config>
    <!-- 配置事务方法 -->
    <tx:advice id="txAdvice" transaction-manager="txManager">
        <tx:attributes>
            <tx:method name="*" propagation="REQUIRED" />
            <tx:method name="get*" propagation="REQUIRED" read-only="true" />
            <tx:method name="find*" propagation="REQUIRED" read-only="true" />
            <tx:method name="list*" propagation="REQUIRED" read-only="true" />
        </tx:attributes>
    </tx:advice>

以上的配置,都是在xml文件中配置的,那么转到springboot上,需要在config类中配置

第一步:配置数据源

看源码,springboot的DataSourceBuilder,可知DataSource类型有以下几种,

private static final String[] DATA_SOURCE_TYPE_NAMES = new String[] {
            "org.apache.tomcat.jdbc.pool.DataSource",
            "com.zaxxer.hikari.HikariDataSource",
            "org.apache.commons.dbcp.BasicDataSource", // deprecated
            "org.apache.commons.dbcp2.BasicDataSource" };
 

在 DataSourceConfiguration.tomcat.class类中,可以看到,默认使用的是org.apache.tomcat.jdbc.pool.DataSource

/**
     * Tomcat Pool DataSource configuration.
     */
    @ConditionalOnClass(org.apache.tomcat.jdbc.pool.DataSource.class)
    @ConditionalOnProperty(name = "spring.datasource.type", havingValue = "org.apache.tomcat.jdbc.pool.DataSource", matchIfMissing = true)
    static class Tomcat extends DataSourceConfiguration {

................

}

myDataSourceConfig.class类

@Configuration
public class MyDataSourceConfig {

    @Bean(name="readDataSource")
    @Qualifier("readDataSource")
    @ConfigurationProperties(prefix="read.jdbc")
    public DataSource readDataSource() {
        return DataSourceBuilder.create().build();
    }
    
    @Bean(name="writeDataSource")
    @Qualifier("writeDataSource")
    @Primary
    @ConfigurationProperties(prefix="write.jdbc")
    public DataSource writeDataSource() {
        return DataSourceBuilder.create().build();
    }

application.properties文件中,数据库的链接配置(因为我本地的mysql是8.0,所以配置与5.7的有所不同)

#数据库session工厂配置
read.jdbc.driverClassName=com.mysql.cj.jdbc.Driver
read.jdbc.url=jdbc:mysql://172.0.0.1:3306/springbootdemo?characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true&nullCatalogMeansCurrent=true
read.jdbc.username=root
read.jdbc.password=root

write.jdbc.driverClassName=com.mysql.cj.jdbc.Driver
write.jdbc.url=jdbc:mysql://172.0.0.1:3306/springbootdemo?characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true&nullCatalogMeansCurrent=true
write.jdbc.username=root
write.jdbc.password=root

spring.jpa.properties.hibernate.current_session_context_class=org.springframework.orm.hibernate4.SpringSessionContext 

//current_session_context_class该属性配置,是为了加载Hibernate的sessionFactory,而不是使用默认的

因为springboot默认加载的是 DataSourceAutoConfiguration.class,即在application文件上设置的两个数据源没办法被其识别,我需要自己手动加入,并去掉默认加载exclude = { DataSourceAutoConfiguration.class },同时在application.properties文件上加入current_session_context_class属性

第二步,配置sessionFactory

@Configuration
@Import(MyDataSourceConfig.class)
public class MySessionFactory {

    @Autowired
    @Qualifier("readDataSource")
    private DataSource readDataSource;

    @Autowired
    @Qualifier("writeDataSource")
    private DataSource writeDataSource;

    @Value(value = "${spring.jpa.show-sql}")
    private String showSql;
    @Value(value = "${spring.jpa.properties.hibernate.dialect}")
    private String dialect;
    @Value(value = "${spring.jpa.hibernate.ddl-auto}")
    private String ddlAuto;

    @Bean(name = "readSessionFactory")
    public LocalContainerEntityManagerFactoryBean readSessionFactory(EntityManagerFactoryBuilder builder) {

        return builder.dataSource(readDataSource).properties(getHibernateProperties(readDataSource))
                .packages("com.xingfu.springboot.persistence.entity").build();
    }
    
    @Bean  
    public SessionFactory sessionFactory(HibernateEntityManagerFactory hemf){  
        return hemf.getSessionFactory();  //必须添加,否则不会加载你所设置的HibernateSessionFactory
    } 
    
    @Bean(name = "writeSessionFactory")
    @Primary  //配置为默认sessionFactory,不设置,两个sessionFactory就无法查找是那个
    public LocalContainerEntityManagerFactoryBean writeSessionFactory(EntityManagerFactoryBuilder builder) {

        return builder.dataSource(writeDataSource).properties(getHibernateProperties(writeDataSource))
                .packages("com.xingfu.springboot.persistence.entity").build();
    }

    @Autowired(required = false)
    private JpaProperties jpaProperties;

    private Map<String, String> getHibernateProperties(DataSource dataSource) {
        Map<String, String> hibernateMap = jpaProperties.getHibernateProperties(dataSource);
        hibernateMap.put("hibernate.show_sql", showSql);
        hibernateMap.put("hibernate.dialect", dialect);
        hibernateMap.put("hibernate.hbm2ddl.auto", ddlAuto);
        return hibernateMap;
    }
}

application.properties文件的配置

spring.jpa.database = MYSQL
spring.jpa.show-sql = false
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
spring.jpa.hibernate.ddl-auto = update

 第三步,配置事物和切面

@Configuration
@Aspect
@Import(value= {MySessionFactory.class})
public class MyHibernateConfig{

    @Autowired
    @Qualifier("writeSessionFactory")
    private LocalContainerEntityManagerFactoryBean writeSessionFactory;
    
    /** 事物切入点 */
    private static final String AOP_POINTCUT_EXPRESSION = "execution (* com.xingfu.springboot.service.impl.*.*(..))";

    
    @Bean(name = "txManager")
    public PlatformTransactionManager txManager() {
        return new JpaTransactionManager(writeSessionFactory.getObject());
    }

    @Bean
    public TransactionInterceptor transctionInterceptor() {
        NameMatchTransactionAttributeSource source = new NameMatchTransactionAttributeSource();
        RuleBasedTransactionAttribute readOnlyTx = new RuleBasedTransactionAttribute();
        readOnlyTx.setReadOnly(true);
        readOnlyTx.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
        RuleBasedTransactionAttribute requiredTx = new RuleBasedTransactionAttribute();
        requiredTx.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
        Map<String, TransactionAttribute> txMap = new HashMap<>();
        txMap.put("*", requiredTx);
        txMap.put("get*", readOnlyTx);
        txMap.put("find*", readOnlyTx);
        txMap.put("list*", readOnlyTx);
        source.setNameMap(txMap);
        TransactionInterceptor txAdvice = new TransactionInterceptor(txManager(), source);
        return txAdvice;
    }

    @Bean
    public Advisor txAdviceAdvisor() {
        AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
        pointcut.setExpression(AOP_POINTCUT_EXPRESSION);
        return new DefaultPointcutAdvisor(pointcut,transctionInterceptor());
    }

}

配置完成. 

参考资料:

https://www.jianshu.com/p/1db9e7667fa7

https://blog.csdn.net/neosmith/article/details/61202084
https://segmentfault.com/q/1010000009512587

http://blog.didispace.com/springboottransactional/
https://blog.csdn.net/nextyu/article/details/78669997

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值