利用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:\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


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2020 ITdaan.com