Java之——基于java开发的功能强大、配置灵活的数据库之间的同步工具

转载出处:https://blog.csdn.net/l1028386804/article/details/80341251

一、项目背景

基于java开发的功能强大、配置灵活的数据库之间的同步工具,和数据产生器一样,均是前段时间因为项目需要编写的小工具,在实际应用场景中,我们经常需要定期将一个数据库的数据同步到另外一个数据库中,常见的一种做法是将源数据库的数据dump为sql文件,然后到目标数据库执行sql文件完成数据库的导入,但是这种方法至少存在以下问题:

  • 需要手工操作,效率低
  • 当涉及数据表较多时,容易遗漏、出错
  • 如果要定期同步,操作人容易忘记
  • 难以应付频繁变更数据表或者字段

针对以上存在的问题,将珍贵人力从这种重复、无意义的工作中解脱出来,特意开发这个小工具,其中主要配置主要在jobs.xml中完成。

二、项目结构

项目整体结构如下图:


三、项目功能

  • MySQL——>MySQL
  • SQLServer——>SQLServer
  • MySQL——>SQLServer
  • SQLServer——>MySQL

注:——>左边的代码源数据库,——>右边代表的是目标数据库,具体解释如下:

  • 支持MySQL向MySQL同步数据
  • 支持SQLServer向SQLServer同步数据
  • 支持MySQL向SQLServer同步数据
  • 支持SQLServer向MySQL同步数据

四、具体功能实现

1、创建数据库信息类DBInfo

这个类主要是存储一些数据库相关的信息,比如数据库驱动、数据库连接、用户名和密码等,具体见如下代码:

[java]  view plain  copy
  1. package io.mykit.db.sync.provider.entity;  
  2.   
  3. /** 
  4.  * 数据库信息 
  5.  * @author liuyazhuang 
  6.  * 
  7.  */  
  8. public class DBInfo {  
  9.     //数据库连接  
  10.     private String url;  
  11.     //数据库用户名  
  12.     private String username;  
  13.     //数据库密码  
  14.     private String password;  
  15.     //数据库类型(对应mysql还是sqlserver)  
  16.     private String dbtype;  
  17.     //数据库驱动  
  18.     private String driver;  
  19.       
  20.     public String getUrl() {  
  21.         return url;  
  22.     }  
  23.     public void setUrl(String url) {  
  24.         this.url = url;  
  25.     }  
  26.     public String getUsername() {  
  27.         return username;  
  28.     }  
  29.     public void setUsername(String username) {  
  30.         this.username = username;  
  31.     }  
  32.     public String getPassword() {  
  33.         return password;  
  34.     }  
  35.     public void setPassword(String password) {  
  36.         this.password = password;  
  37.     }  
  38.     public String getDbtype() {  
  39.         return dbtype;  
  40.     }  
  41.     public void setDbtype(String dbtype) {  
  42.         this.dbtype = dbtype;  
  43.     }  
  44.     public String getDriver() {  
  45.         return driver;  
  46.     }  
  47.     public void setDriver(String driver) {  
  48.         this.driver = driver;  
  49.     }  
  50. }  

2、创建定时同步任务信息类JobInfo

这个类主要是存储一些与定时任务相关的基本信息,具体见如下代码:

[java]  view plain  copy
  1. package io.mykit.db.sync.provider.entity;  
  2.   
  3. /** 
  4.  * 任务信息 
  5.  * @author liuyazhuang 
  6.  * 
  7.  */  
  8. public class JobInfo {  
  9.     //任务名称  
  10.     private String name;  
  11.     //任务表达式  
  12.     private String cron;  
  13.     //源数据源sql  
  14.     private String srcSql;  
  15.     //目标数据表  
  16.     private String destTable;  
  17.     //目标表数据字段  
  18.     private String destTableFields;  
  19.     //目标表主键  
  20.     private String destTableKey;  
  21.     //目标表可更新的字段  
  22.     private String destTableUpdate;  
  23.       
  24.     public String getName() {  
  25.         return name;  
  26.     }  
  27.     public void setName(String name) {  
  28.         this.name = name;  
  29.     }      
  30.     public String getCron() {  
  31.         return cron;  
  32.     }  
  33.     public void setCron(String cron) {  
  34.         this.cron = cron;  
  35.     }  
  36.     public String getSrcSql() {  
  37.         return srcSql;  
  38.     }  
  39.     public void setSrcSql(String srcSql) {  
  40.         this.srcSql = srcSql;  
  41.     }  
  42.     public String getDestTable() {  
  43.         return destTable;  
  44.     }  
  45.     public void setDestTable(String destTable) {  
  46.         this.destTable = destTable;  
  47.     }  
  48.     public String getDestTableFields() {  
  49.         return destTableFields;  
  50.     }  
  51.     public void setDestTableFields(String destTableFields) {  
  52.         this.destTableFields = destTableFields;  
  53.     }  
  54.     public String getDestTableKey() {  
  55.         return destTableKey;  
  56.     }  
  57.     public void setDestTableKey(String destTableKey) {  
  58.         this.destTableKey = destTableKey;  
  59.     }  
  60.     public String getDestTableUpdate() {  
  61.         return destTableUpdate;  
  62.     }  
  63.     public void setDestTableUpdate(String destTableUpdate) {  
  64.         this.destTableUpdate = destTableUpdate;  
  65.     }  
  66. }  

3、创建字符串工具类SpringUtils

这个类主要是为字符串的操作提供统一的工具支持,在这个小工具中,本类主要的作用就是判断给定的字符串是否为空,具体见如下代码:

[java]  view plain  copy
  1. package io.mykit.db.sync.provider.utils;  
  2.   
  3. /** 
  4.  * 字符串工具类 
  5.  * @author liuyazhuang 
  6.  * 
  7.  */  
  8. public class StringUtils {  
  9.       
  10.     public static boolean isEmpty(String str){  
  11.         return str == null || "".equals(str.trim());  
  12.     }  
  13. }  

4、创建工具类Tool

此类的主要作用就是随机生成一个给定长度的字符串,具体见如下代码:

[java]  view plain  copy
  1. package io.mykit.db.sync.provider.utils;  
  2.   
  3. /** 
  4.  * 工具类 
  5.  *  
  6.  * @author liuyazhuang 
  7.  * 
  8.  */  
  9. public class Tool {  
  10.     public static String generateString(int length) {  
  11.         if (length < 1)  
  12.             length = 6;  
  13.         String str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";  
  14.         String genStr = "";  
  15.         for (int index = 0; index < length; index++) {  
  16.             genStr = genStr + str.charAt((int) ((Math.random() * 100) % 26));  
  17.         }  
  18.         return genStr;  
  19.     }  
  20. }  

5、定义常量类Constants

这个类中主要为此工程提供常量信息,标识数据库的类型,具体代码如下:

[java]  view plain  copy
  1. package io.mykit.db.sync.provider.constants;  
  2.   
  3. /** 
  4.  * 常量 
  5.  * @author liuyazhuang 
  6.  * 
  7.  */  
  8. public class Constants {  
  9.       
  10.     /** 
  11.      * sqlserver数据库 
  12.      */  
  13.     public static final String TYPE_DB_SQLSERVER = "sqlserver";  
  14.       
  15.     /** 
  16.      * MySQL数据库 
  17.      */  
  18.     public static final String TYPE_DB_MYSQL = "mysql";  
  19. }  

以上五个类是我们实现数据库数据同步的基础支持类,创建完以上四个类之后,我们就开始编写具体的同步业务了。

6、创建同步数据库的抽象接口DBSync

这个接口主要是定义了同步数据库的方法,具体代码如下:

[java]  view plain  copy
  1. package io.mykit.db.sync.provider.sync;  
  2.   
  3. import java.sql.Connection;  
  4. import java.sql.SQLException;  
  5.   
  6. import io.mykit.db.sync.provider.entity.JobInfo;  
  7.   
  8.   
  9. /** 
  10.  * 同步数据库的抽象接口 
  11.  * @author liuyazhuang 
  12.  * 
  13.  */  
  14. public interface DBSync {  
  15.     /** 
  16.      *  
  17.      * @param paramString:同步参数 
  18.      * @param paramConnection:数据库连接 
  19.      * @param paramJobInfo:同步任务 
  20.      * @return 
  21.      * @throws SQLException 
  22.      */  
  23.     String assembleSQL(String paramString, Connection paramConnection, JobInfo paramJobInfo) throws SQLException;  
  24.     /** 
  25.      *  
  26.      * @param sql:要执行的SQL语句 
  27.      * @param conn:数据库连接 
  28.      * @throws SQLException 
  29.      */  
  30.     void executeSQL(String sql, Connection conn) throws SQLException;  
  31.       
  32.   
  33. }  

7、创建数据库同步抽象类AbstractDBSync

这个类主要是抽象同步业务,目前主要提供的方法为:消除从job.xml文件中读取出的数据存在的空格,具体代码如下:

[java]  view plain  copy
  1. package io.mykit.db.sync.provider.sync.impl;  
  2.   
  3. import io.mykit.db.sync.provider.sync.DBSync;  
  4.   
  5. /** 
  6.  * 执行数据库同步的抽象类 
  7.  * @author liuyazhuang 
  8.  * 
  9.  */  
  10. public abstract class AbstractDBSync implements DBSync {  
  11.     /** 
  12.      * 去除String数组每个元素中的空格 
  13.      * @param arr 
  14.      * @return 
  15.      */  
  16.     protected String[] trimArrayItem(String[] src){  
  17.         if(src == null || src.length == 0return src;  
  18.         String[] dest = new String[src.length];  
  19.         for(int i = 0; i < src.length; i++){  
  20.             dest[i] = src[i].trim();  
  21.         }  
  22.         return dest;  
  23.     }  
  24. }  

8、创建MySQL数据库同步类MySQLSync

此类主要实现的是MySQL数据库之前的同步操作,具体业务见如下代码:

[java]  view plain  copy
  1. package io.mykit.db.sync.provider.sync.impl;  
  2.   
  3. import java.sql.Connection;  
  4. import java.sql.PreparedStatement;  
  5. import java.sql.ResultSet;  
  6. import java.sql.SQLException;  
  7.   
  8. import io.mykit.db.sync.provider.entity.JobInfo;  
  9. import io.mykit.db.sync.provider.sync.DBSync;  
  10. import io.mykit.db.sync.provider.utils.Tool;  
  11.   
  12. /** 
  13.  * 实现MySQL同步数据库 
  14.  * @author liuyazhuang 
  15.  * 
  16.  */  
  17. public class MySQLSync extends AbstractDBSync implements DBSync {  
  18.   
  19.     @Override  
  20.     public String assembleSQL(String srcSql, Connection conn, JobInfo jobInfo) throws SQLException {  
  21.         String uniqueName = Tool.generateString(6) + "_" + jobInfo.getName();  
  22.         String[] fields = jobInfo.getDestTableFields().split(",");  
  23.         fields = this.trimArrayItem(fields);  
  24.         String[] updateFields = jobInfo.getDestTableUpdate().split(",");  
  25.         updateFields = this.trimArrayItem(updateFields);  
  26.         String destTable = jobInfo.getDestTable();  
  27.         String destTableKey = jobInfo.getDestTableKey();  
  28.         PreparedStatement pst = conn.prepareStatement(srcSql);  
  29.         ResultSet rs = pst.executeQuery();  
  30.         StringBuffer sql = new StringBuffer();  
  31.         sql.append("insert into ").append(jobInfo.getDestTable()).append(" (").append(jobInfo.getDestTableFields()).append(") values ");  
  32.         long count = 0;  
  33.         while (rs.next()) {  
  34.             sql.append("(");  
  35.             for (int index = 0; index < fields.length; index++) {  
  36.                 sql.append("'").append(rs.getString(fields[index])).append(index == (fields.length - 1) ? "'" : "',");  
  37.             }  
  38.             sql.append("),");  
  39.             count++;  
  40.         }  
  41.         if (rs != null) {  
  42.             rs.close();  
  43.         }  
  44.         if (pst != null) {  
  45.             pst.close();  
  46.         }  
  47.         if (count > 0) {  
  48.             sql = sql.deleteCharAt(sql.length() - 1);  
  49.             if ((!jobInfo.getDestTableUpdate().equals("")) && (!jobInfo.getDestTableKey().equals(""))) {  
  50.                 sql.append(" on duplicate key update ");  
  51.                 for (int index = 0; index < updateFields.length; index++) {  
  52.                     sql.append(updateFields[index]).append("= values(").append(updateFields[index]).append(index == (updateFields.length - 1) ? ")" : "),");  
  53.                 }  
  54.                 return new StringBuffer("alter table ").append(destTable).append(" add constraint ").append(uniqueName).append(" unique (").append(destTableKey).append(");").append(sql.toString())  
  55.                                 .append(";alter table ").append(destTable).append(" drop index ").append(uniqueName).toString();  
  56.             }  
  57.             return sql.toString();  
  58.         }  
  59.         return null;  
  60.     }  
  61.   
  62.     @Override  
  63.     public void executeSQL(String sql, Connection conn) throws SQLException {  
  64.         PreparedStatement pst = conn.prepareStatement("");  
  65.         String[] sqlList = sql.split(";");  
  66.         for (int index = 0; index < sqlList.length; index++) {  
  67.             pst.addBatch(sqlList[index]);  
  68.         }  
  69.         pst.executeBatch();  
  70.         conn.commit();  
  71.         pst.close();  
  72.     }  
  73. }  

9、创建SQLServer数据库同步类SQLServerSync

这个类主要实现了SQLServer数据库之前的数据同步操作,具体业务见如下代码:

[java]  view plain  copy
  1. package io.mykit.db.sync.provider.sync.impl;  
  2.   
  3.   
  4. import java.sql.Connection;  
  5. import java.sql.PreparedStatement;  
  6. import java.sql.ResultSet;  
  7. import java.sql.SQLException;  
  8. import java.sql.Statement;  
  9.   
  10. import org.apache.log4j.Logger;  
  11.   
  12. import io.mykit.db.sync.provider.entity.JobInfo;  
  13. import io.mykit.db.sync.provider.sync.DBSync;  
  14.   
  15. /** 
  16.  * SQLServer同步的数据库的实现 
  17.  * @author liuyazhuang 
  18.  * 
  19.  */  
  20. public class SQLServerSync extends AbstractDBSync implements DBSync {  
  21.     private Logger logger = Logger.getLogger(SQLServerSync.class);  
  22.   
  23.     @Override  
  24.     public String assembleSQL(String srcSql, Connection conn, JobInfo jobInfo) throws SQLException {  
  25.         String fieldStr = jobInfo.getDestTableFields();  
  26.         String[] fields = jobInfo.getDestTableFields().split(",");  
  27.         fields = this.trimArrayItem(fields);  
  28.         String[] updateFields = jobInfo.getDestTableUpdate().split(",");  
  29.         updateFields = this.trimArrayItem(updateFields);  
  30.         String destTableKey = jobInfo.getDestTableKey();  
  31.         String destTable = jobInfo.getDestTable();  
  32.         Statement stat = conn.createStatement();  
  33.         ResultSet rs = stat.executeQuery(srcSql);  
  34.         StringBuffer sql = new StringBuffer();  
  35.         long count = 0;  
  36.         while (rs.next()) {  
  37.             sql.append("if not exists (select ").append(destTableKey).append(" from ").append(destTable).append(" where ").append(destTableKey).append("='").append(rs.getString(destTableKey))  
  38.                             .append("')").append("insert into ").append(destTable).append("(").append(fieldStr).append(") values(");  
  39.             for (int index = 0; index < fields.length; index++) {  
  40.                 sql.append("'").append(rs.getString(fields[index])).append(index == (fields.length - 1) ? "'" : "',");  
  41.             }  
  42.             sql.append(") else update ").append(destTable).append(" set ");  
  43.             for (int index = 0; index < updateFields.length; index++) {  
  44.                 sql.append(updateFields[index]).append("='").append(rs.getString(updateFields[index])).append(index == (updateFields.length - 1) ? "'" : "',");  
  45.             }  
  46.             sql.append(" where ").append(destTableKey).append("='").append(rs.getString(destTableKey)).append("';");  
  47.             count++;  
  48.             // this.logger.info("第" + count + "耗时: " + (new Date().getTime() - oneStart) + "ms");  
  49.         }  
  50.         this.logger.info("总共查询到 " + count + " 条记录");  
  51.         if (rs != null) {  
  52.             rs.close();  
  53.         }  
  54.         if (stat != null) {  
  55.             stat.close();  
  56.         }  
  57.         return count > 0 ? sql.toString() : null;  
  58.     }  
  59.       
  60.     @Override  
  61.     public void executeSQL(String sql, Connection conn) throws SQLException {  
  62.         PreparedStatement pst = conn.prepareStatement(sql);  
  63.         pst.executeUpdate();  
  64.         conn.commit();  
  65.         pst.close();  
  66.     }  
  67. }  

10、创建同步对象的工厂类DBSyncFactory

这里,我们以工厂的形式来创建MySQLSync类或者SQLServerSync类,具体创建哪个类是根据传递的数据库类型决定的,具体见如下代码:

[java]  view plain  copy
  1. package io.mykit.db.sync.provider.factory;  
  2.   
  3. import io.mykit.db.sync.provider.constants.Constants;  
  4. import io.mykit.db.sync.provider.sync.DBSync;  
  5. import io.mykit.db.sync.provider.sync.impl.MySQLSync;  
  6. import io.mykit.db.sync.provider.sync.impl.SQLServerSync;  
  7. import io.mykit.db.sync.provider.utils.StringUtils;  
  8.   
  9. /** 
  10.  * 创建同步对象的工厂类 
  11.  * @author liuyazhuang 
  12.  * 
  13.  */  
  14. public class DBSyncFactory {  
  15.       
  16.     /** 
  17.      * 根据数据库的类型创建不同的同步数据库数据的对象 
  18.      * @param type:数据库类型 
  19.      * @return:同步数据库数据的对象 
  20.      */  
  21.     public static DBSync create(String type){  
  22.         if(StringUtils.isEmpty(type)) return null;  
  23.         switch (type) {  
  24.         case Constants.TYPE_DB_MYSQL:  
  25.             return new MySQLSync();  
  26.         case Constants.TYPE_DB_SQLSERVER:  
  27.             return new SQLServerSync();  
  28.         default:  
  29.             return null;  
  30.         }  
  31.     }  
  32. }  

11、创建同步数据库任务的具体实现类JobTask

这个类实现org.quartz.Job接口,主要实现定时任务同步数据库,具体见如下代码:

[java]  view plain  copy
  1. package io.mykit.db.sync.provider;  
  2.   
  3. import java.sql.Connection;  
  4. import java.sql.DriverManager;  
  5. import java.sql.SQLException;  
  6. import java.util.Date;  
  7.   
  8. import org.apache.log4j.Logger;  
  9. import org.quartz.Job;  
  10. import org.quartz.JobDataMap;  
  11. import org.quartz.JobExecutionContext;  
  12. import org.quartz.JobExecutionException;  
  13.   
  14. import io.mykit.db.sync.provider.entity.DBInfo;  
  15. import io.mykit.db.sync.provider.entity.JobInfo;  
  16. import io.mykit.db.sync.provider.factory.DBSyncFactory;  
  17. import io.mykit.db.sync.provider.sync.DBSync;  
  18.   
  19. /** 
  20.  * 同步数据库任务的具体实现 
  21.  * @author liuyazhuang 
  22.  * 
  23.  */  
  24. public class JobTask implements Job {  
  25.     private Logger logger = Logger.getLogger(JobTask.class);  
  26.   
  27.     /** 
  28.      * 执行同步数据库任务 
  29.      * 
  30.      */  
  31.     @Override  
  32.     public void execute(JobExecutionContext context) throws JobExecutionException {  
  33.         this.logger.info("开始任务调度: " + new Date());  
  34.         Connection inConn = null;  
  35.         Connection outConn = null;  
  36.         JobDataMap data = context.getJobDetail().getJobDataMap();  
  37.         DBInfo srcDb = (DBInfo) data.get("srcDb");  
  38.         DBInfo destDb = (DBInfo) data.get("destDb");  
  39.         JobInfo jobInfo = (JobInfo) data.get("jobInfo");  
  40.         String logTitle = (String) data.get("logTitle");  
  41.         try {  
  42.             inConn = createConnection(srcDb);  
  43.             outConn = createConnection(destDb);  
  44.             if (inConn == null) {  
  45.                 this.logger.info("请检查源数据连接!");  
  46.                 return;  
  47.             } else if (outConn == null) {  
  48.                 this.logger.info("请检查目标数据连接!");  
  49.                 return;  
  50.             }  
  51.   
  52.             DBSync dbHelper = DBSyncFactory.create(destDb.getDbtype());  
  53.             long start = new Date().getTime();  
  54.             String sql = dbHelper.assembleSQL(jobInfo.getSrcSql(), inConn, jobInfo);  
  55.             this.logger.info("组装SQL耗时: " + (new Date().getTime() - start) + "ms");  
  56.             if (sql != null) {  
  57.                 this.logger.debug(sql);  
  58.                 long eStart = new Date().getTime();  
  59.                 dbHelper.executeSQL(sql, outConn);  
  60.                 this.logger.info("执行SQL语句耗时: " + (new Date().getTime() - eStart) + "ms");  
  61.             }  
  62.         } catch (SQLException e) {  
  63.             this.logger.error(logTitle + e.getMessage());  
  64.             this.logger.error(logTitle + " SQL执行出错,请检查是否存在语法错误");  
  65.         } finally {  
  66.             this.logger.error("关闭源数据库连接");  
  67.             destoryConnection(inConn);  
  68.             this.logger.error("关闭目标数据库连接");  
  69.             destoryConnection(outConn);  
  70.         }  
  71.     }  
  72.   
  73.     /** 
  74.      * 创建数据库连接 
  75.      * @param db 
  76.      * @return 
  77.      */  
  78.     private Connection createConnection(DBInfo db) {  
  79.         try {  
  80.             Class.forName(db.getDriver());  
  81.             Connection conn = DriverManager.getConnection(db.getUrl(), db.getUsername(), db.getPassword());  
  82.             conn.setAutoCommit(false);  
  83.             return conn;  
  84.         } catch (Exception e) {  
  85.             this.logger.error(e.getMessage());  
  86.         }  
  87.         return null;  
  88.     }  
  89.   
  90.     /** 
  91.      * 关闭并销毁数据库连接 
  92.      * @param conn 
  93.      */  
  94.     private void destoryConnection(Connection conn) {  
  95.         try {  
  96.             if (conn != null) {  
  97.                 conn.close();  
  98.                 conn = null;  
  99.                 this.logger.error("数据库连接关闭");  
  100.             }  
  101.         } catch (SQLException e) {  
  102.             e.printStackTrace();  
  103.         }  
  104.     }  
  105. }  

12、创建同步数据库资源的整合类DBSyncBuilder

这个类的主要作用是整合本工程的所有资源,比如:读取相关的配置文件,通过工厂类DBSyncFactory实例化具体的同步对象,启动定时任务,同步数据库数据等。具体见如下代码:

[java]  view plain  copy
  1. package io.mykit.db.sync.build;  
  2.   
  3. import static org.quartz.CronScheduleBuilder.cronSchedule;  
  4. import static org.quartz.JobBuilder.newJob;  
  5. import static org.quartz.TriggerBuilder.newTrigger;  
  6.   
  7. import java.lang.reflect.Field;  
  8. import java.util.ArrayList;  
  9. import java.util.Iterator;  
  10. import java.util.List;  
  11.   
  12. import org.apache.log4j.Logger;  
  13. import org.dom4j.Element;  
  14. import org.dom4j.io.SAXReader;  
  15. import org.quartz.CronTrigger;  
  16. import org.quartz.JobDetail;  
  17. import org.quartz.Scheduler;  
  18. import org.quartz.SchedulerFactory;  
  19. import org.quartz.impl.StdSchedulerFactory;  
  20.   
  21. import io.mykit.db.sync.provider.JobTask;  
  22. import io.mykit.db.sync.provider.entity.DBInfo;  
  23. import io.mykit.db.sync.provider.entity.JobInfo;  
  24.   
  25. /** 
  26.  * 同步数据库数据的Builder对象 
  27.  * @author liuyazhuang 
  28.  * 
  29.  */  
  30. public class DBSyncBuilder {  
  31.       
  32.     private DBInfo srcDb;  
  33.     private DBInfo destDb;  
  34.     private List<JobInfo> jobList;  
  35.     private String code;  
  36.     private static Logger logger = Logger.getLogger(DBSyncBuilder.class);  
  37.       
  38.     private DBSyncBuilder(){  
  39.     }  
  40.       
  41.     /** 
  42.      * 创建DBSyncBuilder对象 
  43.      * @return DBSyncBuilder对象 
  44.      */  
  45.     public static DBSyncBuilder builder(){  
  46.         return new DBSyncBuilder();  
  47.     }  
  48.   
  49.     /** 
  50.      * 初始化数据库信息并解析jobs.xml填充数据 
  51.      * @return DBSyncBuilder对象 
  52.      */  
  53.     public DBSyncBuilder init() {  
  54.         srcDb = new DBInfo();  
  55.         destDb = new DBInfo();  
  56.         jobList = new ArrayList<JobInfo>();  
  57.         SAXReader reader = new SAXReader();  
  58.         try {  
  59.             // 读取xml的配置文件名,并获取其里面的节点  
  60.             Element root = reader.read("jobs.xml").getRootElement();  
  61.             Element src = root.element("source");  
  62.             Element dest = root.element("dest");  
  63.             Element jobs = root.element("jobs");  
  64.             // 遍历job即同步的表  
  65.             for (@SuppressWarnings("rawtypes")  
  66.             Iterator it = jobs.elementIterator("job"); it.hasNext();) {  
  67.                 jobList.add((JobInfo) elementInObject((Element) it.next(), new JobInfo()));  
  68.             }  
  69.             //  
  70.             elementInObject(src, srcDb);  
  71.             elementInObject(dest, destDb);  
  72.             code = root.element("code").getTextTrim();  
  73.         } catch (Exception e) {  
  74.             e.printStackTrace();  
  75.         }  
  76.         return this;  
  77.     }  
  78.   
  79.     /** 
  80.      * 解析e中的元素,将数据填充到o中 
  81.      * @param e 解析的XML Element对象 
  82.      * @param o 存放解析后的XML Element对象 
  83.      * @return 存放有解析后数据的Object 
  84.      * @throws IllegalArgumentException 
  85.      * @throws IllegalAccessException 
  86.      */  
  87.     public Object elementInObject(Element e, Object o) throws IllegalArgumentException, IllegalAccessException {  
  88.         Field[] fields = o.getClass().getDeclaredFields();  
  89.         for (int index = 0; index < fields.length; index++) {  
  90.             fields[index].setAccessible(true);  
  91.             fields[index].set(o, e.element(fields[index].getName()).getTextTrim());  
  92.         }  
  93.         return o;  
  94.     }  
  95.   
  96.     /** 
  97.      * 启动定时任务,同步数据库的数据 
  98.      */  
  99.     public void start() {  
  100.         for (int index = 0; index < jobList.size(); index++) {  
  101.             JobInfo jobInfo = jobList.get(index);  
  102.             String logTitle = "[" + code + "]" + jobInfo.getName() + " ";  
  103.             try {  
  104.                 SchedulerFactory sf = new StdSchedulerFactory();  
  105.                 Scheduler sched = sf.getScheduler();  
  106.                 JobDetail job = newJob(JobTask.class).withIdentity("job-" + jobInfo.getName(), code).build();  
  107.                 job.getJobDataMap().put("srcDb", srcDb);  
  108.                 job.getJobDataMap().put("destDb", destDb);  
  109.                 job.getJobDataMap().put("jobInfo", jobInfo);  
  110.                 job.getJobDataMap().put("logTitle", logTitle);  
  111.                 logger.info(jobInfo.getCron());  
  112.                 CronTrigger trigger = newTrigger().withIdentity("trigger-" + jobInfo.getName(), code).withSchedule(cronSchedule(jobInfo.getCron())).build();  
  113.                 sched.scheduleJob(job, trigger);  
  114.                 sched.start();  
  115.             } catch (Exception e) {  
  116.                 logger.info(logTitle + e.getMessage());  
  117.                 logger.info(logTitle + " run failed");  
  118.                 continue;  
  119.             }  
  120.         }  
  121.     }  
  122. }  

13、创建工程的入口类Main

此类为启动工程的入口类,具体见如下代码:

[java]  view plain  copy
  1. package io.mykit.db.sync;  
  2.   
  3. import io.mykit.db.sync.build.DBSyncBuilder;  
  4.   
  5.   
  6. /** 
  7.  * 程序入口 
  8.  * @author liuyazhuang 
  9.  * 
  10.  */  
  11. public class Main {  
  12.   
  13.     public static void main(String[] args) {  
  14.         DBSyncBuilder.builder().init().start();  
  15.     }  
  16. }  

五、资源配置

写完具体的业务代码后,我们就要完善相关的配置文件信息了。

1、创建配置文件jobs.xml

这个文件是我们整个工程中最核心的配置文件,在这个文件中定义了同步的源数据库信息和目标数据库信息,同步任务等,同时定义了同步数据的数据表和数据字段等信息,具体参见如下配置

[html]  view plain  copy
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <root>  
  3.     <code>4500000001</code>  
  4. <!--     <source>  
  5.         <url>jdbc:oracle:thin:@192.168.1.179:1521:XE</url>  
  6.         <username>test</username>  
  7.         <password>test</password>  
  8.         <dbtype>oracle</dbtype>  
  9.         <driver>oracle.jdbc.driver.OracleDriver</driver>  
  10.     </source>  
  11.     <dest>  
  12.         <url>jdbc:sqlserver://192.168.1.191:1433;DatabaseName=test</url>  
  13.         <username>test</username>  
  14.         <password>test</password>  
  15.         <dbtype>sqlserver</dbtype>  
  16.         <driver>com.microsoft.sqlserver.jdbc.SQLServerDriver</driver>  
  17.     </dest> -->  
  18.     <source>  
  19.         <url>jdbc:mysql://192.168.209.121:3306/test</url>  
  20.         <username>root</username>  
  21.         <password>root</password>  
  22.         <dbtype>mysql</dbtype>  
  23.         <driver>com.mysql.jdbc.Driver</driver>  
  24.     </source>  
  25.     <dest>  
  26.         <url>jdbc:mysql://127.0.0.1:3306/test</url>  
  27.         <username>root</username>  
  28.         <password>root</password>  
  29.         <dbtype>mysql</dbtype>  
  30.         <driver>com.mysql.jdbc.Driver</driver>  
  31.     </dest>  
  32.     <jobs>  
  33.         <job>  
  34.             <name>1</name>  
  35.             <cron>0/10 * * * * ?</cron>  
  36.             <srcSql>select user_id, account,password from user</srcSql>  
  37.             <destTable>client_user</destTable>  
  38.             <destTableFields>user_id, account</destTableFields>  
  39.             <destTableKey>user_id</destTableKey>  
  40.             <destTableUpdate>account</destTableUpdate>  
  41.         </job>  
  42.     </jobs>  
  43. </root>  

2、创建log4j.properties

这个就不多说了,具体如下:

[plain]  view plain  copy
  1. log4j.rootCategory=INFO,A1,A2,A3  
  2. log4j.appender.A1=org.apache.log4j.ConsoleAppender  
  3. log4j.appender.A1.layout=org.apache.log4j.PatternLayout  
  4. log4j.appender.A1.layout.ConversionPattern=%4p [%t] (%F:%L) - %m%n  
  5. log4j.appender.A2=org.apache.log4j.RollingFileAppender  
  6. log4j.appender.A2.File=./databaseSync.log  
  7. log4j.appender.A2.MaxFileSize = 10MB  
  8. log4j.appender.A2.MaxBackupIndex = 10  
  9. log4j.appender.A2.layout=org.apache.log4j.PatternLayout  
  10. log4j.appender.A2.layout.ConversionPattern=%d{yyyy-MM-dd hh:mm:ss}:%p %t %c - %m%n  

3、创建pom.xml

这个文件定义了我们的项目结构和依赖,具体如下:

[html]  view plain  copy
  1. <?xml version="1.0"?>  
  2. <project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"  
  3.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">  
  4.   <modelVersion>4.0.0</modelVersion>  
  5.   <groupId>io.mykit</groupId>  
  6.   <artifactId>mykit-db-sync-provider</artifactId>  
  7.   <version>1.0.0</version>  
  8.   <name>mykit-db-sync-provider</name>  
  9.      
  10.   <licenses>  
  11.     <license>  
  12.         <name>Apache 2</name>  
  13.         <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>  
  14.         <distribution>repo</distribution>  
  15.         <comments>A business-friendly OSS license</comments>  
  16.     </license>  
  17.   </licenses>  
  18.   
  19.   <properties>  
  20.     <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>  
  21.     <skip_maven_deploy>false</skip_maven_deploy>  
  22.     <jdk.version>1.8</jdk.version>  
  23.     <spring.version>4.1.0.RELEASE</spring.version>  
  24.   </properties>  
  25.   
  26.   <dependencies>  
  27.         <dependency>    
  28.             <groupId>org.slf4j</groupId>    
  29.             <artifactId>slf4j-log4j12</artifactId>    
  30.             <version>1.7.2</version>    
  31.         </dependency>   
  32.           
  33.           <dependency>  
  34.             <groupId>commons-logging</groupId>  
  35.             <artifactId>commons-logging</artifactId>  
  36.             <version>1.1.1</version>  
  37.         </dependency>  
  38.           
  39.         <dependency>  
  40.             <groupId>junit</groupId>  
  41.             <artifactId>junit</artifactId>  
  42.             <version>4.12</version>  
  43.             <scope>test</scope>  
  44.         </dependency>  
  45.   
  46.        <dependency>  
  47.             <groupId>mysql</groupId>  
  48.             <artifactId>mysql-connector-java</artifactId>  
  49.             <version>5.1.22</version>  
  50.         </dependency>  
  51.           
  52.         <dependency>  
  53.             <groupId>dom4j</groupId>  
  54.             <artifactId>dom4j</artifactId>  
  55.             <version>1.6.1</version>  
  56.         </dependency>  
  57.           
  58. <!--         <dependency>  
  59.             <groupId>com.microsoft.sqlserver</groupId>  
  60.             <artifactId>sqljdbc4</artifactId>  
  61.             <version>1.0</version>  
  62.         </dependency> -->  
  63.       
  64.         <dependency>  
  65.             <groupId>org.quartz-scheduler</groupId>  
  66.             <artifactId>quartz</artifactId>  
  67.             <version>2.1.3</version>  
  68.         </dependency>  
  69.           
  70. <!--         <dependency>  
  71.             <groupId>com.oracle</groupId>   
  72.             <artifactId>ojdbc6</artifactId>   
  73.             <version>11.2.0.3</version>   
  74.         </dependency>      -->  
  75.   </dependencies>  
  76.     
  77.   <build>  
  78.         <plugins>  
  79.             <plugin>  
  80.                 <groupId>org.apache.maven.plugins</groupId>  
  81.                 <artifactId>maven-jar-plugin</artifactId>  
  82.                 <configuration>  
  83.                     <archive>  
  84.                         <manifest>  
  85.                             <addClasspath>true</addClasspath>  
  86.                             <classpathPrefix>lib/</classpathPrefix>  
  87.                             <mainClass>io.mykit.db.sync.Main</mainClass>  
  88.                         </manifest>  
  89.                     </archive>  
  90.                 </configuration>  
  91.             </plugin>  
  92.             <plugin>  
  93.                 <groupId>org.apache.maven.plugins</groupId>  
  94.                 <artifactId>maven-dependency-plugin</artifactId>  
  95.                 <executions>  
  96.                     <execution>  
  97.                         <id>copy</id>  
  98.                         <phase>package</phase>  
  99.                         <goals>  
  100.                             <goal>copy-dependencies</goal>  
  101.                         </goals>  
  102.                         <configuration>  
  103.                             <outputDirectory>${project.build.directory}/lib</outputDirectory>  
  104.                         </configuration>  
  105.                     </execution>  
  106.                 </executions>  
  107.             </plugin>  
  108.               
  109.             <plugin>  
  110.                 <groupId>org.mortbay.jetty</groupId>  
  111.                 <artifactId>maven-jetty-plugin</artifactId>  
  112.                 <version>6.1.10</version>  
  113.           
  114.           </plugin>  
  115.         </plugins>  
  116.         <resources>  
  117.             <resource>  
  118.                 <directory>src/main/java</directory>  
  119.                 <includes>  
  120.                     <include>**/*.properties</include>  
  121.                     <include>**/*.xml</include>  
  122.                 </includes>  
  123.                 <filtering>true</filtering>  
  124.             </resource>  
  125.         </resources>  
  126.     </build>  
  127. </project>  

至此,我们就实现了基于java开发的功能强大、配置灵活的数据库之间的同步工具,大家可以根据具体需求修改job.xml中的相关配置信息即可实现数据库之前的同步。

猜你喜欢

转载自blog.csdn.net/u011109589/article/details/80356053
今日推荐