閱讀303 返回首頁    go 阿裏雲 go 技術社區[雲棲]


數據集成通過JDBC將數據導入MySQL的幾種模式

目前MySQL JDBC提供了多種將數據寫入MySQL的方式,本文將介紹數據集成(DataX、同步中心、原CDP)支持的幾種模式:

  • insert into xxx values (..), (..), (..)
  • replace into xxx values (..), (..), (..)
  • insert into xxx values (..), (..), (..), … on duplicate key update …

1、功能區別

1.1 insert into 方式

常規的SQL插入,如果提交的MySQL Server端的數據違反了數據庫約束(主鍵衝突、數據類型不匹配)會直接報錯;
對應在數據集成中會報髒數據。 常用於向一張空表裏麵插入數據

1.2 replace into 方式

與insert into類似,區別:假如將要插入表新記錄中主鍵(PRIMARYKEY或UNIQUE索引)與表中舊記錄衝突,replace into自身具有處理衝突的能力:

  • 1、當存在pk衝突的時候是先delete再insert
  • 2、當存在uk衝突的時候是直接update

** 使用replace into 注意事項 **

  • 1、能夠使用replace,您必須同時擁有表的insert和delete權限;
  • 2、衝突記錄:新記錄與舊記錄的主鍵值不同,所以其他表中所有與本表老數據主鍵id建立的關聯全部會被破壞;
  • 3、衝突記錄:所有列的值均取自在熱replace語句中被指定的值。所有缺失的列被設置為各自的默認值,即如果您每次同步的不是表的所有列,會存在一些列在舊記錄中有值,replace into後無值的情況;
  • 4、replace語句會返回一個數,來指示受影響的行的數目。該數是被刪除和被插入的行數的和。

1.3 insert into… on duplicate key update 方式

將要插入表新記錄中主鍵(PRIMARYKEY或UNIQUE索引)與表中舊記錄衝突(具有相同的值),則update舊記錄。

3、Replace into 存在的坑

  • 如果庫存在主備,基於uk去做replace into時,會造成主備的auto_increment不一致(備庫因auto_increment小於實際數據的最大值),在主備切換插入時造成replace into出錯,失敗一次後,會更新auto_increment為最大值+1;

3.1 實例

master:
use test;
CREATE TABLE `test` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `k` int(10) unsigned NOT NULL,
  `v` varchar(100) DEFAULT NULL,
  `extra` varchar(200) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_k` (`k`)
) ENGINE=InnoDB ;

insert into test(k,v,extra) values(1,1,'extra1'),(2,2,'extra2',3,3,'extra3');

插入完成後,主庫和備庫數據和schema完全一致;執行replace into:

replace into test(k,v) values(1,'1-1');

主備庫數據一致,但是schema不一致。

主庫表結構如下:
CREATE TABLE `test` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `k` int(10) unsigned NOT NULL,
  `v` varchar(100) DEFAULT NULL,
  `extra` varchar(200) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_k` (`k`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=gbk;
備庫:
CREATE TABLE `test` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `k` int(10) unsigned NOT NULL,
  `v` varchar(100) DEFAULT NULL,
  `extra` varchar(200) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_k` (`k`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=gbk;

原因分析:

binlog中記錄的SQL:
### UPDATE test.test
### WHERE
###   @1=1
###   @2=1
###   @3='1'
###   @4='extra1'
### SET
###   @1=4
###   @2=1
###   @3='1-1'
###   @4=NULL

如第一章節所述:
replace into 當存在uk衝突的時候是直接update,update操作不會涉及到auto_increment的修改。

基於此,一些replace操作會被建議使用insert into on duplicate key update。

2、數據集成最佳實踐

目前數據集成對於上述三種模式均已經支持,對應DataX MySQLWriter插件配置項中writeMode字段;

{
  "job": {
    "setting": {
      "speed": {
        "channel": 1
      }
    },
    "content": [
      {
        "reader": {
          "name": "streamreader",
          "parameter": {
            "column": [
              {
                "value": "DataX",
                "type": "string"
              }
            ],
            "sliceRecordCount": 1000
          }
        },
        "writer": {
          "name": "mysqlwriter",
          "parameter": {
            "writeMode": "insert/replace/update",
            "username": "root",
            "password": "root",
            "column": [
              "id",
              "name"
            ],
            "connection": [
              {
                "jdbcUrl": "jdbc:mysql://127.0.0.1:3306/datax?useUnicode=true&characterEncoding=gbk",
                "table": [
                  "test"
                ]
              }
            ]
          }
        }
      }
    ]
  }
}

4.1 數據集成如何保證同步到MySQL作業的冪等性

簡單解釋 冪等性 :多次運行同一個同步作業得到的結果是一致的;

  • 場景一:表中數據可以刪除

在數據集成配置同步任務時,配置前置SQL(delete or truncate表的語句),同步任務在每次執行的時候,在真正同步執行前會執行前置SQL,去清空表,這樣即可以實現多次運行同步任務的冪等性。

  • 場景二:表中數據不能刪除,常見回流線上業務MySQL庫 配置writeMode為 replace 或者 update,同步的時候即會采用replace into 或者 insert into… on duplicate key update 方式插入MySQL數據庫。

參考:

https://askdba.alibaba-inc.com/libary/control/getArticle.do?articleId=12735
https://blog.xupeng.me/2013/10/11/mysql-replace-into-trap/

最後更新:2017-05-08 14:01:30

  上一篇:go PLM日誌
  下一篇:go 關於搭建HTTPS