利用mybatis generator实现数据库之间的表同步

项目背景:

项目需要对两个服务器上的表进行同步,表的结构可能不一样。比如服务器A上的表i同步数据到服务器B上的表j,i和j的结构可能不一样,当然大部分字段是一样的。项目看起来很简单,网上一搜也是很多,什么利用Oracle的同步工具,利用mybatis拦截器拦截sql语句等等。不好意思,由于种种原因,我们项目都没有办法使用。我们最后讨论的方案就是最传统的暴力解决,一条一条插入或者更新,当然这有一个很重要的前提,就是我们的数据不多,最多也就是几万条,如果数据量很多,比如上千万的这种级别,这种方案估计就有待商榷了。

项目技术:

在我不知道有mybatis generator的时候,我想着,一张表恨不得几百个字段,我一个一个敲要敲到什么时候,而且很容易出错!是的,我曾经经历过这样的痛楚,如果后面表的字段要改的话,我去,代码很多地方也要改,可谓牵一发而动全身,程序出错的机率非常大。而且,sql语句写起来也很麻烦,insert、update、select等等,太多字段,太多条件,简直哭死。后来,我接触到mybatis generator,我终于明白,什么才叫框架!这才是真正的框架,大大简化了开发!这是我目前遇到的最好的一个框架,没有之一!我用这个来开发,完全不需要关注sql语句怎么写,实体类怎么写,只需要关注业务逻辑,真正的解耦!太NB了!

好了,说到这里,我们项目没有用到什么高深的技术,就是mybatis和mybatis generator,语言是Java,所有的业务逻辑代码不到500行。

项目实施:

1.建立maven项目

利用eclipse建立一个maven工程,无需选择webapp类型,就简单的工程就行了,在pom.xml中添加要依赖的项目:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <groupId>cn.huifu</groupId>
<artifactId>dataSynTest</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging> <name>dataSynTest</name>
<url>http://maven.apache.org</url> <properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties> <dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency> <dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
<version>1.3.5</version>
</dependency> <dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.5</version>
</dependency> <dependency>
<groupId>com.oracle</groupId>
<artifactId>ojdbc6</artifactId>
<version>11.2.0.3</version>
</dependency> <!-- 日志框架 -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.3</version>
</dependency> <dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.25</version>
</dependency> </dependencies> <build>
<finalName>dataSynTest</finalName>
<plugins>
<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.3.6</version>
<configuration>
<configurationFile>${basedir}/src/main/resources/generatorConfig.xml</configurationFile>
<overwrite>true</overwrite>
<verbose>true</verbose>
</configuration>
</plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>application.App</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin> </plugins>
</build> </project>

这里我贴一下所有的xml内容,这很重要,有很多博客,这部分不贴,都不知道他们项目用了哪些依赖,我们根本没有办法复现,即使知道用了哪些依赖,版本不一致的话,也会导致项目失败,因为可能不兼容。不难看到,我们用了mybatis generator和mybatis的相关依赖,同时还用了ojdbc6,因为我们用的是Oracle数据库,所以需要有这个依赖。然后还有一些日志的依赖。

2.mybatis generator的安装和使用

然后需要注意的是plugin中需要添加mybatis generator插件,并且定义配置文件的位置。要让mybatis generator可以在eclipse运行,还需要在eclipse的应用商店中安装mybatis generator插件,查询到了,直接install就行了。

ok,现在工具已经准备好了,下面我们先试一把,我们项目的目录如下,generatorConfig.xml在src/main/resources下面

利用mybatis generator实现数据库之间的表同步

具体内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<!-- 数据库驱动:选择你的本地硬盘上面的数据库驱动包-->
<!-- <classPathEntry location="E:\mysql\mysql-connector-java-5.1.46.jar"/> -->
<context id="DB2Tables" targetRuntime="MyBatis3">
<commentGenerator>
<property name="suppressDate" value="true"/>
<!-- 是否去除自动生成的注释 true:是 : false:否 -->
<property name="suppressAllComments" value="true"/>
</commentGenerator>
<!--数据库链接URL,用户名、密码 -->
<!-- 数据源配置 -->
<jdbcConnection driverClass="oracle.jdbc.OracleDriver" connectionURL="jdbc:oracle:thin:@192.168.4.228:1521:testdb" userId="gadbusr" password="gadbusr">
<!-- 数据目标配置 -->
<!-- <jdbcConnection driverClass="oracle.jdbc.OracleDriver" connectionURL="jdbc:oracle:thin:@192.168.4.228:1521:testdb" userId="newhl" password="newhl"> --> </jdbcConnection>
<javaTypeResolver>
<property name="forceBigDecimals" value="false"/>
</javaTypeResolver>
<!-- 生成模型的包名和位置-->
<javaModelGenerator targetPackage="mybatis.model" targetProject="dataSyn/src/main/java">
</javaModelGenerator>
<!-- 生成映射文件的包名和位置-->
<sqlMapGenerator targetPackage="mybatis.mapping" targetProject="dataSyn/src/main/java/">
</sqlMapGenerator>
<!-- 生成DAO的包名和位置 -->
<javaClientGenerator type="XMLMAPPER" targetPackage="mybatis.mapper" targetProject="dataSyn/src/main/java">
</javaClientGenerator>
<!-- 要生成的表 tableName是数据库中的表名或视图名 domainObjectName是实体类名-->
<!-- <table tableName="people_for_test" domainObjectName="Person" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"></table> -->
<!-- <table tableName="mer_base_info" domainObjectName="MerBaseInfo"></table> -->
<!-- <table tableName="mer_base_info_syn" domainObjectName="MerBaseInfoSyn"></table> -->
<!-- <table tableName="field_syn_info" domainObjectName="FieldSynInfo"></table> -->
<!-- <table tableName="table_syn_info" domainObjectName="TableSynInfo"></table> -->
<table tableName="usr_info" domainObjectName="UsrInfo" schema="GADBUSR"></table>
<!-- <table tableName="usr_info_syn" domainObjectName="UsrInfoSyn"></table> -->
<!-- <table tableName="mer_trans_info" domainObjectName="MerTransInfo" schema="GADBUSR"></table> -->
<!-- <table tableName="mer_trans_info_syn" domainObjectName="MerTransInfoSyn" schema="NEWHL"></table> --> </context> </generatorConfiguration>

主要注意数据库驱动,因为我们已经依赖了ojdbc6,所以这里不用这个,而且这种写死地址的方法也不好,不方便代码迁移。然后就是数据源的配置,你的驱动类型,我们用的是Oracle,所以是Oracle的驱动类型,然后是url,用户名和密码。这些配置好后,就是最重要的3个配置,分别是model、mapping和dao的配置,主要就是注意路径和包名,要与你自己的项目一致,其他默认的就行了,最后,就是表名的配置,根据你数据库的表名配置一下,以及生成实体类的名字。这里特别要注意一下就是schema这个字段,最好加上,我之前做的时候,没有加,导致有些数据库的用户,他会遍历所有的相同表名出来,导致代码重复。比如我代码中gadbusr,如果不加上schema这个字段,它会找出什么newhl.usr_info,gadbusrtmp.usr_info...而如果用newhl,则只会找出newhl.usr_info,估计是newhl和gadbusr在数据库的权限不一致导致的,所以最好加上,以防万一。

这些,确认无误之后,右键->run as->run mybatis generator,就会在相应的目录下生成文件,sql、dao、mapper什么的都生成好,是不是特别神奇!最绝的是,sql这种形式是万能的,你无论增删查改都可以用example的模板,简直太NB!你不需要写一行sql语句,就能实现几乎所有的增删查改,而且基本不会出错,我的天,每次想到这个,就感觉写这个框架的人很了不起,看起来没有什么高大上的东西,但是确实大大方便了开发人员!

3.实现业务逻辑代码

有了上面的这些之后,就可以开始我们的业务逻辑代码编写了,用到的是mybatis,我们没有集成spring,纯Java写的,因为项目很小。

业务逻辑:建立两张表,一张用了存储需要同步的表,一张用来存储字段(根据这个字段可以来找到哪条记录需要同步,其实就是唯一索引字段)。然后到数据库A中去查询出所有的记录,再将这些记录逐一到数据库B中去查找,如果没有找到,则插入,如果找到了,则比较这两条记录,如果记录相等,则不做处理,如果记录不相等,则进行更新。其中判断两条记录用到了反射机制,用反射机制来找到属性值,然后比较,再调用set函数。这里的记录是经过mybatis把数据库的一条记录转换成Java对象,保存在内存中,所以可以相互比较。具体代码,我已经把代码部署到github上了,在文末可以找到。

这里还要注意一下,因为是两个数据库,所以要配置两个数据源,并且需要在代码中创建两个sqlsession。mybatis配置如下:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <environments default="dataSourceA"> <environment id="dataSourceA">
<!-- mybatis使用jdbc事务管理方式 -->
<transactionManager type="JDBC" />
<!-- mybatis使用连接池方式来获取连接 -->
<dataSource type="POOLED">
<property name="driver" value="oracle.jdbc.OracleDriver" />
<property name="url" value="jdbc:oracle:thin:@192.168.4.228:1521:testdb" />
<property name="username" value="gadbusr" />
<property name="password" value="gadbusr" />
</dataSource>
</environment> <environment id="dataSourceB">
<!-- mybatis使用jdbc事务管理方式 -->
<transactionManager type="JDBC" />
<!-- mybatis使用连接池方式来获取连接 -->
<dataSource type="POOLED">
<property name="driver" value="oracle.jdbc.OracleDriver" />
<property name="url" value="jdbc:oracle:thin:@192.168.4.228:1521:testdb" />
<property name="username" value="newhl" />
<property name="password" value="newhl" />
</dataSource>
</environment> </environments> <mappers>
<mapper resource="mybatis/mapping/FieldSynInfoMapper.xml" />
<mapper resource="mybatis/mapping/MerBaseInfoMapper.xml" />
<mapper resource="mybatis/mapping/MerBaseInfoSynMapper.xml" />
<mapper resource="mybatis/mapping/MerTransInfoMapper.xml" />
<mapper resource="mybatis/mapping/MerTransInfoSynMapper.xml" />
<mapper resource="mybatis/mapping/TableSynInfoMapper.xml" />
<mapper resource="mybatis/mapping/UsrInfoMapper.xml" />
<mapper resource="mybatis/mapping/UsrInfoSynMapper.xml" />
</mappers> </configuration>

可以看到有两个environment,分别代表不同的数据源,“POOLED”表示使用数据库连接池。mappers中添加所有要用到的mapper文件。

项目运行:

可以直接run as。当然,作为同步工具,需要触发程序,所以我们想的是用maven来打包成jar包,然后部署到Linux服务器上,用crontab来设置定时任务。用maven来打包可以我之前写的博客,在pom.xml中也会用这个打包插件,然后执行mvn install,最终会生成一个独立的可以运行的jar包,不需要其他的jar包,因为所有的都在一个独立的jar包中

后续改进:

1.一次读取数据到list中,会不会导致内存爆掉?

2.效率不知道高不高,考虑用多线程来处理。

相关链接:

1.mybatis的官方指导文章,中文的,写得很清楚,很详细,包括多数据源配置,怎么使用mybatis来操作等等,强烈推荐:http://www.mybatis.org/mybatis-3/zh/configuration.html

2.一个java实现的mybatis批量插入数据库,但是没有使用mybatis generator,可以看看:https://www.jb51.net/article/86914.htm

3.Oracle高效数据库同步:http://blog.sina.com.cn/s/blog_828f81c80102wpwo.html

4.阿里巴巴开源的数据库同步方案-otter,人家这个当然是支持大数据量,并且时效性也很高,如果是牛人,当然是参考这个:https://github.com/alibaba/otter 但是它也是有使用场景的,它好像是根据日志来找到sql语句,这个场景估计不是什么项目都能用。哎,虽然很高大上,但是适合自己的才是最好的。

5.本项目的代码地址:https://github.com/fxlnjfu/MybatisSyn

上一篇:struts.xml语法


下一篇:java web系统优化, mysql查询优化