服务器之家:专注于服务器技术及软件下载分享
分类导航

Mysql|Sql Server|Oracle|Redis|MongoDB|PostgreSQL|Sqlite|DB2|mariadb|Access|数据库技术|

服务器之家 - 数据库 - Redis - Redis整合MySQL主从集群的示例代码

Redis整合MySQL主从集群的示例代码

2021-11-19 17:34别团等shy哥发育 Redis

本文主要介绍了Redis整合MySQL主从集群的示例代码,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

redis作为承担缓存作用的数据库,一般会应用在高并发的场景里,而在这些高并发应用场景的数据库层面还会用到其他数据库的组件或集群以提升性能,比如用mysql主从集群实现读写分离效果、用mycat组件实现分库分表的功能。另外,redis本身会以集群的形式对外提供缓存服务。

1、用docker搭建mysql主从集群

这里用docker容器搭建如下图所示的mysql主从集群。

Redis整合MySQL主从集群的示例代码

  • 在主mysql服务器里操作的动作会自动同步到从nysql服务器,比如在主服务器里发起的“建数据库”“通过insert语句插入数据”和“通过delete语句删除数据”的动作都会同步到从服务器,并且这些操作都会在从服务器上被执行。通过这种同步的动作能确保主从数据库间的数据一致性。
  • 在项目里,一般是向“主服务器”里写数据,从“从服务器”里读数据,用这种“读写分离”的操作方式提升数据库性能。

具体搭建的步骤如下:

1.1 拉取mysql镜像

  开启一个命令窗口,在其中运行docker pull mysql:latest,下载最新的mysql镜像。下载完成后,通过docker images mysql能看到如下图所示的镜像i信息。

Redis整合MySQL主从集群的示例代码

1.2 创建配置文件夹

新建/root/redisconf/mastermysql/conf/root/redisconf/mastermysql/data两个目录,在其中将会保存主mysql服务器的配置信息和数据。同时新建/root/redisconf/slavemysql/conf/root/redisconf/slavemysql/data两个目录,在其中将会保存从mysql服务器的配置信息和数据。当然,目录可自行更改。

1.3 编写主服务器的配置文件信息

  在/root/redisconf/mastermysql/conf目录里新建一个my.cnf文件,在其中编写针对主mysql服务器的配置信息,主mysql服务器在启动时会读取其中的配置,具体代码如下所示:

?
1
2
3
4
5
6
[mysqld]
pid-file =/var/run/mysqld/mysqld.pid
socket =/var/run/mysqld/mysqld.sock
datadir =/var/lib/mysql
server-id =1
log-bin=mysql-master-bin

  第二行到第四行给出了mysql运行时的参数,在第五行里定义了该服务器的id(这个id需要和之后编写的从mysql服务器的server-id不一样,否则会出错),在第6行里制定了二进制文件的名字(为了搭建主从集群,建议加上这行配置)

1.4 启动mysql主服务器的容器

?
1
2
3
4
docker run -itd --privileged=true -p 3306:3306 \
--name mymastermysql -e mysql_root_password=123456\
-v /root/redisconf/mastermysql/conf:/etc/mysql/conf.d\
 -v /root/redisconf/mastermysql/data:/var/lib/mysql mysql:latest

-p3306:3306参数指定docker容器里mysql的工作端口3306映射到主机的3306端口
-itd参数指定该容器以后台交互模式的方式启动
--name参数指定该容器的名字
通过-e mysql_root_password=123456参数指定该容器运行时的环境变量,具体到这个场景,配置以用户名root登录到mysql服务器时所用到的密码123456.
两个-v参数指定外部主机和docker容器间映射的目录。由于在第三步把mysql启动时需要加载的my.cnf文件放在了/root/redisconf/mastermysql/conf目录里,因此这里需要把/root/redisconf/mastermysql/conf目录映射成容器内部mysql服务器的相关路径。
通过mysql:latest参数指定该容器是基于这个镜像生成的。

查看启动的容器:docker ps

Redis整合MySQL主从集群的示例代码

由此能确认mymastermysql启动成功。
查看该docker容器的ip地址:docker inspect mymastermysql

Redis整合MySQL主从集群的示例代码

可以看到,这里是172.17.0.2,这也是主mysql服务器所在的ip地址。

1.5 观察主服务器状态

  运行docker exec -it mymastermysql /bin/bash命令后进入该mymastermysql容器的命令行窗口,再运行mysql -u root -p命令,进入mysql服务器的命令行窗口,在这个mysql命令里,以-u参数指定用户名,随后需要输入密码(刚才设置的123456).

进入mysql服务器之后,再运行show master status命令观察主服务器的状态。

Redis整合MySQL主从集群的示例代码  

可以看到,主从集群同步所用到的日志文件是mysql-master-bin.000003,当前同步的位置是156,每次运行这个命令看到的结果未必相同,请记住这两个值,在设置从mysql服务器的主从同步关系时会用到。

1.6 配置mysql从服务器

  在/root/redisconf/slavemaster/conf目录里,新建一个名为my.cnf的文件,编写针对从mysql服务器的配置信息。同样的,从mysql服务器在启动时也会读取其中的配置,具体代码如下所示。

?
1
2
3
4
5
6
[mysqld]
pid-file=/var/run/mysqld/mysqld.pid
socket=/var/run/mysqld/mysqld.sock
datadir=/var/lib/mysql
server-id=2
log-bin=mysql-slave-bin

  该配置文件和第三步创建的主服务器的配置文件很相似,只不过在第5行更改了server-id(这里的取值不能和主mysql服务器的一致)。在第6行也是设置二进制文件的名字

1.7 启动mysql从服务器

?
1
2
3
4
5
docker run -itd --privileged=true -p 3316:3306\
 --name myslavemysql -e mysql_root_password=123456\
 -v /root/redisconf/slavemysql/conf:/etc/mysql/conf.d\
 -v /root/redisconf/slavemysql/data:/var/lib/mysql\
  mysql:latest

  这里在-p参数之后使用主机的3316端口映射docker容器的3306端口,因为之前主mysql服务器的docker容器已经映射到了3306端口,其他的参数和之前创建mymastermysql容器时很相似,就不再重复了。

  随后docker exec -it myslavemysql /bin/bash进入容器,进入后可以运行mysql -h 172.17.0.2 -u root -p命令,尝试在这个容器里连接主mysql服务器。其中172.17.0.2是主服务器的地址。随后输入root用户的密码123456,即可确认连接。

Redis整合MySQL主从集群的示例代码

  确认链接后,通过exit命令退出指向mymastermysql的连接,再通过mysql -h 127.0.0.1 -u root -p命令连接到本docker容器包含的从mysql服务器上。

1.8 确认主从关系

?
1
2
3
4
change master to master_host='172.17.0.2',master_port=3306,\
master_user='root',master_password='123456',\
master_log_pos=156,\
master_log_file='mysql-master-bin.000003';

   本命令运行在myslavemysql容器中的从mysql服务器里,通过master_host和master_port指定主服务器的ip地址和端口号,通过master_user和master_password设置了连接所用的用户名和密码。
  注意master_logpos和master_log_file两个参数的值需要和第5步图中的结果一致。

  运行完成后,需要再运行start slave命令启动主从复制的动作。运行后可以通过show slave status\g;命令查看主从复制的状态,如果slave_io_running和slave_sql_running这两项都是yes,并且没有其他异常,就说明配置主从复制成功。

Redis整合MySQL主从集群的示例代码

  此时如果再到主mysql服务器里运行create database redisdemo创建一个数据库,那么从库里虽然没有运行命令,但是也能看到redisdemo数据库,这说明已经成功地搭建了mysql主从复制集群。其中,主库地ip地址和端口号是172.17.0.2:3306,从库是172.17.0.3:3306.

主库

Redis整合MySQL主从集群的示例代码

从库

Redis整合MySQL主从集群的示例代码

2、准备数据

  由于已经成功地设置了主从复制模式,因此如下地建表和插入语句都只需要在主库里运行。

2.1 创建数据库

?
1
create database redisdemo

进入redisdemo数据库use redisdemo

2.2 创建student数据表

?
1
2
3
4
5
6
create table student(
    id int not null primary key,
    name char(20),
     age int,
     score float
    );

Redis整合MySQL主从集群的示例代码

2.3 向student表插入几条数据

?
1
2
3
insert into student(id,name,age,score) values(1,'peter',18,100);
insert into student(id,name,age,score) values(2,'tom',17,98);
insert into student(id,name,age,score) values(3,'john',17,99);

Redis整合MySQL主从集群的示例代码

从库里查看

Redis整合MySQL主从集群的示例代码

3、用java代码读写mysql集群和redis

3.1 引入redis和mysql依赖

?
1
2
3
4
5
6
7
8
9
10
11
12
13
<!-- https://mvnrepository.com/artifact/redis.clients/jedis -->
     <dependency>
         <groupid>redis.clients</groupid>
         <artifactid>jedis</artifactid>
         <version>3.3.0</version>
     </dependency>
 
     <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
     <dependency>
         <groupid>mysql</groupid>
         <artifactid>mysql-connector-java</artifactid>
         <version>8.0.21</version>
     </dependency>

Redis整合MySQL主从集群的示例代码

  java应用程序是向主mysql服务器写数据,这样写入地数据会自动同步到从mysql服务器上,而读数据时会先从redis缓存里读,读不到时再到从mysql里读。以下用代码实现

3.2 代码整合

mysqlclusterdemo.java

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
import redis.clients.jedis.jedis;
import java.sql.*;
public class mysqlclusterdemo {
    //创建操作redis和数据库的对象
    private jedis jedis;
    private connection masterconn;  //连接主库的对象
    private connection slaveconn;   //连接从库的对象
    preparedstatement masterps=null;    //对主库进行操作的对象
    preparedstatement slaveps=null;     //对从库进行操作的对象
    //初始化环境
    private void init(){
        //mysql的连接参数
        string mysqldriver="com.mysql.cj.jdbc.driver";
        string masterurl="jdbc:mysql://192.168.159.33:3306/redisdemo?usessl=false&servertimezone=utc&allowpublickeyretrieval=true";
        string slaveurl="jdbc:mysql://192.168.159.33:3316/redisdemo?usessl=false&servertimezone=utc&allowpublickeyretrieval=true";
        string user="root";
        string pwd="123456";
        try{
            class.forname(mysqldriver);
            masterconn= drivermanager.getconnection(masterurl,user,pwd);
            slaveconn= drivermanager.getconnection(slaveurl,user,pwd);
            jedis=new jedis("192.168.159.33",6379);
        }catch (sqlexception e){
            e.printstacktrace();
        }catch (exception e){
            e.printstacktrace();
        }
    }
 
    private void insertdata(){
        //是向主mysql服务器插入数据
        try{
        masterps=masterconn.preparestatement("insert into student(id,name,age,score) values(10,'frank',18,100)");
        masterps.executeupdate();
        }catch (sqlexception e){
            e.printstacktrace();
        }catch (exception e){
            e.printstacktrace();
        }
    }
 
    private string getnamebyid(string id){
        string key="stu"+id;
        string name="";
        //如果存在于redis,就先从redis里获取
        if(jedis.exists(key)){
            system.out.println("id:"+key+" exists in redis");
            name=jedis.get(key);
            system.out.println("name is :"+jedis.get(key));
            return name;
        }else{  //如果没在redis里,就到从mysql里去读
            try {
                slaveps=slaveconn.preparestatement("select name from student where id=10");
                resultset rs=slaveps.executequery();
                if(rs.next()){
                    system.out.println("id: "+key+" exists in slave mysql");
                    name=rs.getstring("name");
                    system.out.println("name is: "+name);
                    //放入redis缓存
                    jedis.set(key,name);
                }
                return name;
            }catch (sqlexception e){
                e.printstacktrace();
            }catch (exception e){
                e.printstacktrace();
            }
        }
        return name;
    }
 
    public static void main(string[] args) {
        mysqlclusterdemo tool=new mysqlclusterdemo();
        tool.init();
        tool.insertdata();
        //场景1 没有从redis中找到,就到从mysql服务器中去读
        system.out.println(tool.getnamebyid("10"));
        //场景2,当前id=10的数据已存在于redis,所有直接读缓存
        system.out.println(tool.getnamebyid("10"));
    }
}

运行结果

Redis整合MySQL主从集群的示例代码

4、mysql主从集群整合redis主从集群

  上面的mysql主从集群至整合了一个redis主机,在这种模式里如果redis服务器失效了,那么整个缓存可能都会失效。可以在次基础上引入redis主从复制集群,以提升缓存的可用性以及性能,改进后的框架图如下所示。

Redis整合MySQL主从集群的示例代码

应用程序同样是向主mysql服务器里写数据,这些数据同步到从mysql数据库里。

应用程序先到“从redis服务器”里读取缓存,如果找不到,就再到从mysql数据库里去读。

如果从“从mysql数据库”里读到数据,那么需要写入“主redis”,而根据redis集群的主从复制机制,该数据会被写入“从redis服务器”。这种针对redis集群的读写分离机制能提升读写缓存的性能。

4.1 搭建redis主从复制集群

4.1.1 创建redis-master容器

?
1
docker run -itd --name redis-master -p 6379:6379 redis:latest

Redis整合MySQL主从集群的示例代码

4.1.2 创建resis-slave容器

?
1
docker run -itd --name redis-slave -p 6380:6379 redis:latest

Redis整合MySQL主从集群的示例代码

4.1.3 查看redis服务器的ip

?
1
docker inspect redis-master

Redis整合MySQL主从集群的示例代码

可以看到,redis-master的ip地址为172.17.0.4

4.1.4 主从配置

  在redis-slave容器的窗口里,通过docker exec -it redis-slave /bin/bash命令进入容器的命令行窗口。运行如下的slaveof命令,指定当前服务器为从服务器,该命令的格式是slaveof ip地址 端口号,这里指向172.17.0.2:6379所在的主服务器。

?
1
slaveof 172.17.0.4 6379

Redis整合MySQL主从集群的示例代码

运行完该命令后,在redis-slave客户端里再次运行info replication

Redis整合MySQL主从集群的示例代码

  可以看到,该redis-slave已经成为从服务器,从属于172.17.0.2:6379所在的redis服务器。

4.2、代码整合

mysqlclusterimproveddemo.java

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
import redis.clients.jedis.jedis;
import java.sql.*;
public class mysqlclusterimproveddemo {
    //创建操作redis和数据库的对象
    private jedis masterjedis;  //指向主redis服务器
    private jedis slavejedis;   //指向从redis服务器
    private connection masterconn;  //连接主库的对象
    private connection slaveconn;   //连接从库的对象
    preparedstatement masterps=null;    //对主库进行操作的对象
    preparedstatement slaveps=null;     //对从库进行操作的对象
 
    private void init(){
        //mysql的连接参数
        string mysqldriver="com.mysql.cj.jdbc.driver";
        string masterurl="jdbc:mysql://192.168.159.33:3306/redisdemo?usessl=false&servertimezone=utc&allowpublickeyretrieval=true";
        string slaveurl="jdbc:mysql://192.168.159.33:3316/redisdemo?usessl=false&servertimezone=utc&allowpublickeyretrieval=true";
        string user="root";
        string pwd="123456";
        try{
            class.forname(mysqldriver);
            masterconn= drivermanager.getconnection(masterurl,user,pwd);
            slaveconn= drivermanager.getconnection(slaveurl,user,pwd);
            masterjedis=new jedis("192.168.159.33",6379);
            slavejedis=new jedis("192.168.159.33",6380);
        }catch (sqlexception e){
            e.printstacktrace();
        }catch (exception e){
            e.printstacktrace();
        }
 
    }
 
    private void insertdata(){
        //是向主mysql服务器插入数据
        try{
            masterps=masterconn.preparestatement("insert into student(id,name,age,score) values(10,'frank',18,100)");
            masterps.executeupdate();
        }catch (sqlexception e){
            e.printstacktrace();
        }catch (exception e){
            e.printstacktrace();
        }
    }
 
    private string getnamebyid(string id){
        string key="stu"+id;
        string name="";
        //如果存在于redis,就先从redis里获取
        if(slavejedis.exists(key)){ //到从redis服务器去找
            system.out.println("id: "+key+" exists in redis.");
            name=slavejedis.get(key);//找到后到从redis里读
            system.out.println("name is: "+slavejedis.get(key));
            return name;
        }else{  //没在redis,就到从mysql去读
            try{
                slaveps=slaveconn.preparestatement("select name from student where id=10");
                resultset rs=slaveps.executequery();
                if(rs.next())
                {
                    system.out.println("id: "+key+" exists in slave mysql");
                    name=rs.getstring("name");
                    system.out.println("name is: "+name);
                    //放入主redis缓存
                    masterjedis.set(key,name);
                }
                return name;
            }catch (sqlexception e){
                e.printstacktrace();
            }catch (exception e){
                e.printstacktrace();
            }
        }
        return name;
    }
 
    public static void main(string[] args) {
        mysqlclusterimproveddemo tool=new mysqlclusterimproveddemo();
        tool.init();
        tool.insertdata();
        //场景1 在主redis中没有读到,则到从mysql服务器中读
        system.out.println(tool.getnamebyid("10"));
        //场景2 当前id=10已经存在于redis,所以直接读缓存
        system.out.println(tool.getnamebyid("10"));
    }
}

Redis整合MySQL主从集群的示例代码

   为了突出重点,这里我并没有设置“缓存失效时间”和“防止缓存穿透”等方面的实施代码,但是这些要点同样重要。

到此这篇关于redis整合mysql主从集群的示例代码的文章就介绍到这了,更多相关redis整合mysql主从集群内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!

原文链接:https://blog.csdn.net/qq_43753724/article/details/120489532

延伸 · 阅读

精彩推荐
  • RedisRedis集群的5种使用方式,各自优缺点分析

    Redis集群的5种使用方式,各自优缺点分析

    Redis 多副本,采用主从(replication)部署结构,相较于单副本而言最大的特点就是主从实例间数据实时同步,并且提供数据持久化和备份策略。...

    优知学院4082021-08-10
  • Redis关于Redis数据库入门详细介绍

    关于Redis数据库入门详细介绍

    大家好,本篇文章主要讲的是关于Redis数据库入门详细介绍,感兴趣的同学赶快来看一看吧,对你有帮助的话记得收藏一下,方便下次浏览...

    沃尔码6982022-01-24
  • RedisRedis Template实现分布式锁的实例代码

    Redis Template实现分布式锁的实例代码

    这篇文章主要介绍了Redis Template实现分布式锁,需要的朋友可以参考下 ...

    晴天小哥哥2592019-11-18
  • Redis详解三分钟快速搭建分布式高可用的Redis集群

    详解三分钟快速搭建分布式高可用的Redis集群

    这篇文章主要介绍了详解三分钟快速搭建分布式高可用的Redis集群,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,...

    万猫学社4502021-07-25
  • Redisredis缓存存储Session原理机制

    redis缓存存储Session原理机制

    这篇文章主要为大家介绍了redis缓存存储Session原理机制详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪...

    程序媛张小妍9252021-11-25
  • RedisRedis 6.X Cluster 集群搭建

    Redis 6.X Cluster 集群搭建

    码哥带大家完成在 CentOS 7 中安装 Redis 6.x 教程。在学习 Redis Cluster 集群之前,我们需要先搭建一套集群环境。机器有限,实现目标是一台机器上搭建 6 个节...

    码哥字节15752021-04-07
  • Redis如何使用Redis锁处理并发问题详解

    如何使用Redis锁处理并发问题详解

    这篇文章主要给大家介绍了关于如何使用Redis锁处理并发问题的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用Redis具有一定的参考学习...

    haofly4522019-11-26
  • Redis《面试八股文》之 Redis十六卷

    《面试八股文》之 Redis十六卷

    redis 作为我们最常用的内存数据库,很多地方你都能够发现它的身影,比如说登录信息的存储,分布式锁的使用,其经常被我们当做缓存去使用。...

    moon聊技术8182021-07-26