`
Donald_Draper
  • 浏览: 984078 次
社区版块
存档分类
最新评论

Mysql主从复制读写分离连接的获取

    博客分类:
  • JDBC
阅读更多
JDBC驱动初始化-Mysql:http://donald-draper.iteye.com/blog/2342010
JDBC连接的获取:http://donald-draper.iteye.com/blog/2342011
Mysql负载均衡连接的获取:http://donald-draper.iteye.com/blog/2342089
Mysql主从复制读写分离连接的获取:http://donald-draper.iteye.com/blog/2342108
ConnectionImp创建MysqlIO :http://donald-draper.iteye.com/blog/2342959
Mysql预编译SQL:http://donald-draper.iteye.com/blog/2342960
MysqlSQL PreparedStatement的查询:http://donald-draper.iteye.com/blog/2343083
MySQL ServerPreparedStatement查询:http://donald-draper.iteye.com/blog/2343124
前面讲过Driver的初始化,单机Server连接的获取,负载均衡连接的获取,今天讲一下主从复制,读写分析连接的获取:
从下面一段代码来看:
//如果url以jdbc:mysql:replication://则调用集群连接获取方法
if(StringUtils.startsWithIgnoreCase(url, "jdbc:mysql:replication://"))
return connectReplicationConnection(url, info);

//NonRegisteringDriver
private Connection connectReplicationConnection(String url, Properties info)
        throws SQLException
    {
        Properties parsedProps = parseURL(url, info);
        if(parsedProps == null)
            return null;
        Properties masterProps = (Properties)parsedProps.clone();
        Properties slavesProps = (Properties)parsedProps.clone();
        slavesProps.setProperty("com.mysql.jdbc.ReplicationConnection.isSlave", "true");
        String hostValues = parsedProps.getProperty("HOST");
        if(hostValues != null)
        {
            StringTokenizer st = new StringTokenizer(hostValues, ",");
            StringBuffer masterHost = new StringBuffer();
            StringBuffer slaveHosts = new StringBuffer();
	    //Url中第一个host为master,后面为Slave
            if(st.hasMoreTokens())
            {
                String hostPortPair[] = parseHostPortPair(st.nextToken());
                if(hostPortPair[0] != null)
                    masterHost.append(hostPortPair[0]);
                if(hostPortPair[1] != null)
                {
                    masterHost.append(":");
                    masterHost.append(hostPortPair[1]);
                }
            }
            boolean firstSlaveHost = true;
            do
            {
                if(!st.hasMoreTokens())
                    break;
                String hostPortPair[] = parseHostPortPair(st.nextToken());
                if(!firstSlaveHost)
                    slaveHosts.append(",");
                else
                    firstSlaveHost = false;
                if(hostPortPair[0] != null)
                    slaveHosts.append(hostPortPair[0]);
                if(hostPortPair[1] != null)
                {
                    slaveHosts.append(":");
                    slaveHosts.append(hostPortPair[1]);
                }
            } while(true);
            if(slaveHosts.length() == 0)
                throw SQLError.createSQLException("Must specify at least one slave host to connect to for master/slave replication load-balancing functionality", "01S00", null);
            //MaterHost
	    masterProps.setProperty("HOST", masterHost.toString());
	    //SlaveHost
            slavesProps.setProperty("HOST", slaveHosts.toString());
        }
        return new ReplicationConnection(masterProps, slavesProps);
    }

我们来看一下ReplicationConnection
public class ReplicationConnection
    implements Connection, PingTarget
{  
    protected Connection currentConnection;//当前连接
    protected Connection masterConnection;//主连接
    protected Connection slavesConnection;//从连接
    public ReplicationConnection(Properties masterProperties, Properties slaveProperties)
        throws SQLException
    {
        NonRegisteringDriver driver = new NonRegisteringDriver();
        StringBuffer masterUrl = new StringBuffer("jdbc:mysql://");
        StringBuffer slaveUrl = new StringBuffer("jdbc:mysql://");
        String masterHost = masterProperties.getProperty("HOST");
	//初始化Master与Slave的URL
        if(masterHost != null)
            masterUrl.append(masterHost);
        String slaveHost = slaveProperties.getProperty("HOST");
        if(slaveHost != null)
            slaveUrl.append(slaveHost);
        String masterDb = masterProperties.getProperty("DBNAME");
        masterUrl.append("/");
        if(masterDb != null)
            masterUrl.append(masterDb);
        String slaveDb = slaveProperties.getProperty("DBNAME");
        slaveUrl.append("/");
        if(slaveDb != null)
            slaveUrl.append(slaveDb);
        slaveProperties.setProperty("roundRobinLoadBalance", "true");
	//从Driver获取Master连接
        masterConnection = (Connection)driver.connect(masterUrl.toString(), masterProperties);
	//从Driver获取Slave连接
        slavesConnection = (Connection)driver.connect(slaveUrl.toString(), slaveProperties);
        slavesConnection.setReadOnly(true);
	//当前连接为masterConnection
        currentConnection = masterConnection;
    }
    public synchronized void setReadOnly(boolean readOnly)
        throws SQLException
    {
        if(readOnly)
        {
            if(currentConnection != slavesConnection)
                switchToSlavesConnection();
        } else
        if(currentConnection != masterConnection)
            switchToMasterConnection();
    }
    //Master与SLave连接切换
     private synchronized void switchToMasterConnection()
        throws SQLException
    {
        swapConnections(masterConnection, slavesConnection);
    }
    //Slave与Master连接切换
    private synchronized void switchToSlavesConnection()
        throws SQLException
    {
        swapConnections(slavesConnection, masterConnection);
    }
    //切换连接
    private synchronized void swapConnections(Connection switchToConnection, Connection switchFromConnection)
        throws SQLException
    {
        String switchFromCatalog = switchFromConnection.getCatalog();
        String switchToCatalog = switchToConnection.getCatalog();
        if(switchToCatalog != null && !switchToCatalog.equals(switchFromCatalog))
            switchToConnection.setCatalog(switchFromCatalog);
        else
        if(switchFromCatalog != null)
            switchToConnection.setCatalog(switchFromCatalog);
        boolean switchToAutoCommit = switchToConnection.getAutoCommit();
        boolean switchFromConnectionAutoCommit = switchFromConnection.getAutoCommit();
        if(switchFromConnectionAutoCommit != switchToAutoCommit)
            switchToConnection.setAutoCommit(switchFromConnectionAutoCommit);
        int switchToIsolation = switchToConnection.getTransactionIsolation();
        int switchFromIsolation = switchFromConnection.getTransactionIsolation();
        if(switchFromIsolation != switchToIsolation)
            switchToConnection.setTransactionIsolation(switchFromIsolation);
        currentConnection = switchToConnection;
    }
    //回滚
     public synchronized void rollback()
        throws SQLException
    {
        currentConnection.rollback();
    }

    public synchronized void rollback(Savepoint savepoint)
        throws SQLException
    {
        currentConnection.rollback(savepoint);
    }
    //设置是否自动提交
    public synchronized void setAutoCommit(boolean autoCommit)
        throws SQLException
    {
        currentConnection.setAutoCommit(autoCommit);
    }
    public PreparedStatement prepareStatement(String sql)
        throws SQLException
    {
        PreparedStatement pstmt = currentConnection.prepareStatement(sql);
        ((com.mysql.jdbc.Statement)pstmt).setPingTarget(this);
        return pstmt;
    }
    public CallableStatement prepareCall(String sql)
        throws SQLException
    {
        return currentConnection.prepareCall(sql);
    }
}

总结:
从上面可以看出,主从集群的连接获取,首先解析url分离出Mater host和Slave host,第一个为Master,后面为Slave,NonRegisteringDriver创建复制连接时,返回的是一个ReplicationConnection,而ReplicationConnection内有三个连接分别为,currentConnection,masterConnection,slavesConnection,
这三个连接实际上是ConnectionImpl;默认情况下currentConnection为masterConnection,当我们设置readonly为true时,切换到slavesConnection,为false,切换到masterConnection;;ReplicationConnection的相关方法的实现,实际上是调用ConnectionImpl的相应方法。

//NonRegisteringReplicationDriver
public class NonRegisteringReplicationDriver extends NonRegisteringDriver
{

    public NonRegisteringReplicationDriver()
        throws SQLException
    {
    }

    public Connection connect(String url, Properties info)
        throws SQLException
    {
        Properties parsedProps = parseURL(url, info);
        if(parsedProps == null)
            return null;
        Properties masterProps = (Properties)parsedProps.clone();
        Properties slavesProps = (Properties)parsedProps.clone();
        slavesProps.setProperty("com.mysql.jdbc.ReplicationConnection.isSlave", "true");
        String hostValues = parsedProps.getProperty("HOST");
        if(hostValues != null)
        {
            StringTokenizer st = new StringTokenizer(hostValues, ",");
            StringBuffer masterHost = new StringBuffer();
            StringBuffer slaveHosts = new StringBuffer();
            if(st.hasMoreTokens())
            {
                String hostPortPair[] = parseHostPortPair(st.nextToken());
                if(hostPortPair[0] != null)
                    masterHost.append(hostPortPair[0]);
                if(hostPortPair[1] != null)
                {
                    masterHost.append(":");
                    masterHost.append(hostPortPair[1]);
                }
            }
            boolean firstSlaveHost = true;
            do
            {
                if(!st.hasMoreTokens())
                    break;
                String hostPortPair[] = parseHostPortPair(st.nextToken());
                if(!firstSlaveHost)
                    slaveHosts.append(",");
                else
                    firstSlaveHost = false;
                if(hostPortPair[0] != null)
                    slaveHosts.append(hostPortPair[0]);
                if(hostPortPair[1] != null)
                {
                    slaveHosts.append(":");
                    slaveHosts.append(hostPortPair[1]);
                }
            } while(true);
            if(slaveHosts.length() == 0)
                throw SQLError.createSQLException("Must specify at least one slave host to connect to for master/slave replication load-balancing functionality", "01S00", null);
            masterProps.setProperty("HOST", masterHost.toString());
            slavesProps.setProperty("HOST", slaveHosts.toString());
        }
        return new ReplicationConnection(masterProps, slavesProps);
    }
}
分享到:
评论

相关推荐

    MySQL主从复制 读写分离

    根据提供的文件信息,我们可以总结出以下关于MySQL主从复制与读写分离的相关知识点: ### MySQL主从复制原理 MySQL主从复制是一种数据同步机制,它允许将一个MySQL服务器(主服务器)上的数据自动复制到一个或多个...

    mysql 主从复制读写分离实现

    mysql 主从复制读写分离实现

    MySQL主从复制与读写分离.docx

    MySQL 主从复制与读写分离 MySQL 主从复制是指将一个 MySQL 服务器的数据实时同步到另一个 MySQL 服务器中,以实现数据的高可用性和读写分离。下面是 MySQL 主从复制与读写分离的详细知识点: MySQL 主从复制 ...

    MySQL主从复制与读写分离

    MySQL主从复制与读写分离是数据库架构中的重要策略,旨在提高系统的可用性、扩展性和数据安全性。在大型系统中,随着数据量的增长和访问压力的增加,单一数据库服务器往往无法满足性能需求。主从复制和读写分离是...

    SpringBoot第 12 讲:SpringBoot+MySQL主从复制、读写分离

    在本讲中,我们将深入探讨如何使用SpringBoot与MySQL实现主从复制以及读写分离的架构设计。这一技术方案在大型分布式系统中尤为常见,它能够有效地提高数据库系统的可用性和性能。 首先,让我们理解主从复制的核心...

    MySQL主从复制读写分离.zip

    MySQL主从复制与读写分离是数据库架构中的重要策略,用于提高系统性能和可用性。在高并发的互联网应用中,这种设计模式尤为常见。本文将深入探讨这两个概念及其实施方法。 **一、MySQL主从复制** MySQL主从复制是...

    基于mycat的Mysql主从复制读写分离笔记

    4. Mysql主从复制配置 2 1) 配置主库 2 A. 修改主库配置文件 3 B. 重启mysql 3 C. 查看主库状态 3 D. 分配一个从库复制的账号 3 E. 查看从库复制账号 3 2) 配置从库 4 A. 修改从库配置文件 4 B. 重启mysql从服务器 4...

    Mycat+MySQL主从复制读写分离验证安装手册

    ### Mycat+MySQL主从复制读写分离验证安装手册知识点详解 #### 1. 实验环境及准备 在实现Mycat与MySQL的主从复制读写分离之前,需要搭建好实验环境。根据文档中的信息,实验环境由两台机器组成,分别用于充当MySQL...

    mysql 主从复制 读写分离

    1.环境准备:mysql主服务器IP:192.168.60.5 Mysql从1服务器IP:192.168.60.10 mysql从2服务器IP:192.168.60.11 Amoeba代理服务器IP;192.168.60.20 客户机IP:192.168.60.30 ...主从复制 读写分离 经本人测试已成功

    linux Mysql mycat主从复制读写分离部署完成

    linux Mysql mycat主从复制读写分离部署完成 技术:mycat mysql集群 linux mycat读写分离 说明包含: mysql数据库服务安装包 mysql+mycat主从复制读写分离部署帮助文档 mysql+mycat主从复制读写分离使用帮助...

    Mysql主从复制读写分离实现

    下面将详细介绍MySQL主从复制中的读写分离实现步骤。 1. **安装MySQL** 在主从服务器上,首先都需要安装MySQL。这里以Linux环境为例,通过编译源码的方式进行安装。创建一个名为`mysql`的用户,解压MySQL的源代码...

    MySQL主从复制读写分离 .pdf

    MySQL的主从配置,读写分离,详细完整教程,pdf文档思维导图

    mysql主从复制读写分离

    MySQL的主从复制和读写分离是数据库高可用性和负载均衡的重要策略,它们可以提高数据库系统的性能和稳定性。以下是对这一主题的详细说明: **主从复制** 是一种数据库复制技术,它允许数据从一个主数据库(Master)...

    Mysql主从复制及读写分离

    一、Mysql5.7的版本优势; 二、数据库集群的概述; 三、Mysql数据库的主从复制; 四、Mysql数据库的读写分离; 五、案例:搭建Mysql数据库集群(主从复制--二进制日志文件...七、案例:实现Mysql主从复制+读写分离;

    基于数据库中间件Mycat的MySQL主从与读写分离配置详解与示例

    本文将深入探讨基于Mycat的MySQL主从配置与读写分离的详细步骤,并结合【心跳问题heartbeat bug #393】和【bug407:修复主从状态监控和读写分离】的修复进行讲解。 首先,理解Mycat的工作原理至关重要。Mycat作为...

    MySQL主从同步与读写分离配置图文详解

    ### MySQL主从同步与读写分离配置详解 #### 一、实验目的 在现代的生产环境中,单一的MySQL服务器往往无法满足对数据处理的安全性、高可用性和高并发的需求。因此,采用**主从同步(Master-Slave Replication)**...

Global site tag (gtag.js) - Google Analytics