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

  • 相关阅读:
    葡萄庄园 [图论]
    硬币游戏 [博弈论, 思维题]
    烹饪 [容斥]
    BZOJ1597 [Usaco2008 Mar]土地购买 [斜率优化]
    TCP IP协议
    soap协议
    xml的语法规则
    fiddler的使用
    常见默认端口
    智能休眠时间的使用
  • 原文地址:https://www.cnblogs.com/fxl-njfu/p/10039694.html
Copyright © 2011-2022 走看看