CentOS7搭建MariaDB主从
目录结构如下:
4.0.0
org.springframework.boot
spring-boot-starter-parent
2.2.0.RELEASE
com.nifujia
data
0.0.1-SNAPSHOT
data
SpringBoot2+Druid+MyBatis+读写分离
UTF-8
UTF-8
1.8
org.springframework.boot
spring-boot-starter
org.mybatis.spring.boot
mybatis-spring-boot-starter
1.3.2
mysql
mysql-connector-java
runtime
com.alibaba
druid
1.1.11
org.springframework.boot
spring-boot-starter-aop
org.projectlombok
lombok
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-devtools
true
org.springframework.boot
spring-boot-starter-test
test
org.junit.vintage
junit-vintage-engine
data
src/main/java
**/*.properties
**/*.xml
true
src/main/resources
org.apache.maven.plugins
maven-war-plugin
org.apache.maven.plugins
maven-compiler-plugin
1.8
org.apache.maven.plugins
maven-surefire-plugin
true
**/*Test*.java
true
server:
port: 8080
tomcat:
uri-encoding: UTF-8
servlet:
context-path: /data
spring:
http:
encoding:
charset: UTF-8
jackson:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: GMT+8
default-property-inclusion: NON_NULL
druid:
type: com.alibaba.druid.pool.DruidDataSource
master:
url: jdbc:mysql://192.168.174.129:3306/spring?characterEncoding=UTF-8&autoReconnect=true&zeroDateTimeBehavior=convertToNull&useUnicode=true&serverTimezone=UTC
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: mysql
initialSize: 5
minIdle: 1
#maxIdle: 10
maxActive: 100
maxWait: 60000
timeBetweenEvictionRunsMillis: 60000
minEvictableIdleTimeMillis: 300000
validationQuery: SELECT 1 FROM DUAL
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
poolPreparedStatements: true
maxPoolPreparedStatementPerConnectionSize: 20
filters: stat,wall
useGlobalDataSourceStat: true
slave:
url: jdbc:mysql://192.168.174.135:3306/spring?characterEncoding=UTF-8&autoReconnect=true&zeroDateTimeBehavior=convertToNull&useUnicode=true&serverTimezone=UTC
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: mysql
initialSize: 5
minIdle: 1
#maxIdle: 10
maxActive: 100
maxWait: 60000
timeBetweenEvictionRunsMillis: 60000
minEvictableIdleTimeMillis: 300000
validationQuery: SELECT 1 FROM DUAL
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
poolPreparedStatements: true
maxPoolPreparedStatementPerConnectionSize: 20
filters: stat,wall
useGlobalDataSourceStat: true
mybatis:
type-aliases-package: com.nifujia.model
mapper-locations: classpath:com/nifujia/mapper/*.xml
logging:
level:
tk.mybatis: TRACE
mybatis提供了一个类叫AbstractRoutingDataSource,重写determineCurrentLookupKey()方法,达到动态切换数据源的目的。
DataSourceConfiguration.java
@Configuration
@Slf4j
public class DataSourceConfiguration {
@Value("${druid.type}")
public Class extends DataSource> dataSourceType;
@Bean(name = "masterDataSource")
@Primary
@ConfigurationProperties(prefix = "druid.master")
public DataSource masterDataSource() {
DataSource masterDataSource = DataSourceBuilder.create().type(dataSourceType).build();
log.info("=====================MASTER======================" + masterDataSource);
return masterDataSource;
}
@Bean(name = "slaveDataSource")
@ConfigurationProperties(prefix = "druid.slave")
public DataSource slaveDataSource() {
DataSource slaveDataSource = DataSourceBuilder.create().type(dataSourceType).build();
log.info("=====================SLAVE======================" + slaveDataSource);
return slaveDataSource;
}
@Bean
public DataSource routingDataSource(@Qualifier("masterDataSource") DataSource masterDataSource,
@Qualifier("slaveDataSource") DataSource slaveDataSource) {
Map
DataBaseContextHolder.java
public enum DataBaseType {
MASTER, SLAVE
}
private static final ThreadLocal context = new ThreadLocal<>();
public static void setDataBaseType(DataBaseType dataBaseType) {
if (dataBaseType == null) {
throw new NullPointerException();
}
context.set(dataBaseType);
}
public static DataBaseType getDataBaseType() {
return context.get() == null ? DataBaseType.MASTER : context.get();
}
public static void clearDataBaseType() {
context.remove();
}
public class ReadWriteSplitRoutingDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return DataBaseContextHolder.getDataBaseType();
}
}
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface ReadOnlyAnnotation {
}
@Aspect
@Slf4j
public class ReadOnlyAnnotationInterceptor implements Ordered {
@Around("@annotation(readOnlyAnnotation)")
public Object proceed(ProceedingJoinPoint joinPoint, ReadOnlyAnnotation readOnlyAnnotation) throws Throwable {
try {
log.info("==================开始切换数据源为只读,从数据源==================");
DataBaseContextHolder.setDataBaseType(DataBaseContextHolder.DataBaseType.SLAVE);
Object proceed = joinPoint.proceed();
return proceed;
} finally {
log.info("=================切换为主数据源=========================");
DataBaseContextHolder.clearDataBaseType();
}
}
@Override
public int getOrder() {
return 0;
}
}
主从数据库都开启日志,查看日志文件查询哪个库,之后,关闭日志。
#查看是否开启日志记录
SHOW VARIABLES WHERE Variable_name="general_log";
#显示为OFF为关闭
#临时开启日志记录,重启服务器之后失效
SET GLOBAL general_log=ON;
#查看日志的名称
SHOW VARIABLES WHERE Variable_name="general_log_file";
#登录MariaDB服务器,查看日志位置
find / --name "日志名"
tail -f /var/lib/mysql/localhost.log
#主从服务器,都关闭日志
SET GLOBAL general_log=OFF;