springboot-mybatis整合多数据源方式之一AOP法

环境: intellij idea 2017.1.4 + spring boot 1.5.9

简介: 用这种方式实现多数据源的前提必须要清楚两个知识点:AOP原理和AbstractRoutingDataSource抽象类。

1、AOP:相当于拦截器,只要满足要求的都会被拦截过来,然后进行一些列的操作。具体需要自己去体会。。。

2、AbstractRoutingDataSource:这个类是实现多数据源的关键,他的作用就是动态切换数据源,实质:有多少个数据源就存多少个数据源在targetDataSources(是AbstractRoutingDataSource的一个map类型的属性,其中value为每个数据源,key表示每个数据源的名字)这个属性中,然后根据determineCurrentLookupKey()这个方法获取当前数据源在map中的key值,然后determineTargetDataSource()方法中动态获取当前数据源,如果当前数据源不存并且默认数据源也不存在就抛出异常。

public abstract class AbstractRoutingDataSource extends AbstractDataSource implements InitializingBean {
    //多数据源map集合
    private Map<Object, Object> targetDataSources;
    //默认数据源
    private Object defaultTargetDataSource;
    //其实就是targetDataSources,后面的afterPropertiesSet()方法会将targetDataSources赋值给resolvedDataSources
    private Map<Object, DataSource> resolvedDataSources;
    private DataSource resolvedDefaultDataSource;
    public void setTargetDataSources(Map<Object, Object> targetDataSources) {
        this.targetDataSources = targetDataSources;
    }
    protected DataSource determineTargetDataSource() {
        Assert.notNull(this.resolvedDataSources, "DataSource router not initialized");
        Object lookupKey = this.determineCurrentLookupKey();
        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;
        }
    }
    protected abstract Object determineCurrentLookupKey();
}

具体实现:

1、定义一个动态数据源:继承AbstractRoutingDataSource 抽象类,并重写determineCurrentLookupKey()方法

public class DynamicDataSource extends AbstractRoutingDataSource {

    @Override
    protected Object determineCurrentLookupKey() {
        DataSourceType.DataBaseType dataBaseType = DataSourceType.getDataBaseType();
        return dataBaseType;
    }
}

项目文件结构:

附上代码:

application.properties

#spring.datasource.driverClassName=com.mysql.jdbc.Driver
#spring.datasource.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8
#spring.datasource.username=root
#spring.datasource.password=
#mybatis.mapper-locations: classpath:mapper/*.xml

server.port=8080
## test1 database
spring.datasource.db1.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC&useSSL=false
spring.datasource.db1.username=root
spring.datasource.db1.password=
spring.datasource.db1.driver-class-name=com.mysql.cj.jdbc.Driver
## test2 database
spring.datasource.db2.url=jdbc:mysql://localhost:3306/news?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC&useSSL=false
spring.datasource.db2.username=root
spring.datasource.db2.password=
spring.datasource.db2.driver-class-name=com.mysql.cj.jdbc.Driver

pom.xml

<?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.neo</groupId>
	<artifactId>spring-boot-hello</artifactId>
	<version>1.0</version>
	<packaging>jar</packaging>

	<name>spring-boot-hello</name>
	<description>Demo project for Spring Boot</description>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>1.5.9.RELEASE</version>
		<!--<version>2.0.0.RELEASE</version>-->
	</parent>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<java.version>1.8</java.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-jdbc</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>


		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-aop</artifactId>
		</dependency>
		<dependency>
			<groupId>org.mybatis.spring.boot</groupId>
			<artifactId>mybatis-spring-boot-starter</artifactId>
			<version>1.3.2</version>
		</dependency>
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>8.0.11</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>
	
	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>
	

</project>

注:springboot 原来用的是2.0,但有个类(org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;)会找不到,切到1.5.9反而可以。

entity

package com.neo.entity;

import org.springframework.stereotype.Component;


@Component
public class Sound {
    private Long id;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    private String title;
}


package com.neo.entity;

import org.springframework.stereotype.Component;


@Component
public class User {
    private Long id;
    private String username;
    private int age;
    public Long getId() {
        return id;
    }
    public void setId(Long id) {
        this.id = id;
    }
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
}

mapper

package com.neo.mapper.db1;

import com.neo.entity.User;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
public interface  UserMapper {
    //获取用户名单
    List<User> getUser() throws Exception;
    //根据id删除用户
    void deleteUser(int id)throws Exception;
    //新增用户
    void addUser(User user)throws Exception;

    //修改用户信息
    void updateUser(User user) throws Exception;

//    //用注解实现的
//    //获取用户名单
//    @Select("select * from user")
//    public List<User> getUser() throws Exception;
//    //根据id删除用户
//    @Delete("delete from user where id = #{id}")
//    public void deleteUser(int id)throws Exception;
//    //新增用户
//    @Insert("insert into user(id,username,age)values(#{id},#{username},#{age})")
//    public void addUser(User user)throws Exception;
//    //修改用户信息
//    @Update("update user set username = #{name} where id = #{id}")
//    public void updateUser(User user) throws Exception;
}


package com.neo.mapper.db2;

import com.neo.entity.Sound;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
public interface SoundMapper {
    //获取列表
    List<Sound> getSound() throws Exception;
    //根据id删除
    void deleteSound(int id)throws Exception;
    //新增
    void addSound(Sound sound)throws Exception;

    //修改信息
    //public void updateSound(Sound sound) throws Exception;

}

mappering

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://www.mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.neo.mapper.db1.UserMapper">
    <select id="getUser" resultType="com.neo.entity.User">
        select * from user
        <where>
            <if test="username != null">
                username=#{username}
            </if>

            <if test="age!= null">
                and age=#{age}
            </if>
        </where>
    </select>
    <delete id="deleteUser" parameterType="Integer">
        delete from user where id =#{id}
    </delete>
    <insert id="addUser" parameterType="com.neo.entity.User">
    insert into user(id,username,age)values(#{id},#{username},#{age})
</insert>
    <update id="updateUser" parameterType="com.neo.entity.User">
        update user
        <set>
            <if test = "username != null">
                user.username = #{username},
            </if>
            <if test = "age != 0">
                user.age = #{age}
            </if>
        </set>
        where id = #{id}
    </update>
</mapper>


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://www.mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.neo.mapper.db2.SoundMapper">
    <select id="getSound" resultType="com.neo.entity.Sound">
        select * from t_sound
        <where>
            <if test="title != null">
                title=#{title}
            </if>

            <if test="id!= null">
                and id=#{id}
            </if>
        </where>
    </select>
    <delete id="deleteSound" parameterType="Integer">
        delete from t_sound where id =#{id}
    </delete>
    <insert id="addSound" parameterType="com.neo.entity.Sound">
    insert into t_sound(id,title)values(#{id},#{title})
</insert>
    <update id="updateSound" parameterType="com.neo.entity.Sound">
        update t_sound
        <set>
            <if test = "title != null">
                sound.title = #{title},
            </if>
        </set>
        where id = #{id}
    </update>
</mapper>

dao

package com.neo.dao;

import com.neo.entity.Sound;
import com.neo.mapper.db2.SoundMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.List;


@Component

public class SoundDao {
    @Autowired
    private SoundMapper tm1;

    public List<Sound> getSound() {

        try {
           return tm1.getSound();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return  null;
    }
}


package com.neo.dao;

import com.neo.entity.User;
import com.neo.mapper.db1.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.List;


@Component
public class UserDao {
    @Autowired
    private UserMapper tm1;

    public List<User> getUser() {

        try {
           return tm1.getUser();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return  null;
    }
}

service

package com.neo.service.db1;

import com.neo.dao.SoundDao;
import com.neo.dao.UserDao;
import com.neo.entity.Sound;
import com.neo.entity.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;


@Service
public class UserService {
    @Autowired
    private UserDao ts1;

    @Transactional
    public List<User> getUser(){
        return ts1.getUser();
    }
}


package com.neo.service.db2;

import com.neo.dao.SoundDao;

import com.neo.entity.Sound;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

@Service
public class SoundService {
    @Autowired
    private SoundDao ts1;

    @Transactional
    public List<Sound> getSound(){
        return ts1.getSound();
    }
}

datasource

package com.neo.datasource;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Aspect

@Component
public class DataSourceAop {
	@Before("execution(* com.neo.service.db1..*(..))")
	public void setDataSource2test01() {
		System.err.println("test01业务");
		DataSourceType.setDataBaseType(DataSourceType.DataBaseType.DB1);
	}
	@Before("execution(* com.neo.service.db2..*(..))")
	public void setDataSource2test02() {
		System.err.println("test02业务");
		DataSourceType.setDataBaseType(DataSourceType.DataBaseType.DB2);
	}
}


package com.neo.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.boot.autoconfigure.jdbc.DataSourceBuilder;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;

import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;

@Configuration
@MapperScan(basePackages = "com.neo.mapper", sqlSessionFactoryRef = "SqlSessionFactory")
public class DataSourceConfig {
	@Primary
	@Bean(name = "db1DataSource")
	@ConfigurationProperties(prefix = "spring.datasource.db1")
	public DataSource getDateSource1() {
		return DataSourceBuilder.create().build();
	}

	@Bean(name = "db2DataSource")
	@ConfigurationProperties(prefix = "spring.datasource.db2")
	public DataSource getDateSource2() {
		return DataSourceBuilder.create().build();
	}

	@Bean(name = "dynamicDataSource")
	public DynamicDataSource DataSource(@Qualifier("db1DataSource") DataSource db1DataSource,
			@Qualifier("db2DataSource") DataSource db2DataSource) {
		Map<Object, Object> targetDataSource = new HashMap<>();
		targetDataSource.put(DataSourceType.DataBaseType.DB1, db1DataSource);
		targetDataSource.put(DataSourceType.DataBaseType.DB2, db2DataSource);
		DynamicDataSource dataSource = new DynamicDataSource();
		dataSource.setTargetDataSources(targetDataSource);
		dataSource.setDefaultTargetDataSource(db1DataSource);
		return dataSource;
	}

	@Bean(name = "SqlSessionFactory")
	public SqlSessionFactory test1SqlSessionFactory(@Qualifier("dynamicDataSource") DataSource dynamicDataSource)
			throws Exception {
		SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
		bean.setDataSource(dynamicDataSource);
		bean.setMapperLocations(
				new PathMatchingResourcePatternResolver().getResources("classpath*:mappering/*/*.xml"));
		return bean.getObject();
	}

}


package com.neo.datasource;

public class DataSourceType {

	public enum DataBaseType {
		DB1, DB2
	}

	// 使用ThreadLocal保证线程安全
	private static final ThreadLocal<DataBaseType> TYPE = new ThreadLocal<DataBaseType>();

	// 往当前线程里设置数据源类型
	public static void setDataBaseType(DataBaseType dataBaseType) {
		if (dataBaseType == null) {
			throw new NullPointerException();
		}
		System.err.println("[将当前数据源改为]:" + dataBaseType);
		TYPE.set(dataBaseType);
	}

	// 获取数据源类型
	public static DataBaseType getDataBaseType() {
		DataBaseType dataBaseType = TYPE.get() == null ? DataBaseType.DB1 : TYPE.get();
		System.err.println("[获取当前数据源的类型为]:" + dataBaseType);
		return dataBaseType;
	}

	// 清空数据类型
	public static void clearDataBaseType() {
		TYPE.remove();
	}

}


package com.neo.datasource;

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

public class DynamicDataSource extends AbstractRoutingDataSource {

	@Override
	protected Object determineCurrentLookupKey() {
		DataSourceType.DataBaseType dataBaseType = DataSourceType.getDataBaseType();
		return dataBaseType;
	}

}

control

package com.neo.controller;

import com.neo.entity.Sound;
import com.neo.service.db2.SoundService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;


@RestController
public class SoundController {

    @Autowired
    private SoundService soundService;
    @Autowired
    private Sound sound;
    //显示用户
    @RequestMapping("sound/list")
    public List<Sound> index() throws Exception {
        return soundService.getSound();
    }

//    //增加用户
//    @RequestMapping("sound/add")
//    public String addSound() throws Exception {
//        sound.setTitle("平凡之路");
//        soundService.addSound(sound);
//        return "增加";
//    }
}


package com.neo.controller;

import com.neo.entity.User;
import com.neo.service.db1.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;


@RestController
public class UserController {

    @Autowired
    private UserService userService;
    @Autowired
    private User user;
    //显示用户
    @RequestMapping("list")
    public List<User> index() throws Exception {
        return userService.getUser();
    }
//    //删除用户
//    @RequestMapping("delete/{id}")
//    public String delete(@PathVariable int id) throws Exception {
//        userService.deleteUser(id);
//        return "你已经删掉了id为"+id+"的用户";
//    }
//    //增加用户
//    @RequestMapping("addUser")
//    public String addUser() throws Exception {
//        user.setAge(33);
//        user.setUsername("阿花");
//        userService.addUser(user);
//        return "增加用户";
//    }
}

启动类

package com.neo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class HelloApplication {

	public static void main(String[] args) {
		SpringApplication.run(HelloApplication.class, args);
	}
}

项目完整包下载地址: 下载

--- end ---

猜你喜欢

转载自blog.csdn.net/huwei2003/article/details/88997471
今日推荐