基于Docker搭建Mycat环境实现Mysql数据库的读写分离
2019-07-19 11:54
736 查看
参考每特教育上课内容,但是电脑配置有点低,这边就改用docker进行搭建了。
1.搭建环境
1.1 搭建Mysql主从服务
1.1.1 下载Mysql镜像docker pull mysql:5.71.1.2 创建Mysql挂载目录
mkdir -p /opt/mysql/master/{conf,data,logs}
mkdir -p /opt/mysql/slave/{conf,data,logs}1.1.3 进入conf目录中编辑my.cnf
主配置文件
[client] port=3306 default-character-set=utf8 [mysql] default-character-set=utf8 [mysqld] character_set_server=utf8 sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES # 配置大小写不敏感 lower_case_table_names=1 server_id=66 ###服务器id log-bin=mysql-bin ###开启日志文件
从配置文件
port=3306 default-character-set=utf8 [mysql] default-character-set=utf8 [mysqld] character_set_server=utf8 sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES # 配置大小写不敏感 lower_case_table_names=1 server_id=88 ###服务器id log-bin=mysql-bin ###开启日志文件 binlog_do_db=test1.1.4 运行Mysql容器
docker run -it --name mysql-master -p 3308:3306 -e MYSQL_ROOT_PASSWORD=root --privileged=true -v /opt/mysql/master/conf/my.cnf:/etc/mysql/my.cnf -v /opt/mysql/master/data:/var/lib/mysql -v /opt/mysql/master/logs:/var/log/mysql -d --restart=always mysql:5.7
docker run -it --name mysql-slave -p 3309:3306 -e MYSQL_ROOT_PASSWORD=root --privileged=true -v /opt/mysql/slave/conf/my.cnf:/etc/mysql/my.cnf -v /opt/mysql/slave/data:/var/lib/mysql -v /opt/mysql/slave/logs:/var/log/mysql -d --restart=always mysql:5.71.1.5 查看容器
1.1.6 连接到主服务器
查询主对应配置文件中的server_id,查询到了说明已经以上步骤ok。
show variables like '%server_id%';
查询主状态信息
show master status;
1.1.6 连接从服务器
同步主服务器配置
change master to master_host='192.168.0.171',master_user='root',master_password='root', master_log_file='mysql-bin.000005',master_log_pos=1188;
开始同步
start slave;
检查从服务器复制功能状态
SHOW SLAVE STATUS;
Slave_IO_Running 、Slave_SQL_Running 都为Yes说明配置成功,验证效果就不截图了。
1.2 搭建Mycat环境
参考博客:https://blog.csdn.net/weixin_39781526/article/details/84867397
1.2.1 获取资源#先获取mycat包 wget Mycat-server-1.6.5-release-20180122220033-linux.tar.gz;1.2.2 编写Dockerfile
FROM java:8 USER root COPY Mycat-server-1.6.5-release-20180122220033-linux.tar.gz / RUN tar -zxf /Mycat-server-1.6.5-release-20180122220033-linux.tar.gz ENV MYCAT_HOME=/mycat ENV PATH=$PATH:${MYCAT_HOME}/bin WORKDIR $MYCAT_HOME/bin RUN chmod u+x ./mycat EXPOSE 8066 9066 CMD ["./mycat", "console"]1.2.3 获取配置文件
tar -zxvf Mycat-server-1.6.5-release-20180122220033-linux.tar.gz mv mycat/conf/ conf1.2.4 修改mycat配置文件
真正需要修改的只有三个文件,具体官方文档写的很详细;
(1):schema.xml ,(2):server.xml,(3):rule.xml;
现在搭建的是Mysql读写分离,修改schema.xml、server.xm即可。rule.xml用于分表分库配置文件。
<?xml version="1.0"?> <!DOCTYPE mycat:schema SYSTEM "schema.dtd"> <mycat:schema xmlns:mycat="http://io.mycat/"> <!-- TESTDB1 是mycat的逻辑库名称,链接需要用的 --> <schema name="mycat_testdb" checkSQLschema="false" sqlMaxLimit="100" dataNode="dn1"></schema> <!-- database 是MySQL数据库的库名 --> <dataNode name="dn1" dataHost="localhost1" database="test" /> <!-- dataNode节点中各属性说明: name:指定逻辑数据节点名称; dataHost:指定逻辑数据节点物理主机节点名称; database:指定物理主机节点上。如果一个节点上有多个库,可使用表达式db$0-99, 表示指定0-99这100个数据库; dataHost 节点中各属性说明: name:物理主机节点名称; maxCon:指定物理主机服务最大支持1000个连接; minCon:指定物理主机服务最小保持10个连接; writeType:指定写入类型; 0,只在writeHost节点写入; 1,在所有节点都写入。慎重开启,多节点写入顺序为默认写入根据配置顺序,第一个挂掉切换另一个; dbType:指定数据库类型; dbDriver:指定数据库驱动; balance:指定物理主机服务的负载模式。 0,不开启读写分离机制; 1,全部的readHost与stand by writeHost参与select语句的负载均衡,简单的说,当双主双从模式(M1->S1,M2->S2,并且M1与 M2互为主备),正常情况下,M2,S1,S2都参与select语句的负载均衡; 2,所有的readHost与writeHost都参与select语句的负载均衡,也就是说,当系统的写操作压力不大的情况下,所有主机都可以承担负载均衡; --> <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.0.171:3308" user="root" password="root"> <!-- 可以配置多个从库 --> <readHost host="hostS2" url="192.168.0.171:3309" user="root" password="root" /> </writeHost> </dataHost> </mycat:schema>
<?xml version="1.0" encoding="UTF-8"?> <!-- - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. --> <!DOCTYPE mycat:server SYSTEM "server.dtd"> <mycat:server xmlns:mycat="http://io.mycat/"> <!-- 读写都可用的用户 --> <user name="root" defaultAccount="true"> <property name="password">123456</property> <property name="schemas">mycat_testdb</property> <!-- 表级 DML 权限设置 --> <!-- <privileges check="false"> <schema name="TESTDB" dml="0110" > <table name="tb01" dml="0000"></table> <table name="tb02" dml="1111"></table> </schema> </privileges> --> </user> <!-- 只读用户 --> <user name="user"> <property name="password">user</property> <property name="schemas">mycat_testdb</property> <property name="readOnly">true</property> </user> </mycat:server>1.2.5 执行Dockerfile
docker build -t mycat:1.6.5 .1.2.6 编写mycat启动脚本
docker run -d --rm -p:8066:8066 --name mycat-mysql -p 9066:9066 -v $PWD/logs:/mycat/logs -v $PWD/conf:/mycat/conf mycat:1.6.5
1.2.7 验证效果
连接这四个服务
在root服务修改数据,其他三个服务的数据自动同步相应的修改。
在user服务修改数据报错,只允许读数据。
2 SpringBoot整合Mycat实现读写分离
2.1 导入Maven依赖
<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.wanzh</groupId> <artifactId>mycat_demo</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> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
2.2 配置application.yml
spring: datasource: ###可读数据源 select: jdbc-url: jdbc:mysql://192.168.0.171:8066/mycat_testdb driver-class-name: com.mysql.jdbc.Driver username: user password: user ####可写数据源 update: jdbc-url: jdbc:mysql://192.168.0.171:8066/mycat_testdb driver-class-name: com.mysql.jdbc.Driver username: root password: 123456 type: com.alibaba.druid.pool.DruidDataSource
2.3 配置多数据源环境
package com.wanzh.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(); } }
package com.wanzh.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(); } }
package com.wanzh.config; 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; //在Spring 2.0.1中引入了AbstractRoutingDataSource, 该类充当了DataSource的路由中介, 能有在运行时, 根据某种key值来动态切换到真正的DataSource上。 @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(); } }
2.4 AOP拦截动态切换数据源
package com.wanzh.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.wanzh.config.DataSourceContextHolder; @Aspect @Component @Lazy(false) @Order(0) // Order设定AOP执行顺序 使之在数据库事务上先执行 public class SwitchDataSourceAOP { // 这里切到你的方法目录 @Before("execution(* com.wanzh.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"); } } }
2.5 整合Mybatis
package com.wanzh.entity; public class User { private int id; private String name; 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; } }
package com.wanzh.mapper; import java.util.List; import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Select; import com.wanzh.entity.User; public interface UserMapper { @Select("SELECT id,name FROM sys_user ") public List<User> findUser(); @Select("insert into sys_user(name) values (#{name}); ") public List<User> insertUser(@Param("name") String name); }
package com.wanzh.service; import java.util.List; import com.wanzh.entity.User; public interface UserService { public List<User> findUser(); public List<User> insertUser(String name); }
package com.wanzh.service.impl; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.wanzh.entity.User; import com.wanzh.mapper.UserMapper; import com.wanzh.service.UserService; @Service("userService") public class UserServiceImpl implements UserService { @Autowired private UserMapper userMapper; public List<User> findUser() { return userMapper.findUser(); } public List<User> insertUser(String name) { return userMapper.insertUser(name); } }
package com.wanzh.controller; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; import com.wanzh.entity.User; import com.wanzh.service.UserService; @RestController public class UserController { @Autowired private UserService userService; @RequestMapping("/findUser") public List<User> findUser() { return userService.findUser(); } @RequestMapping(value="/insertUser",method=RequestMethod.POST) public List<User> insertUser(String name) { return userService.insertUser(name); } }
package com.wanzh; import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication @MapperScan(basePackages = "com.wanzh.mapper") public class App { public static void main(String[] args) { SpringApplication.run(App.class, args); } }
2.6 Postman测试
相关文章推荐
- 基于Docker搭建MySQL(MariaDB)+ mycat读写分离测试环境
- 基于docker ceph环境快速搭建体验
- 搭建基于springmvc,ibatis的工程实现读写分离,配置分离
- 基于CentOS搭建Docker环境
- MyCat实现mysql数据库的读写分离
- Centos 6.5环境实现本地局域网搭建YUM的方法【基于HTTP】
- 利用mycat实现mysql数据库读写分离的示例
- centos7基于Dockerfile搭建jdk、tomcat、maven运行环境
- 搭建基于Docker的PHP开发环境的详细教程
- springmvc配置mysql数据库读写分离(基于注解aop)加上(搭建mysql主从同步)
- 基于MyCAT实现MySQL读写分离
- iOS基于XMPP实现即时通讯之一、环境的搭建
- 基于Docker镜像的开发环境搭建
- 基于MyCat实现的MySQL读写分离
- 基于MyCat的MySql集群的读写分离搭建与配置
- •搭建LAMP环境及快速部署双网站并实现基于域名的虚拟主机
- iOS基于XMPP实现即时通讯之一、环境的搭建
- 完整的ssm环境搭建 基于maven3.6.0使用mysql数据库 用 mybatis-spring-springmvc 搭建环境 主要在已有包结构下配置所需要的配置文件包括:pom.
- DWCS6搭建jsp开发环境及使用ajax实现用户注册(基于文件)