springboot + mybatis+多数据源配置

此示例支持多种数据类型的数据源。

思路:

1.springboot默认配置是单数据源的,Mapper也是自动绑定到数据源的。所以要实现多数据源,必须先禁用掉springboot的默认配置。然后实现自定义的数据源,Mapper也需要自定义绑定数据源。

2.关于事务,对于跨数据源的事务,最好根据实际业务,通过不同数据源Service组合和实现。

3.同一个service方法只能用一个事务管理器,多个事务管理器@Transactional(rollbackFor = Exception.class,propagation=Propagation.REQUIRED,value="db1TxManager"),需要指定事务管理器。

4.同一个service方法里面可以从N个数据源里面查询数据,但是增删改的操作只能保持在一个数据源进行。不同的数据源增删改用

不同的service方法。

 

以下是代码

   HelloController.java

package com.xxh.controller;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import com.xxh.service.HelloService;

@Controller
public class HelloController {
    
    private static Logger logger=LoggerFactory.getLogger(HelloController.class);
    @Autowired
    private HelloService helloService;
    
    @RequestMapping(value="/hello",method=RequestMethod.GET)
    @ResponseBody
    public String hello() {
        logger.debug("come into controller");
        return helloService.sayHello();
    }
    
}
 

HelloDB1Mapper .java

package com.xxh.db1.mapper;

import com.xxh.entity.HelloBean;

public interface HelloDB1Mapper {
    
    int deleteByPrimaryKey(String id);
    
    int insertSelective(HelloBean record);

    HelloBean selectByPrimaryKey(String id);

    int updateByPrimaryKeySelective(HelloBean record);

    int updateByPrimaryKey(HelloBean record);

    
}
 

HelloDB2Mapper .java

package com.xxh.db2.mapper;

import com.xxh.entity.HelloBean;

public interface HelloDB2Mapper {
    
    int deleteByPrimaryKey(String id);
    
    int insertSelective(HelloBean record);

    HelloBean selectByPrimaryKey(String id);

    int updateByPrimaryKeySelective(HelloBean record);

    int updateByPrimaryKey(HelloBean record);

    
}
 

DB1Config

package com.xxh.dbconfig;

import javax.sql.DataSource;

import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;

import com.alibaba.druid.pool.DruidDataSource;

@Configuration
@MapperScan(basePackages = DB1Config.BASE_PACKAGE, sqlSessionFactoryRef = "db1SqlSessionFactory")
public class DB1Config {
     // 精确到 master 目录,以便跟其他数据源隔离
    static final String BASE_PACKAGE = "com.xxh.db1.mapper";
    static final String MAPPER_LOCATION = "classpath:db1mapper/*.xml";
 
    @Value("${db1.datasource.url}")
    private String url;
 
    @Value("${db1.datasource.username}")
    private String user;
 
    @Value("${db1.datasource.password}")
    private String password;
 
    @Value("${db1.datasource.driverClassName}")
    private String driverClass;
 
    @Bean(name = "db1DataSource")
    public DataSource db1DataSource() {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName(driverClass);
        dataSource.setUrl(url);
        dataSource.setUsername(user);
        dataSource.setPassword(password);
        return dataSource;
    }
 
    @Bean(name = "db1TransactionManager")  
    public DataSourceTransactionManager db1TransactionManager() {
        return new DataSourceTransactionManager(db1DataSource());
    }
 
    @Bean(name = "db1SqlSessionFactory")
    public SqlSessionFactory db1SqlSessionFactory(@Qualifier("db1DataSource") DataSource db1DataSource)
            throws Exception {
        final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
        sessionFactory.setDataSource(db1DataSource);
        sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(DB1Config.MAPPER_LOCATION));
        return sessionFactory.getObject();

    }
}
 

DB2Config.java 

package com.xxh.dbconfig;

import javax.sql.DataSource;

import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;

import com.alibaba.druid.pool.DruidDataSource;

@Configuration
@MapperScan(basePackages = DB2Config.BASE_PACKAGE, sqlSessionFactoryRef = "db2SqlSessionFactory")
public class DB2Config {
     // 精确到 master 目录,以便跟其他数据源隔离
    static final String BASE_PACKAGE = "com.xxh.db2.mapper";
    static final String MAPPER_LOCATION = "classpath:db2mapper/*.xml";
 
    @Value("${db2.datasource.url}")
    private String url;
 
    @Value("${db2.datasource.username}")
    private String user;
 
    @Value("${db2.datasource.password}")
    private String password;
 
    @Value("${db2.datasource.driverClassName}")
    private String driverClass;
 
    @Bean(name = "db2DataSource")
    public DataSource db2DataSource() {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName(driverClass);
        dataSource.setUrl(url);
        dataSource.setUsername(user);
        dataSource.setPassword(password);
        return dataSource;
    }
 
    @Bean(name = "db2TransactionManager")  
    public DataSourceTransactionManager db2TransactionManager() {
        return new DataSourceTransactionManager(db2DataSource());
    }
 
    @Bean(name = "db2SqlSessionFactory")
    public SqlSessionFactory db2SqlSessionFactory(@Qualifier("db2DataSource") DataSource db2DataSource)
            throws Exception {
        final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
        sessionFactory.setDataSource(db2DataSource);
        sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(DB2Config.MAPPER_LOCATION));
        return sessionFactory.getObject();

    }
}
 

HelloBean .java

package com.xxh.entity;


public class HelloBean {
    
    private String id;   

    private String name;
   
    private String code;

   
    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id == null ? null : id.trim();
    }    

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name == null ? null : name.trim();
    }   

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code == null ? null : code.trim();
    }

    @Override
    public String toString() {
        return "HelloBean [id=" + id + ", name=" + name + ", code=" + code
                + "]";
    }

    
    
    
}

 

HelloService .java

package com.xxh.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.xxh.db1.mapper.HelloDB1Mapper;
import com.xxh.db2.mapper.HelloDB2Mapper;
import com.xxh.entity.HelloBean;

@Service("helloService")
public class HelloService {

    @Autowired
    private HelloDB1Mapper helloDB1Mapper;
    
    @Autowired
    private HelloDB2Mapper helloDB2Mapper;
    
    public String sayHello() {
        HelloBean org1=helloDB1Mapper.selectByPrimaryKey("26668");
        HelloBean org2=helloDB2Mapper.selectByPrimaryKey("26669");
        return org1.toString()+org2.toString();
    }

}
 

App .java

package com.xxh.springboot_multidatasource;

import org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;

/**
 * Hello world!
 *
 */
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class,MybatisAutoConfiguration.class})
@ComponentScan("com.xxh.controller,com.xxh.service,com.xxh.dbconfig")
public class App 
{
    public static void main( String[] args )
    {
       SpringApplication.run(App.class, args);
    }
}
 

HelloDB1Mapper.xml 位于src/main/resources/db1mapper/

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.xxh.db1.mapper.HelloDB1Mapper" >
  <resultMap id="BaseResultMap" type="com.xxh.entity.HelloBean" >
    <id column="ID" property="id" jdbcType="VARCHAR" />
    <result column="CODE" property="code" jdbcType="VARCHAR" />
    <result column="NAME" property="name" jdbcType="VARCHAR" />    
  </resultMap>
  
  <sql id="Base_Column_List" >
    ID,CODE,NAME
  </sql>
  
  <select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.String" >
    select 
    <include refid="Base_Column_List" />
    from db1_hello_table
    where ID = #{id,jdbcType=VARCHAR}
  </select>
  
  <delete id="deleteByPrimaryKey" parameterType="java.lang.String" >
    delete from db1_hello_table
    where ID = #{id,jdbcType=VARCHAR}
  </delete>

  <insert id="insertSelective" parameterType="com.xxh.entity.HelloBean" >
    insert into db1_hello_table
    <trim prefix="(" suffix=")" suffixOverrides="," >
      <if test="id != null" >
        ID,
      </if>  
      <if test="name != null" >
        NAME,
      </if>  
      <if test="code != null" >
        CODE,
      </if>

    </trim>
    <trim prefix="values (" suffix=")" suffixOverrides="," >
      <if test="id != null" >
        #{id,jdbcType=VARCHAR},
      </if>    
      <if test="name != null" >
        #{name,jdbcType=VARCHAR},
      </if>
      <if test="code != null" >
        #{code,jdbcType=VARCHAR},
      </if>
    </trim>
  </insert>
  <update id="updateByPrimaryKeySelective" parameterType="com.xxh.entity.HelloBean" >
    update db1_hello_table
    <set >     
      <if test="name != null" >
        NAME = #{name,jdbcType=VARCHAR},
      </if>
      <if test="code != null" >
        CODE = #{code,jdbcType=VARCHAR},
      </if>     
    </set>
    where ID = #{id,jdbcType=VARCHAR}
  </update>
  <update id="updateByPrimaryKey" parameterType="com.xxh.entity.HelloBean" >
    update db1_hello_table
    set 
      NAME = #{name,jdbcType=VARCHAR},     
      CODE = #{code,jdbcType=VARCHAR}
    where ID = #{id,jdbcType=VARCHAR}
  </update>
  
 
</mapper>

HelloDB2Mapper.xml    位于src/main/resources/db2mapper/

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.xxh.db2.mapper.HelloDB2Mapper" >
  <resultMap id="BaseResultMap" type="com.xxh.entity.HelloBean" >
    <id column="ID" property="id" jdbcType="VARCHAR" />
    <result column="CODE" property="code" jdbcType="VARCHAR" />
    <result column="NAME" property="name" jdbcType="VARCHAR" />    
  </resultMap>
  
  <sql id="Base_Column_List" >
    ID,CODE,NAME
  </sql>
  
  <select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.String" >
    select 
    <include refid="Base_Column_List" />
    from db2_hello_table
    where ID = #{id,jdbcType=VARCHAR}
  </select>
  
  <delete id="deleteByPrimaryKey" parameterType="java.lang.String" >
    delete from db2_hello_table
    where ID = #{id,jdbcType=VARCHAR}
  </delete>

  <insert id="insertSelective" parameterType="com.xxh.entity.HelloBean" >
    insert into db2_hello_table
    <trim prefix="(" suffix=")" suffixOverrides="," >
      <if test="id != null" >
        ID,
      </if>  
      <if test="name != null" >
        NAME,
      </if>  
      <if test="code != null" >
        CODE,
      </if>

    </trim>
    <trim prefix="values (" suffix=")" suffixOverrides="," >
      <if test="id != null" >
        #{id,jdbcType=VARCHAR},
      </if>    
      <if test="name != null" >
        #{name,jdbcType=VARCHAR},
      </if>
      <if test="code != null" >
        #{code,jdbcType=VARCHAR},
      </if>
    </trim>
  </insert>
  <update id="updateByPrimaryKeySelective" parameterType="com.xxh.entity.HelloBean" >
    update db2_hello_table
    <set >     
      <if test="name != null" >
        NAME = #{name,jdbcType=VARCHAR},
      </if>
      <if test="code != null" >
        CODE = #{code,jdbcType=VARCHAR},
      </if>     
    </set>
    where ID = #{id,jdbcType=VARCHAR}
  </update>
  <update id="updateByPrimaryKey" parameterType="com.xxh.entity.HelloBean" >
    update db2_hello_table
    set 
      NAME = #{name,jdbcType=VARCHAR},     
      CODE = #{code,jdbcType=VARCHAR}
    where ID = #{id,jdbcType=VARCHAR}
  </update>
  
 
</mapper>

application.properties

server.port=14000

db1.datasource.driverClassName=your_driver_class_name
db1.datasource.url              = your_datasource_url
db1.datasource.username         = your_username
db1.datasource.password         = your_userpasswd

db2.datasource.driverClassName=your_driver_class_name
db2.datasource.url              = your_datasource_url
db2.datasource.username         = your_username
db2.datasource.password         = your_userpasswd

logback.xml

<?xml version="1.0"?>
<configuration scan="true" scanPeriod="60 seconds" debug="false">

    <property name="rootPath" value="${catalina.base}/logs" />    
    <!-- controller debug appender -->
    <appender name="app_debugAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <File>${rootPath}/app_debug.log</File>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <FileNamePattern>
                ${rootPath}/app_debug-%d{yyyy-MM-dd}-%i.log.gz
            </FileNamePattern>
            <MaxHistory>31</MaxHistory>
            <TimeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <MaxFileSize>100MB</MaxFileSize>
            </TimeBasedFileNamingAndTriggeringPolicy>
        </rollingPolicy>
        <filter class="ch.qos.logback.classic.filter.LevelFilter"> 
            <level>DEBUG</level> 
            <onMatch>ACCEPT</onMatch> 
            <onMismatch>DENY</onMismatch> 
        </filter>
        <layout class="ch.qos.logback.classic.PatternLayout">
            <pattern>
                [%d{yyyy-MM-dd HH:mm:ss.SSS}] [%t] [%-5p] %logger{36} | %msg%n
            </pattern>
        </layout>
    </appender>
    
    <!-- controller error appender -->
    <appender name="app_errorAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <File>${rootPath}/app_error.log</File>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <FileNamePattern>
                ${rootPath}/app_error-%d{yyyy-MM-dd}-%i.log.gz
            </FileNamePattern>
            <MaxHistory>31</MaxHistory>
            <TimeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <MaxFileSize>100MB</MaxFileSize>
            </TimeBasedFileNamingAndTriggeringPolicy>
        </rollingPolicy>
        <filter class="ch.qos.logback.classic.filter.LevelFilter"> 
            <level>ERROR</level> 
            <onMatch>ACCEPT</onMatch> 
            <onMismatch>DENY</onMismatch> 
        </filter>
        <layout class="ch.qos.logback.classic.PatternLayout">
            <pattern>
                [%d{yyyy-MM-dd HH:mm:ss.SSS}] [%t] [%-5p] %logger{36} | %msg %n
            </pattern>
        </layout>
    </appender>    
    
    <!-- other appender -->    
    <appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>
                [%d{yyyy-MM-dd HH:mm:ss.SSS}] [%t] [%-5p] %logger{36} | %msg%n
            </pattern>
        </encoder>
    </appender>
    
    <!-- loggers -->
    <logger name="com.xxh.controller" additivity="false">
        <level value="ALL" />
        <appender-ref ref="app_debugAppender"/>        
        <appender-ref ref="app_errorAppender"/>
        <appender-ref ref="consoleAppender" />
      </logger>
    
    <!-- default Root logger -->
    <root>
        <level value="DEBUG" />
        <appender-ref ref="consoleAppender" />
    </root>
    
</configuration>

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值