Mysql master-slave replication read-write separation connection acquisition

JDBC driver initialization-Mysql: http://donald-draper.iteye.com/blog/2342010
JDBC connection acquisition: http://donald-draper.iteye.com/blog/2342011
Mysql load balancing connection acquisition: http: //donald-draper.iteye.com/blog/2342089
Mysql master-slave replication read-write separation connection acquisition: http://donald-draper.iteye.com/blog/2342108
ConnectionImp creates MysqlIO: http://donald-draper .iteye.com/blog/2342959
Mysql precompiled SQL: http://donald-draper.iteye.com/blog/2342960
MysqlSQL PreparedStatement Query: http://donald-draper.iteye.com/blog/2343083
MySQL ServerPreparedStatement Query: http://donald-draper.iteye.com/blog/2343124
I talked about the initialization of Driver, the acquisition of single-server server connections, and the acquisition of load balancing connections. Today, I will talk about master-slave replication, and the acquisition of read-write analysis connections:
From the following piece of code:
//If the url is jdbc:mysql:replication://, call the cluster connection acquisition method
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();
	    //The first host in Url is master, followed by 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);
    }

Let's take a look at ReplicationConnection
public class ReplicationConnection
    implements Connection, PingTarget
{  
    protected Connection currentConnection;//Current connection
    protected Connection masterConnection;//Main connection
    protected Connection slavesConnection;//Slave connection
    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");
	//Initialize the URL of Master and Slave
        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");
	//Get the Master connection from the Driver
        masterConnection = (Connection)driver.connect(masterUrl.toString(), masterProperties);
	//Get Slave connection from Driver
        slavesConnection = (Connection)driver.connect(slaveUrl.toString(), slaveProperties);
        slavesConnection.setReadOnly(true);
	//The current connection is masterConnection
        currentConnection = masterConnection;
    }
    public synchronized void setReadOnly(boolean readOnly)
        throws SQLException
    {
        if(readOnly)
        {
            if(currentConnection != slavesConnection)
                switchToSlavesConnection();
        } else
        if(currentConnection != masterConnection)
            switchToMasterConnection();
    }
    //Master and SLave connection switch
     private synchronized void switchToMasterConnection()
        throws SQLException
    {
        swapConnections(masterConnection, slavesConnection);
    }
    //Slave and Master connection switch
    private synchronized void switchToSlavesConnection()
        throws SQLException
    {
        swapConnections(slavesConnection, masterConnection);
    }
    // switch connection
    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;
    }
    // rollback
     public synchronized void rollback()
        throws SQLException
    {
        currentConnection.rollback();
    }

    public synchronized void rollback(Savepoint savepoint)
        throws SQLException
    {
        currentConnection.rollback(savepoint);
    }
    //Set whether to submit automatically
    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);
    }
}

Summary:
As can be seen from the above, the connection between the master and the slave cluster is obtained. First, the url is parsed to separate the Mater host and the Slave host. The first is the Master, and the latter is the Slave. When the NonRegisteringDriver creates a replication connection, it returns a ReplicationConnection, and the ReplicationConnection There are three connections, currentConnection, masterConnection, slavesConnection,
these three connections are actually ConnectionImpl; by default currentConnection is masterConnection, when we set readonly to true, switch to slavesConnection, false, switch to masterConnection; ReplicationConnection The implementation of the related method is actually calling the corresponding method of 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);
    }
}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326524386&siteId=291194637