springboot-mybatis—多数据源

来源:互联网 发布:淘宝店铺免费一键复制 编辑:程序博客网 时间:2024/06/07 04:56
    工作老系统添加新的功能  需要调用其他数据库的资源,应用多数据源,老大只给一晚上解决,哎,总算是磨出来(看了很多好的博客),我也记录一篇,也给后人方便。    原理简单说明,详细请看代码分析。 1. 配置多个数据源 =》 每个数据源一个key。 2. 将多个数据源注入到DynmicDataSource(自己定义,必须实现AbstractRoutingDataSource)。 3. 设置默认数据源,其他由业务手动获取key后动态注入达到切换数据源的效果。 4. 授人以鱼不如授人以渔,我看了很多同学博客,懂了原理才能进步,希望不要以完成任务为目的,多多分析,其它同学还可以有aop实现动态注入数据源,在这里我时间紧迫,且工作需求不大,在这里就不再分析aop情况。

1.pom 文件

<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">    <modelVersion>4.0.0</modelVersion>    <groupId>com.mybatis.datasources</groupId>    <artifactId>spring-boot-datasources</artifactId>    <version>0.0.1-SNAPSHOT</version>    <packaging>jar</packaging>    <name>spring-boot-datasources</name>    <description>Demo project for Spring Boot</description>    <parent>        <groupId>org.springframework.boot</groupId>        <artifactId>spring-boot-starter-parent</artifactId>        <version>1.5.2.RELEASE</version>        <relativePath/> <!-- lookup parent from repository -->    </parent>    <properties>        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>        <java.version>1.8</java.version>    </properties>    <dependencies>        <dependency>            <groupId>org.mybatis.spring.boot</groupId>            <artifactId>mybatis-spring-boot-starter</artifactId>            <version>1.3.0</version>        </dependency>        <dependency>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-starter-web</artifactId>        </dependency>        <dependency>            <groupId>mysql</groupId>            <artifactId>mysql-connector-java</artifactId>            <scope>runtime</scope>        </dependency>        <dependency>            <groupId>org.projectlombok</groupId>            <artifactId>lombok</artifactId>            <optional>true</optional>        </dependency>        <dependency>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-starter-test</artifactId>            <scope>test</scope>        </dependency>    <!-- 连接池 -->        <dependency>            <groupId>com.alibaba</groupId>            <artifactId>druid</artifactId>            <version>1.0.29</version>        </dependency>    </dependencies>    <build>        <plugins>            <plugin>                <groupId>org.springframework.boot</groupId>                <artifactId>spring-boot-maven-plugin</artifactId>            </plugin>        </plugins>    </build></project>

2.application.properties 配置 主从数据源基本数据

#主数据源primary.datasource.driverClassName = com.mysql.jdbc.Driverprimary.datasource.url = jdbc:mysql://localhost:3306/mybatisprimary.datasource.username = rootprimary.datasource.password = root#从数据源customer.datasource.driverClassName = com.mysql.jdbc.Drivercustomer.datasource.url = jdbc:mysql://localhost:3306/lucenecustomer.datasource.username = rootcustomer.datasource.password = root

3.DataSourceType (数据源key)

public enum DataSourceType {    mybatis , lucene //(用数据库名方便记忆)}

4.DynamicDataSource (动态数据源 )

package com.mybatis.datasources.config;import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;/** * Created by guoyao on 2017/4/18. */public class DynamicDataSource extends AbstractRoutingDataSource {    private static final ThreadLocal<DataSourceType> contextHolder=new ThreadLocal<>();    /**     * 动态数据源(继承AbstractRoutingDataSource)     */    @Override  //父类方法     protected Object determineCurrentLookupKey() {        return getDatabaseType();    }    public static void setDatabaseType(DataSourceType type) {        contextHolder.set(type);    }    public static DataSourceType getDatabaseType() {        return contextHolder.get();    }}

5.动态数据源源码分析 AbstractRoutingDataSource

protected DataSource determineTargetDataSource() {        Assert.notNull(this.resolvedDataSources, "DataSource router not initialized");        //获取lookupkey        Object lookupKey = this.determineCurrentLookupKey();        //由lookupkey 获取数据源 (动态指定的关键)        DataSource dataSource = (DataSource)this.resolvedDataSources.get(lookupKey);        if(dataSource == null && (this.lenientFallback || lookupKey == null)) {            dataSource = this.resolvedDefaultDataSource;        }        if(dataSource == null) {            throw new IllegalStateException("Cannot determine target DataSource for lookup key [" + lookupKey + "]");        } else {            return dataSource;        }    }    //指定lookupkey    protected abstract Object determineCurrentLookupKey();

6.mybatis-config 配置类编写

package com.mybatis.datasources.config;import com.alibaba.druid.pool.DruidDataSourceFactory;import org.apache.ibatis.session.SqlSessionFactory;import org.mybatis.spring.SqlSessionFactoryBean;import org.mybatis.spring.annotation.MapperScan;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.beans.factory.annotation.Qualifier;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.context.annotation.Primary;import org.springframework.jdbc.datasource.DataSourceTransactionManager;import javax.sql.DataSource;import java.util.HashMap;import java.util.Map;import java.util.Properties;/** * Created by guoyao on 2017/4/18. */@Configuration@MapperScan("com.mybatis.datasources.mapper")public class MyBatisConfig {    @Autowired  //采用java配置类读取配置(application.properties)    private PrimaryDataSourceProperty primaryDataSourceProperty;    @Autowired //采用java配置类读取配置(application.properties)    private CustomerDataSourceProperty customerDataSourceProperty;    /**     * 创建数据源(方法名即实例化对象名,可以由对象名指定注入@Qualifier )     */    @Bean    public DataSource dbDataSource1() throws Exception {        Properties props=new Properties();        props.put("driverClassName", primaryDataSourceProperty.getDriverClassName());        props.put("url", primaryDataSourceProperty.getUrl());        props.put("username", primaryDataSourceProperty.getUsername());        props.put("password", primaryDataSourceProperty.getPassword());        // 连接池 创建数据源 可用 DataSourceBuilder 非连接池方式        return DruidDataSourceFactory.createDataSource(props);    }    @Bean    public DataSource dbDataSource2() throws Exception {        Properties props=new Properties();        props.put("driverClassName", customerDataSourceProperty.getDriverClassName());        props.put("url", customerDataSourceProperty.getUrl());        props.put("username", customerDataSourceProperty.getUsername());        props.put("password", customerDataSourceProperty.getPassword());        return DruidDataSourceFactory.createDataSource(props);    }    /**     * @Primary 该注解表示在同一个接口有多个实现类可以注入的时候,默认选择哪一个,而不是让@autowire注解报错     * @Qualifier 根据名称进行注入,通常是在具有相同的多个类型的实例的一个注入(例如有多个DataSource类型的实例)     */    @Bean    @Primary       public DynamicDataSource ds(@Qualifier("dbDataSource1") DataSource dbDataSource1,                                        @Qualifier("dbDataSource2") DataSource dbDataSource2) {        Map<Object, Object> targetDataSources=new HashMap<>();        targetDataSources.put(DataSourceType.mybatis, dbDataSource1);        targetDataSources.put(DataSourceType.lucene, dbDataSource2);        DynamicDataSource dataSource=new DynamicDataSource();        // 该方法是AbstractRoutingDataSource的方法        // 即源码分析中map resolvedDataSources 属性由lookupkey获取         dataSource.setTargetDataSources(targetDataSources);        dataSource.setDefaultTargetDataSource(dbDataSource1);// 默认的datasource设置为dbDataSource1        return dataSource;    }    /**     * 根据数据源创建SqlSessionFactory     */    @Bean    public SqlSessionFactory sqlSessionFactory(DynamicDataSource ds) throws Exception {        SqlSessionFactoryBean fb=new SqlSessionFactoryBean();        fb.setDataSource(ds);// 指定数据源        return fb.getObject();    }    /**     * 配置事务管理器     */    @Bean    public DataSourceTransactionManager transactionManager(DynamicDataSource ds) throws Exception {        return new DataSourceTransactionManager(ds);    }}

7.Application ***一定要关闭datasource 自动配置

package com.mybatis.datasources;import com.mybatis.datasources.config.CustomerDataSourceProperty;import com.mybatis.datasources.config.PrimaryDataSourceProperty;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;import org.springframework.boot.context.properties.EnableConfigurationProperties;@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class}) //关闭datasource的自动注入@EnableConfigurationProperties({CustomerDataSourceProperty.class, PrimaryDataSourceProperty.class})  //注入配置文件public class SpringBootDatasourcesApplication {    public static void main(String[] args) {        SpringApplication.run(SpringBootDatasourcesApplication.class, args);    }}

8.测试

package com.mybatis.datasources.mapper;import com.mybatis.datasources.dataobject.Book;import org.apache.ibatis.annotations.Mapper;import java.util.List;/** * Created by guoyao on 2017/4/18. */@Mapperpublic interface BookMapper {    //@Select("select * from book ")    //@ResultType(value =  Book.class)    List<Book> findAll();}@Mapperpublic interface UserMapper {    //@Select("select * from user ")    //@ResultType(value =  User.class)    List<User> findAll();}@Service("bookService")public class BookServiceImpl implements BookService {    @Autowired    private BookMapper bookDao ;    @Override    public List<Book> findAll() {        //指定数据源  即lookupkey        DynamicDataSource.setDatabaseType(DataSourceType.lucene);        return bookDao.findAll();    }}@Service("userService")public class UserServiceImpl implements UserService {    @Autowired    private UserMapper userDao ;    @Override    public List<User> findAll() {        return userDao.findAll();    }}/** * Created by guoyao on 2017/4/18. */@RestControllerpublic class TestController {    @Autowired    private UserService userService;    @Autowired    private BookService bookService;    @RequestMapping("/getUser")    public List<User> getUser() {       return userService.findAll();    }    @RequestMapping("/getBook")    public List<Book> getBook() {        return bookService.findAll();    }}
2 0
原创粉丝点击