之前有个小的测试项目需要定时同步本地的一些数据到阿里云数据库,用了最机械的脚本执行LOAD DATA来实现,这里简单介绍一下。
LOAD DATA能够快速的将文本文件数据读入表中(导入数据使用LOAD DATA通常比使用INSERT语句快20倍 ),LOAD DATA与SELECT … INTO OUTFILE属于逆向互补功能,要将数据从表导出到文本文件,就使用 SELECT … INTO OUTFILE,反之则使用 LOAD DATA,两者的FIELDS和LINES子句的语法相同。
LOAD DATA
[LOW_PRIORITY | CONCURRENT] [LOCAL] --LOCAL:从客户端主机读取文本文件
INFILE 'file_name'
[REPLACE | IGNORE] --REPLACE:输入行将替换现有重复行,IGNORE:跳过重复行
INTO TABLE tbl_name
[PARTITION (partition_name [, partition_name] ...)]
[CHARACTER SET charset_name] --指定文件中的所有字段解释为具有相同的字符集,而不管字段值加载到的列的数据类型如何
[{FIELDS | COLUMNS} --FIELDS必须在LINES之前
[TERMINATED BY 'string'] --列字段分隔符,默认\t
[[OPTIONALLY] ENCLOSED BY 'char'] --指定列值的包括符,默认空
[ESCAPED BY 'char'] --转义字符,默认\
]
[LINES
[STARTING BY 'string'] --行起始符
[TERMINATED BY 'string'] --换行符,默认\n
]
[IGNORE number {LINES | ROWS}] --导入的时候跳过指定的前几行
[(col_name_or_user_var
[, col_name_or_user_var] ...)]
[SET col_name={expr | DEFAULT}
[, col_name={expr | DEFAULT}] ...]
FIELDS ESCAPED BY控制如何读取或写入特殊字符:
几个官方例子:# 字段由逗号分隔,字段值用双引号引起来,数据文件第一行以列名开头,行以回车/换行符对终止。
LOAD DATA INFILE 'data.txt' INTO TABLE tbl_name
FIELDS TERMINATED BY ',' ENCLOSED BY '"'
LINES TERMINATED BY '\r\n'
IGNORE 1 LINES;
# 以回车/换行对结尾的行
LOAD DATA INFILE '/tmp/jokes.txt' INTO TABLE jokes
FIELDS TERMINATED BY ''
LINES TERMINATED BY '\n%%\n' (joke);
一般情况下,都是本地的数据文件导入到本地的数据库中,弹药将客户端主机上的文件执行导入到远程MySQL数据库,就需要用到LOCAL关键字。这里说明一下:LOCAL仅当服务器和客户端都已配置为允许时才可以使用,例如,如果 mysqld是在local_infile禁用系统变量的情况下启动的,LOCAL则无法使用。
LOAD DATA使用LOCAL存在两个潜在的安全问题:
- 数据库服务器会告诉客户端程序传输服务器选择的文件,而不是语句中命名的文件,数据库服务器可以访问客户端用户具有读取访问权限的客户端主机上的任何文件;
- 在web环境中,客户从web服务器进行连接,用户可以使用LOAD DATA LOCAL来读取Web服务器进程具有读取权限的任何文件(假设用户可以针对SQL Server运行任何语句)。在这种环境下,关于MySQL服务器的客户端实际上是Web服务器,而不是由连接到Web服务器的用户运行的远程程序。
为了避免连接到不受信任的服务器,客户端可以建立安全连接并通过使用–ssl-mode=VERIFY_IDENTITY选项和适当的CA证书进行连接来验证服务器身份;为了控制本地数据加载数据,MySQL允许启用或禁用LOCAL功能,从MySQL 8.0.21开始,MySQL客户端只能从本地指定目录中的数据文件实现加载数据功能。
下面来看通过LOAD DATA LOCAL定时本地同步数据到阿里云的案例,定时:
[root@mysqlplus2 ~]# crontab -e
01 00 * * 1-6 /home/mysqlbak/script/bigdata_impinc.sh
先导出需要的数据:
SELECT insId,areaNo,jointId,contractId,sold
FROM tb_jyx_ins_bizarea into outfile "/home/databak/tb_bizarea.txt" fields terminated by ',';
SELECT tb_member.mid,openid,unionid,cellPhone,nickname,
sex,headImgUrl,country,city,province,xlanguage,privilege,
nextMid,createDatetime,bindphoneDatetime
FROM tb_member where TO_DAYS(NOW())-TO_DAYS(createDatetime)=1 into outfile "/home/databak/tb_member.txt" fields terminated by ',';
SELECT orgID,orgname,disno,province,city,orgnum,fullname,orgtype
FROM tb_organization into outfile "/home/databak/tb_organization.txt" fields terminated by '|';
再看看LOAD DATA:
set autocommit=0;
set unique_checks=0;
load data local infile "/home/databak/tb_bizarea.txt" into table tb_test_bizareafields terminated by ',';
load data local infile "/home/databak/tb_member.txt" replace into table tb_test_member fields terminated by ',';
load data local infile "/home/databak/tb_organization.txt" into table tb_test_organization fields terminated by '|'(orgID,orgname,disno,province,city,orgnum,fullname,orgtype) ;
set unique_checks=1;