這節說代碼如何和mycat實現讀寫分離
1、pom.xml
<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.mayikt</groupId>
<artifactId>springboot-mybatis-02</artifactId>
<version>0.0.1-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.4.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</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>
<scope>runtime</scope>
</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.23</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.1.0</version>
<configuration>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
2、application.yml配置兩個數據源,一讀一寫
spring:
datasource:
###可讀數據源
select:
jdbc-url: jdbc:mysql://你的IP:8066/my_db1
driver-class-name: com.mysql.jdbc.Driver
username: user
password: user
####可寫數據源
update:
jdbc-url: jdbc:mysql://你的IP:8066/my_db1
driver-class-name: com.mysql.jdbc.Driver
username: root
password: 123456
type: com.alibaba.druid.pool.DruidDataSource
3、AppMybatis.java
package com.mayikt;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@MapperScan(basePackages = "com.mayikt.mapper")
public class AppMybatis {
public static void main(String[] args) {
SpringApplication.run(AppMybatis.class, args);
}
}
4、用註釋 bean的方法,配置兩個數據源 DataSourceConfig.java
package com.mayikt.config;
import javax.sql.DataSource;
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;
@Configuration
public class DataSourceConfig {
// 創建可讀數據源
@Bean(name = "selectDataSource")
@ConfigurationProperties(prefix = "spring.datasource.select") // application.properteis中對應屬性的前綴
public DataSource dataSource1() {
return DataSourceBuilder.create().build();
}
// 創建可寫數據源
@Bean(name = "updateDataSource")
@ConfigurationProperties(prefix = "spring.datasource.update") // application.properteis中對應屬性的前綴
public DataSource dataSource2() {
return DataSourceBuilder.create().build();
}
}
5、DataSourceContextHolder
.java
package com.mayikt.config;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
@Component
@Lazy(false)
public class DataSourceContextHolder {
// 採用ThreadLocal 保存本地多數據源
private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();
// 設置數據源類型
public static void setDbType(String dbType) {
contextHolder.set(dbType);
}
public static String getDbType() {
return contextHolder.get();
}
public static void clearDbType() {
contextHolder.remove();
}
}
6、DynamicDataSource.java
package com.mayikt.config;
//在Spring 2.0.1中引入了AbstractRoutingDataSource, 該類充當了DataSource的路由中介, 能有在運行時, 根據某種key值來動態切換到真正的DataSource上。
import java.util.HashMap;
import java.util.Map;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import org.springframework.stereotype.Component;
@Component
@Primary
public class DynamicDataSource extends AbstractRoutingDataSource {
@Autowired
@Qualifier("selectDataSource")
private DataSource selectDataSource;
@Autowired
@Qualifier("updateDataSource")
private DataSource updateDataSource;
/**
* 這個是主要的方法,返回的是生效的數據源名稱
*/
@Override
protected Object determineCurrentLookupKey() {
System.out.println("DataSourceContextHolder:::" + DataSourceContextHolder.getDbType());
return DataSourceContextHolder.getDbType();
}
/**
* 配置數據源信息
*/
@Override
public void afterPropertiesSet() {
Map<Object, Object> map = new HashMap<>();
map.put("selectDataSource", selectDataSource);
map.put("updateDataSource", updateDataSource);
setTargetDataSources(map);
setDefaultTargetDataSource(updateDataSource);
super.afterPropertiesSet();
}
}
7、SwitchDataSourceAOP 這個主要做AOP攔截數據語句,判斷是DML還是查詢,走相應的數據源,實現讀寫分離
package com.mayikt.aop;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.context.annotation.Lazy;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import com.mayikt.config.DataSourceContextHolder;
@Aspect
@Component
@Lazy(false)
@Order(0) // Order設定AOP執行順序 使之在數據庫事務上先執行
public class SwitchDataSourceAOP {
// 這裏切到你的方法目錄
@Before("execution(* com.mayikt.service.*.*(..))")
public void process(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
if (methodName.startsWith("get") || methodName.startsWith("count") || methodName.startsWith("find")
|| methodName.startsWith("list") || methodName.startsWith("select") || methodName.startsWith("check")) {
// 讀
DataSourceContextHolder.setDbType("selectDataSource");
} else {
// 切換dataSource
DataSourceContextHolder.setDbType("updateDataSource");
}
}
}
8、UserMapper.java做數據庫操作
package com.mayikt.mapper;
import java.util.List;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import com.mayikt.entity.UserEntity;
public interface UserMapper {
@Select("SELECT user_name as userName FROM user ")
public List<UserEntity> findUser();
@Select("insert into user(user_name) values (#{userName}); ")
public List<UserEntity> insertUser(@Param("userName") String userName);
}
9、其它的server/controller自己實現。累了