前言
首先为什么要做读写分离呢,大多数项目都是读的操作的次数远远要比写操作的次数多,所以让MySQL的主服务器做写操作,从服务器做读操作,下面详细的说一下如何利用MyCat做读写分离,至于MySQL的安装和搭建MySQL的主从复制请看我另一篇博客 Linux上MySQL安装和搭建MySQL的主从复制和读写分离
MyCat的安装及启动
环境装备
虚拟机:192.168.50.152(MyCat) 虚拟机:192.168.50.150(MySQl主) 虚拟机:192.168.50.151(MySQl从)
我们从网上下载一个MyCat的压缩包,放到了/usr/local这个路径,并解压,解压完之后有一个mycat的文件夹
我们进入mycat的这个文件夹,编辑conf文件夹下的schema.xml
<
?xml version="1.0" encoding="UTF
-8"
?>
<
!DOCTYPE mycat
:schema SYSTEM "schema.dtd"
>
<mycat
:schema xmlns
:mycat="http
://io.mycat/"
>
<
!-- mycat_testdb是mycat的逻辑库名称
-->
<schema name="mycat_testdb" checkSQLschema="true" sqlMaxLimit="100" >
</schema
>
<
!-- database 是MySQL数据库的库名
-->
<dataNode name="dn1" dataHost="localhost1" database="test" />
<dataHost name="localhost1" maxCon="1000" minCon="10" balance="3" writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100"
>
<heartbeat
>select user()</heartbeat
>
<
!-- 可以配置多个主从
-->
<writeHost host="hostM1" url="192.168.50.150:3306" user="root" password="root">
<!-- 可以配置多个从库 -->
<readHost host="hostS2" url="192.168.50.151:3306" user="root" password="root" />
</writeHost>
</dataHost
>
</mycat
:schema
>
启动MyCat,进入MyCat下的bin目录,执行如下命令
./mycat
start
查看是否启动成功,查看MyCat下的logs文件夹下的wrapper.log,看到successfully就算启动成功
配置SpringBoot项目
新建yml文件,配置读和写的JDBC连接
spring:
datasource:
select:
jdbc-url: jdbc
:mysql
://192.168.50.152
:8066/mycat_testdb
driver-class-name: com.mysql.jdbc.Driver
username: user
password: user
update:
jdbc-url: jdbc
:mysql
://192.168.50.152
:8066/mycat_testdb
driver-class-name: com.mysql.jdbc.Driver
username: root
password: 123456
type: com.alibaba.druid.pool.DruidDataSource
三个配置文件
@Configuration
public class DataSourceConfig {
@Bean(name
= "selectDataSource")
@ConfigurationProperties(prefix
= "spring.datasource.select")
public DataSource
dataSource1() {
return DataSourceBuilder
.create().build();
}
@Bean(name
= "updateDataSource")
@ConfigurationProperties(prefix
= "spring.datasource.update")
public DataSource
dataSource2() {
return DataSourceBuilder
.create().build();
}
}
@Component
@Lazy(false)
public class DataSourceContextHolder {
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();
}
}
@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();
}
}
配置aop
@Aspect
@Component
@Lazy(false)
@Order(0)
public class SwitchDataSourceAOP {
@Before("execution(* com.example.demo.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 {
DataSourceContextHolder
.setDbType("updateDataSource");
}
}
}
controller、entity、mapper、service的编写
@RestController
public class UserController {
@Autowired
private UserService userService
;
@RequestMapping("/findUser")
public List
<UserEntity> findUser() {
return userService
.findUser();
}
@RequestMapping("/insertUser")
public List
<UserEntity> insertUser(String userName
) {
return userService
.insertUser(userName
);
}
}
public class UserEntity {
private String userName
;
public String
getUserName() {
return userName
;
}
public void setUserName(String userName
) {
this.userName
= userName
;
}
}
public interface UserMapper {
@Select("SELECT * FROM test ")
public List
<UserEntity> findUser();
@Select("insert into test values (#{userName}); ")
public List
<UserEntity> insertUser(@Param("userName") String userName
);
}
@Service
public class UserService {
@Autowired
private UserMapper userMapper
;
public List
<UserEntity> findUser() {
return userMapper
.findUser();
}
public List
<UserEntity> insertUser(String userName
) {
return userMapper
.insertUser(userName
);
}
}
启动项目,进行测试 我们插入一条userName为123456的数据 IDEA控制台打出来的日志为updateDataSource数据源
然后我们查询一下刚才插入的数据
IDEA控制台打出来的日志为selectDataSource数据源
至此基于SpringBootl利用MyCat实现对MySQL的读写分离就搭建完毕了
总结
通过这次颗粒归仓,发现自己对这个东西还是不熟练,还是要多多学习,积累自己!