MySQL数据库同步小工具(Java实现)

近期公司做个报表系统,为了报表系统中复杂的查询条件,不影响线上业务系统的使用,研究了一下MySQL数据库同步,下面用Java代码实现MySQL数据库同步,以便自己查阅!

 

数据库同步实现功能点:

1.支持跨服务器跨库的多线程同步

2.每张表的同步有日志记录

3.每次同步记录数可配置

源码和具体的使用细则,可以到下载源码及使用说明请添加链接描述 。

 

一、数据同步核心代码

package com.zrscsoft.synchtool.db;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;

import cn.com.dd.connector.db.ConnectionPoolManager;

import com.synch.connector.DataBaseUtil;
import com.synch.connector.DataSourceConnectDBVO;
import com.synch.connector.TableFieldVO;
import com.zrscsoft.synchtool.util.PropertyUtil;
import com.zrscsoft.synchtool.util.StringUtil;

public class SynchMain {
    public void addSynchLog(Connection bakconn, String synchtable,
            String synchsql, String syncherr, String synchtime) {
        PreparedStatement bakps = null;
        try {
            String bakInsertSQL = "insert into sys_synchlog (synchtable,synchsql,syncherr,synchtime,createtime) values ('"
                    + synchtable
                    + "','"
                    + synchsql
                    + "',?,'"
                    + synchtime + "',now())";
            bakps = bakconn.prepareStatement(bakInsertSQL);
            bakps.setString(1, syncherr);
            bakps.execute();
            bakconn.commit();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 备库连接释放
            if (bakps != null) {
                try {
                    bakps.close();
                } catch (SQLException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
    }

    public void synch(String synchtablenames) throws Exception {
        HashMap<String, String> synProperty = PropertyUtil.getAllMessage();
        // 数据库连接参数
        DataSourceConnectDBVO maindb = new DataSourceConnectDBVO();
        maindb.setDataSourceType(0);
        maindb.setDataSourceName("maindb"+synchtablenames);
        maindb.setAccessMethod(0);
        maindb.setDataSourceAddress(synProperty.get("maindb.address"));
        maindb.setDataSourcePort(Integer.parseInt(synProperty
                .get("maindb.port")));
        maindb.setDatabaseName(synProperty.get("maindb.databasename"));
        maindb.setAccountName(synProperty.get("maindb.accountname"));
        maindb.setAccountPwd(synProperty.get("maindb.accountpwd"));

        DataSourceConnectDBVO bakdb = new DataSourceConnectDBVO();
        bakdb.setDataSourceType(0);
        bakdb.setDataSourceName("bakdb"+synchtablenames);
        bakdb.setAccessMethod(0);
        bakdb.setDataSourceAddress(synProperty.get("bakdb.address"));
        bakdb.setDataSourcePort(Integer.parseInt(synProperty.get("bakdb.port")));
        bakdb.setDatabaseName(synProperty.get("bakdb.databasename"));
        bakdb.setAccountName(synProperty.get("bakdb.accountname"));
        bakdb.setAccountPwd(synProperty.get("bakdb.accountpwd"));

        int currows = Integer.parseInt(synProperty.get("synchrows"));// 每次同步的记录数
        // 同步表名.
        String synchtablenamestmp=synProperty.get(synchtablenames);
        if(synchtablenamestmp==null||"".equals(synchtablenamestmp)){
            return;
        }

        String[] tableNames = synchtablenamestmp.split(",");
        for (int t = 0; t < tableNames.length; t++) {
            String tableName = tableNames[t];
            // 获取同步字段名
            List<TableFieldVO> list = DataBaseUtil.getFieldsForTable(tableName,
                    maindb);
            String fields = "`"+list.get(0).getColumnName()+"`";
            String values = "?";
            String idfield="";
            int paraCount = list.size();
            for (int i = 1; i < paraCount; i++) {
                String columnName=list.get(i).getColumnName();
                fields = fields + ",`" + columnName+"`";
                values = values + ",?";
                if("id".equals(columnName.toLowerCase())){
                    idfield=columnName;
                }
            }

            Connection mainconn = null;
            PreparedStatement mainps = null;
            ResultSet mainrs = null;
            Connection bakconn = null;
            PreparedStatement bakps = null;

            int curpage = 1;// 第几页,默认显示第1页
            long startTime = System.currentTimeMillis();
            String mainQuerySQL = "";
            String bakInsertSQL ="";
            while (true) {
                try {
                    String orderby="".equals(idfield)?"":" order by "+idfield+" ";
                    String limit = orderby+" limit " + (curpage - 1) * currows + ","
                            + currows;
                    mainQuerySQL = "select * from " + tableName + limit;
                    bakInsertSQL = "insert ignore into " + tableName + " ("
                            + fields + ") values (" + values + ")";
                    // 主库
                    mainconn = DataBaseUtil.getMySQLConnect(maindb);
                    mainps = mainconn.prepareStatement(mainQuerySQL);
                    mainrs = mainps.executeQuery();
                    // 被库
                    bakconn = DataBaseUtil.getMySQLConnect(bakdb);
                    bakps = bakconn.prepareStatement(bakInsertSQL);
                    int querySize = 0;
                    while (mainrs.next()) {
                        querySize++;
                        for (int i = 0; i < paraCount; i++) {
                            bakps.setString(i + 1, mainrs.getString(list.get(i)
                                    .getColumnName()));
                        }
                        bakps.addBatch();
                    }
                    if (querySize == 0) {
                        break;
                    }
                    curpage++;
                    bakps.executeBatch();
                    bakconn.commit();
                    this.addSynchLog(bakconn, tableName, mainQuerySQL, "",
                            (System.currentTimeMillis() - startTime) + "");
                } catch (Exception e) {
                    e.printStackTrace();
                    this.addSynchLog(bakconn, tableName, mainQuerySQL,
                            StringUtil.getExceptionAllinformation(e),
                            (System.currentTimeMillis() - startTime) + "");
                    break;
                } finally {
                    // 主库连接释放
                    if (mainrs != null) {
                        try {
                            mainrs.close();
                        } catch (SQLException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                    }
                    if (mainps != null) {
                        try {
                            mainps.close();
                        } catch (SQLException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                    }
                    if (mainconn != null) {
                        ConnectionPoolManager.getInstance().release(mainconn);
                    }
                    // 备库连接释放
                    if (bakps != null) {
                        try {
                            bakps.close();
                        } catch (SQLException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                    }
                    if (bakconn != null) {
                        ConnectionPoolManager.getInstance().release(bakconn);
                    }
                }
            }
            System.out.println(tableNames.length + "/" + t + "表" + tableName
                    + "耗时:" + (System.currentTimeMillis() - startTime) + "毫秒");
        }
    }

    public static void main(String[] args) throws Exception {
        new SynchThread("synchtablenames1").start();
        new SynchThread("synchtablenames2").start();
        new SynchThread("synchtablenames3").start();
    }

}

二、数据库同步多线程实现

package com.zrscsoft.synchtool.db;

public class SynchThread extends Thread {
    private String synchtablenames;

    public SynchThread(String synchtablenames) {
        this.synchtablenames = synchtablenames;
    }

    public void run() {
        if(synchtablenames==null||"".equals(synchtablenames)){
            return;
        }
        SynchMain main = new SynchMain();
        try {
            main.synch(synchtablenames);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

}

三、配置文件及读取配置文件代码

配置文件内容为:

#主库
maindb.address=localhost
maindb.port=3306
maindb.databasename=mysqlmain
maindb.accountname=root
maindb.accountpwd=root
#备库
bakdb.address=localhost
bakdb.port=3306
bakdb.databasename=mysqlbak
bakdb.accountname=root
bakdb.accountpwd=root
#同步表名,多张表以,分开
synchtablenames1=sys_user1
synchtablenames2=sys_user2
synchtablenames3=sys_user3
#每次同步记录数
synchrows=10000

读取配置文件的Java类为:

package com.zrscsoft.synchtool.util;

import java.util.Enumeration;
import java.util.HashMap;
import java.util.ResourceBundle;

public class PropertyUtil {
    public static HashMap<String, String> getAllMessage() {
        String propertyName = "synch";
        // 获得资源包
        ResourceBundle rb = ResourceBundle.getBundle(propertyName.trim());
        // 通过资源包拿到所有的key
        Enumeration<String> allKey = rb.getKeys();
        // 遍历key 得到 value
        HashMap<String, String> valList = new HashMap<String, String>();
        while (allKey.hasMoreElements()) {
            String key = allKey.nextElement();
            String value = (String) rb.getString(key);
            valList.put(key, value);
        }
        return valList;
    }
}
 

运行方式为:执行SynchMain.java类中的main()方法。

源码和具体的使用细则,可以到下载源码及使用说明请添加链接描述 。

转载于:https://blog.51cto.com/1681229/2370801

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值