zoukankan      html  css  js  c++  java
  • 利用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下面

    具体内容如下:

    <?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:mysqlmysql-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

  • 相关阅读:
    I NEED A OFFER!
    水题 Codeforces Round #303 (Div. 2) A. Toy Cars
    模拟 HDOJ 5099 Comparison of Android versions
    模拟 HDOJ 5095 Linearization of the kernel functions in SVM
    贪心 HDOJ 5090 Game with Pearls
    Kruskal HDOJ 1863 畅通工程
    Kruskal HDOJ 1233 还是畅通工程
    并查集 HDOJ 1232 畅通工程
    DFS/并查集 Codeforces Round #286 (Div. 2) B
    水题 Codeforces Round #286 (Div. 2) A Mr. Kitayuta's Gift
  • 原文地址:https://www.cnblogs.com/fxl-njfu/p/10039694.html
Copyright © 2011-2022 走看看