崛起於Springboot2.X + Mysql讀寫分離(6)

《SpringBoot2.X心法總綱》java

       (本篇博客已於2019-08-28優化更新)mysql

      序言:這個讀寫分離摘自於Springboot多數據源快速啓動器,讀寫分離的話並非按照傳統方式的springmvc看方法命名那樣,而是在每一個方法上加註解或者類上添加註解代表選用的數據源。支持事物!spring

 一、建立Springboot項目

      勾選Web,Mysql,MyBatis三個模塊,最終建立springboot項目成功sql

二、pom.xml

<!-- springboot-aop包,AOP切面註解,Aspectd等相關注解 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-configuration-processor</artifactId>
    <optional>true</optional>
</dependency>
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
    <version>1.0.0</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>

三、application.properties

server.port=8088
#數據源1
spring.datasource.db1.jdbc-url=jdbc:mysql://127.0.0.1:3306/test_msg2?useUnicode=true&characterEncoding=utf-8&useSSL=false
spring.datasource.db1.username=root
spring.datasource.db1.password=root
spring.datasource.db1.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.db1.max-idle=10
spring.datasource.db1.max-wait=10000
spring.datasource.db1.min-idle=5
spring.datasource.db1.initial-size=5
#數據源2
spring.datasource.db2.jdbc-url=jdbc:mysql://127.0.0.1:3306/test_msg3?useUnicode=true&characterEncoding=utf-8&useSSL=false
spring.datasource.db2.username=root
spring.datasource.db2.password=root
spring.datasource.db2.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.db2.max-idle=10
spring.datasource.db2.max-wait=10000
spring.datasource.db2.min-idle=5
spring.datasource.db2.initial-size=5
#mybatis
mybatis.mapper-locations=classpath*:mapper/*.xml
mybatis.type-aliases-package=com.springboot2.mjt04.dao

四、實體類

public class User {
    private int id;
    private String name;
    private int age;

    public User(){}

    public User(String name, int age){
        this.name = name;
        this.age  = age;
    }

    public int getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

五、建立UserDao.xml

<?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.springboot2.mjt04.dao.UserDao">
       <!-- 查詢全部user -->
       <select id="getAllUser" resultType="java.util.Map">
              select * from user
       </select>
       <!-- 添加數據並返回主鍵ID,接收主鍵,必須以實體類接收 -->
       <!-- keyColumn="id"對應數據庫字段,keyProperty="id"對應實體類屬性  -->
       <insert id="addUserGetID" parameterType="com.springboot2.mjt04.entity.User" useGeneratedKeys="true" keyColumn="id" keyProperty="id">
              insert into user(name,age) values(#{name},#{age})
       </insert>
       <insert id="addUser">
              insert into user(name,age) values(#{name},#{age})
       </insert>
</mapper>

六、UserDao

@Mapper
public interface UserDao {
    //使用xml配置形式查詢

    List<Map> getAllUser();
    Long addUserGetID(User user);


    void addUser(User user);
}

七、UserService

@Service
public class UserService {

    @Autowired
    private UserDao moredataDao;

    //使用數據源1查詢
   @DS("datasource1")
    public List<Map> getAllUser1(){
        return moredataDao.getAllUser();
    }
    //使用數據源2查詢
    @DS("datasource2")
    public List<Map> getAllUser2(){
        return moredataDao.getAllUser();
    }

    //使用數據源1插入數據
    @DS("datasource1")
    public Long addUserGetID1(User user){
        return moredataDao.addUserGetID(user);
    }
    //使用數據源1插入數據
    @DS("datasource2")
    public Long addUserGetID2(User user){
        return moredataDao.addUserGetID(user);
    }

    //使用數據源1插入數據
    @DS("datasource1")
    public void addUser1(User user){
        moredataDao.addUser(user);
    }

    //使用數據源2插入數據
    @DS("datasource2")
    public void addUser2(User user){
        moredataDao.addUser(user);
    }

    @Transactional
    public void test1(){

       moredataDao.addUserGetID(new User("mdx1",18));
       int a =10/0;
       moredataDao.addUserGetID(new User("mdxl1",20));

    }
}

八、建立controller

@Controller
public class RWController {


    @Autowired
    UserService userService;

    //走數據源1庫
    @GetMapping(value = "/test1")
    @ResponseBody
    public String testOne(){
        User user = new User("mjt01",20);
        userService.addUser1(user);
        return "success";
    }

    //使用數據源2插入數據
    @GetMapping(value = "/test2")
    @ResponseBody
    public String testTwo(){
        User user = new User("mjt02",20);
        userService.addUser2(user);
        return "success";
    }

}

九、mysql多數據源配置類

      5個配置文件,切記若是照着寫的話,當心裏面的路徑要準確對應上數據庫

//import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
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 org.springframework.transaction.PlatformTransactionManager;

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

/**
 * 多數據源配置類
 * Created by pure on 2018-05-06.
 */
@Configuration
public class DataSourceConfig {
    //數據源1
    @Bean(name = "datasource1")
    @ConfigurationProperties(prefix = "spring.datasource.db1") // application.properteis中對應屬性的前綴
    public DataSource dataSource1() {
        return DataSourceBuilder.create().build();
    }

    //數據源2
    @Bean(name = "datasource2")
    @ConfigurationProperties(prefix = "spring.datasource.db2") // application.properteis中對應屬性的前綴
    public DataSource dataSource2() {
        return DataSourceBuilder.create().build();
    }

    /**
     * 動態數據源: 經過AOP在不一樣數據源之間動態切換
     * @return
     */
    @Primary
    @Bean(name = "dynamicDataSource")
    public DataSource dynamicDataSource() {
        DynamicDataSource dynamicDataSource = new DynamicDataSource();
        // 默認數據源
        dynamicDataSource.setDefaultTargetDataSource(dataSource1());
        // 配置多數據源
        Map<Object, Object> dsMap = new HashMap();
        dsMap.put("datasource1", dataSource1());
        dsMap.put("datasource2", dataSource2());

        dynamicDataSource.setTargetDataSources(dsMap);
        return dynamicDataSource;
    }

    /**
     * 配置@Transactional註解事物
     * @return
     */
    @Bean
    public PlatformTransactionManager transactionManager() {
        return new DataSourceTransactionManager(dynamicDataSource());
    }
}
public class DataSourceContextHolder {
    /**
     * 默認數據源
     */
    public static final String DEFAULT_DS = "datasource1";

    private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();

    // 設置數據源名
    public static void setDB(String dbType) {
        System.out.println("切換到{"+dbType+"}數據源");
        contextHolder.set(dbType);
    }

    // 獲取數據源名
    public static String getDB() {
        return (contextHolder.get());
    }

    // 清除數據源名
    public static void clearDB() {
        contextHolder.remove();
    }
}
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface DS {
    String value() default "datasource1";
}
public class DynamicDataSource extends AbstractRoutingDataSource {
    @Override
    protected Object determineCurrentLookupKey() {
        System.out.println("數據源爲"+DataSourceContextHolder.getDB());
        return DataSourceContextHolder.getDB();
    }
}
@Aspect
@Component
public class DynamicDataSourceAspect {

    @Before("@annotation(com.springboot2.mjt04.config.mysql.DS)")
    public void beforeSwitchDS(JoinPoint point){
        //得到當前訪問的class
        Class<?> className = point.getTarget().getClass();
        //得到訪問的方法名
        String methodName = point.getSignature().getName();
        //獲得方法的參數的類型
        Class[] argClass = ((MethodSignature)point.getSignature()).getParameterTypes();
        String dataSource = DataSourceContextHolder.DEFAULT_DS;
        try {
            // 獲得訪問的方法對象
            Method method = className.getMethod(methodName, argClass);
            // 判斷是否存在@DS註解
            if (method.isAnnotationPresent(DS.class)) {
                DS annotation = method.getAnnotation(DS.class);
                // 取出註解中的數據源名
                dataSource = annotation.value();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        // 切換數據源
        DataSourceContextHolder.setDB(dataSource);
    }

    @After("@annotation(com.springboot2.mjt04.config.mysql.DS)")
    public void afterSwitchDS(JoinPoint point){
        DataSourceContextHolder.clearDB();
    }
}

      最終目錄結構圖:springboot

十、注意的問題

      10.1 出現這個錯誤 jdbcUrl is required with driverClassName.運行出現這個過程是由於在多數據源的狀況下,springboot2.0與1.X版本都不一樣配置屬性,解決jdbcUrl is required with driverClassName.問題,點擊這裏,可是我如今已經改過來了,之前是mybatis

spring.datasource.db1.url=jdbc:mysql://127.0.0.1:3306/test_msg2?useUnicode=true&characterEncoding=utf-8&useSSL=false

      而如今添加了jdbc-urlmvc

spring.datasource.db1.jdbc-url=jdbc:mysql://127.0.0.1:3306/test_msg2?useUnicode=true&characterEncoding=utf-8&useSSL=false

      10.2 包名路徑跟換app

      之前1.X版本爲ide

import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;

      而如今2.X版本

import org.springframework.boot.jdbc.DataSourceBuilder;

      注意一下就好,由於我都給你們改好了。

      5.3 事物能夠正常使用,也支持讀寫分離,不過在事物的方法可能比springmvc的項目麻煩些,畢竟目前個人技術只能用註解才能切換數據源,目前我沒有成功找到在配置類根據方法前綴名就能夠判斷數據源的。

      5.4 這個是application啓動類上面的一個註解,代表是不使用DataSourceAutoCOnfiguration.class,由於咱們的是多個數據源,不能默認使用一個單數據源,因此要加上這個。

@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})

      成功!不懂能夠私信我或者留言就好。

相關文章
相關標籤/搜索