Docker-一台服务器用docker实现mysql主从配置
package com.dao.split;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @Created with IntelliJ IDEA
* @Description: 动态的选择需要的数据源
* @Package: com.dao.split
* @author: FLy-Fly-Zhang
* @Date: 2020/2/10
* @Time: 12:22
*/
public class DynamicDataSourceHolder {
private static Logger logger=LoggerFactory.getLogger(DynamicDataSourceHolder.class);
//线程本地变量
//ThreadLocal为变量在每个线程中都创建了一个副本,那么每个线程可以访问自己内部的副本变量
private static ThreadLocal<String> contextHolder=new ThreadLocal<>();
public static final String DB_MASTER="master";
//若是多个从库,这里可以变为一个常量数组,在返回slave的地方使用random随机取
public static final String DB_SLAVE="slave";
/**
* 获取线程的DBType
* @return
*/
public static String getDbType(){
String db=contextHolder.get();
if(db==null){
db=DB_MASTER;
}
return db;
}
/**
* 设置线程的dbType
* @param db
*/
public static void setDbtype(String db){
logger.debug("所使用的数据源为"+db);
contextHolder.set(db);
}
/**
* 清理连接类型
*/
public static void clearDBType(){
contextHolder.remove();
}
}
package com.dao.split;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.executor.keygen.SelectKeyGenerator;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import java.util.Locale;
import java.util.Properties;
/**
* @Created with IntelliJ IDEA
* @Description: mybatis拦截器
* 用来拦截sql信息,并通过判断返回使用主从库
* @Package: com.dao.split
* @author: FLy-Fly-Zhang
* @Date: 2020/2/10
* @Time: 12:49
*/
//mybatis会将增删改的操作封装在update里面,select封装在query里面
// 需要拦截的方法所在的类,方法名,参数,返回值
@Intercepts({@Signature(type = Executor.class,method = "update",args={MappedStatement.class,Object.class}),
@Signature(type = Executor.class,method = "query",
args={MappedStatement.class,Object.class,RowBounds.class,ResultHandler.class})})
public class DynamicDataSourceInterceptor implements Interceptor {
private Logger logger=LoggerFactory.getLogger(DynamicDataSourceInterceptor.class);
//\u0020 空格 判断字符串是不是这三个字符打头
private static final String REGEX=".*insert\\u0020.*|.*delete\\u0020.*|.*update\\u0020.*";
@Override
public Object intercept(Invocation invocation) throws Throwable {
//判断当前操作是不是事务的
boolean synchronizationActive=TransactionSynchronizationManager.isActualTransactionActive();
String lookupKey=DynamicDataSourceHolder.DB_MASTER;;
Object[] objects=invocation.getArgs(); //获取sql参数
MappedStatement mappedStatement=(MappedStatement)objects[0]; //objectsz中第一个参数就用来确定是CRUD
//不是事务
if(!synchronizationActive){
//读方法
if(mappedStatement.getSqlCommandType().equals(SqlCommandType.SELECT)){
//selectKey 为自增id查询主键即(select LAST_INSERT_ID()) 方法,使用主库查询
//一般我们插入数据返回自增主键时就调用select LAST_INSERT_ID()方法,插入时为主库,
// 查询时若切换则会导致数据发生错误
if(mappedStatement.getId().contains(SelectKeyGenerator.SELECT_KEY_SUFFIX)){
//lookupKey=DynamicDataSourceHolder.DB_MASTER;
}else{
//绑定sql objects[1]第二个参数就是sql
BoundSql boundSql=mappedStatement.getSqlSource().getBoundSql(objects[1]);
String sql=boundSql.getSql().toLowerCase(Locale.CHINA) //sql转换为中国时区
//将所有的制表符,换行符,回车替换为空格==>将sql变为一行
.replaceAll("\\t\\n\\r"," ");
//正则表达式匹配
if(sql.matches(REGEX)){
//lookupKey=DynamicDataSourceHolder.DB_MASTER;
}else{
lookupKey=DynamicDataSourceHolder.DB_SLAVE;
}
}
}
}
//else{ //事务类,都会改数据
//lookupKey=DynamicDataSourceHolder.DB_MASTER;
//}
//[{}] 占位符,用来替换后面的参数
logger.debug("设置方法[{}] use[{}]Strategy,SqlCommonType[{}]..",
mappedStatement.getId(),
lookupKey,
mappedStatement.getSqlCommandType().name());
DynamicDataSourceHolder.setDbtype(lookupKey);
return invocation.proceed(); //结束拦截,程序继续进行
}
/**
* 拦截配置
* @param o
* @return
*/
@Override
public Object plugin(Object o) {
//如果拦截的对象是Executor类型的,就进行拦截
//Executor 在mybatis中做CRUD操作
if(o instanceof Executor)
return Plugin.wrap(o,this);
return o;
}
@Override
public void setProperties(Properties properties) {
}
}
package com.dao.split;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
/**
* @Created with IntelliJ IDEA
* @Description: 动态数据源:返回拦截后输出的结果
* @Package: com.dao.split
* @author: FLy-Fly-Zhang
* @Date: 2020/2/10
* @Time: 12:14
*/
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return DynamicDataSourceHolder.getDbType();
}
}
<configuration>
<settings>
<setting name="useGeneratedKeys" value="true"/>
<setting name="useColumnLabel" value="true"/>
<setting name="mapUnderscoreToCamelCase" value="true"/>
settings>
<plugins>
<plugin interceptor="com.dao.split.DynamicDataSourceInterceptor">plugin>
plugins>
configuration>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:property-placeholder location="classpath:jdbc.properties"/>
<bean id="abstractDataSource" abstract="true" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="maxPoolSize" value="30"/>
<property name="minPoolSize" value="10"/>
<property name="autoCommitOnClose" value="false"/>
<property name="checkoutTimeout" value="10000"/>
<property name="acquireRetryAttempts" value="2"/>
bean>
<bean id="master" parent="abstractDataSource">
<property name="driverClass" value="${jdbc.driver}"/>
<property name="jdbcUrl" value="${jdbc.master.url}"/>
<property name="user" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
bean>
<bean id="slave" parent="abstractDataSource">
<property name="driverClass" value="${jdbc.driver}"/>
<property name="jdbcUrl" value="${jdbc.slave.url}"/>
<property name="user" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
bean>
<bean id="dynamicDataSource" class="com.dao.split.DynamicDataSource">
<property name="targetDataSources">
<map>
<entry value-ref="master" key="master">entry>
<entry value-ref="slave" key="slave">entry>
map>
property>
bean>
<bean id="dataSource" class="org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy">
<property name="targetDataSource">
<ref bean="dynamicDataSource"/>
property>
bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="configLocation" value="classpath:mybatis-config.xml"/>
<property name="typeAliasesPackage" value="com.entity"/>
<property name="mapperLocations" value="classpath:mapper/*.xml"/>
bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
<property name="basePackage" value="com.dao"/>
bean>
beans>
需要注意的是,我在拦截器代码中加了日志,若您也想配置日志,请参考此篇博客:Log-ssm中日志文件的配置
若不想配置,只需要删除出现Logger的那两行代码。
在此,我也将我的pom文件放在此处,仅供参考。
<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/maven-v4_0_0.xsd">
<modelVersion>4.0.0modelVersion>
<groupId>comgroupId>
<artifactId>storeartifactId>
<version>1.0.0-SNAPSHOTversion>
<packaging>warpackaging>
<name>store Maven Webappname>
<url>http://maven.apache.orgurl>
<properties>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
<maven.compiler.source>1.7maven.compiler.source>
<maven.compiler.target>1.7maven.compiler.target>
<spring.version>4.3.7.RELEASEspring.version>
properties>
<dependencies>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.12version>
<scope>testscope>
dependency>
<dependency>
<groupId>ch.qos.logbackgroupId>
<artifactId>logback-classicartifactId>
<version>1.2.3version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-coreartifactId>
<version>${spring.version}version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-beansartifactId>
<version>${spring.version}version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-contextartifactId>
<version>${spring.version}version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-jdbcartifactId>
<version>${spring.version}version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-txartifactId>
<version>${spring.version}version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webartifactId>
<version>${spring.version}version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webmvcartifactId>
<version>${spring.version}version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-testartifactId>
<version>${spring.version}version>
<scope>testscope>
dependency>
<dependency>
<groupId>javax.servletgroupId>
<artifactId>javax.servlet-apiartifactId>
<version>3.1.0version>
dependency>
<dependency>
<groupId>com.fasterxml.jackson.coregroupId>
<artifactId>jackson-databindartifactId>
<version>2.8.7version>
dependency>
<dependency>
<groupId>commons-collectionsgroupId>
<artifactId>commons-collectionsartifactId>
<version>3.2.2version>
dependency>
<dependency>
<groupId>commons-fileuploadgroupId>
<artifactId>commons-fileuploadartifactId>
<version>1.3.2version>
dependency>
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatisartifactId>
<version>3.4.2version>
dependency>
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatis-springartifactId>
<version>1.3.0version>
dependency>
<dependency>
<groupId>com.mchangegroupId>
<artifactId>c3p0artifactId>
<version>0.9.5.4version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>5.1.37version>
dependency>
<dependency>
<groupId>net.coobirdgroupId>
<artifactId>thumbnailatorartifactId>
<version>0.4.8version>
dependency>
<dependency>
<groupId>com.github.pengglegroupId>
<artifactId>kaptchaartifactId>
<version>2.3.2version>
dependency>
dependencies>
<build>
<finalName>storefinalName>
<plugins>
<plugin>
<groupId>org.apache.maven.pluginsgroupId>
<artifactId>maven-compiler-pluginartifactId>
<version>3.6.1version>
<configuration>
<source>1.8source>
<target>1.8target>
<encoding>UTF8encoding>
configuration>
plugin>
plugins>
build>
project>