参考网上 LOAD DATA LOCAL INFILE 的使用方法,做了一个demo,记录下主要使用过程
需求:往数据库表插入大量的测试数据
主要步骤:
1.生成一个需要的数据txt文件,这个文件大概长这样
(这里数据格式和样式在后面可根据自己需求修改)
2.将这个文件使用 LOAD DATA LOCAL INFILE 命令导入数据
主要代码
1.数据库连接
//有一种mysqli的set_local_infile_handler的写法,具体没测试,这里使用普通的连接方式
$link = @mysql_connect($host, $user, $password, 1, MYSQL_CLIENT_COMPRESS);
$db = mysql_select_db($dbName, $link);
mysql_query('set names utf8');
2.数据库表处理
该方法取出数据库所有表
//查询所有表,不想往所有表插数据就单独传个表名称参数,跳过该方法
public function tables(){
$return = array();
$sql = " show tables ";
$result = mysql_query($sql);
while( $row = mysql_fetch_array($result) ){
$return[] = $row[0];
}
//mysql_free_result($result);
//取到数据库所有表名
return $return;
}
该方法取出表的所有字段
//获取数据库表的所有字段
//$tableName string 表名
public function columns($tableName=''){
$return = array();
if( $tableName ){
$sql = "SHOW FULL COLUMNS FROM ".$tableName;
$result = mysql_query($sql);
$i = 0;
while( $row = mysql_fetch_array($result) ){
$return[$i] = $row;
$i++;
}
}
return $return;
}
该方法查数据库表的自增id,可查所有表和单表
//获取数据库表的所有字段
public function auto_increment_id($dbName='',$tableName=''){
$return = array();
//所有表状态
$sql = " SHOW TABLE STATUS ";
//单个表状态
if( $dbName && $tableName ){
$sql = " select Auto_increment into autoId from information_schema.tables where Table_Schema = ".$dbName." and table_name = ".$tableName;
}
$result = mysql_query($sql);
while( $row = mysql_fetch_assoc($result) ){
$tmp_arr[] = $row;
}
//只保留自增主键信息
foreach( $tmp_arr as $val ){
$return[$val['Name']] = $val['Auto_increment'];
}
return $return;
}
知道一个表的所有字段,知道它的当前自增id,可以造一条数据
public function doColumns($columns,$auto_increment_id){
$return = array();
if( $columns && $auto_increment_id ){
//一条数据字串
$insert_str = '';
//字段分隔符,这里需要着重强调注意的是,尽量使用默认的tab分隔字段,使用其它的分隔符,后面导入sql需要拼接分隔符语句,而该语句很可能执行不成功
$fenge = "\t";
//循环字段生成一条数据
foreach( $columns as $key=>$val ){
//主键的值
if( $val['Key'] == 'PRI' ){
$insert_str .= $auto_increment_id.$fenge;
}elseif( isset($val['Default']) && $val['Type'] != 'timestamp' ){
//有默认值的数据,以默认值为数据
$insert_str .= $val['Default'].$fenge;
}else{
//非主键,没默认值的,给个数字字串
$v = $this->__columns($val['Type']); //该方法在下面
$insert_str .= $v.$fenge;
}
}
$insert_str = trim($insert_str,$fenge);
return $insert_str;
}
}
造数据,该方法根据自己的需要修改,这里是根据字串长度随机数字当作字段值
//具体字段处理
public static function __columns($type){
if( $type == 'datetime' || $type == 'timestamp' ){ //年月日时分秒格式
$val = date('Y-m-d H:i:s');
}elseif( $type == 'date' ){ //年月日格式
$val = date('Y-m-d');
}elseif( $type == 'time' ){ //时分秒格式
$val = date('H:i:s');
}elseif( $type == 'year' ){ //年
$val = date('Y');
}else{
//其它类型的用数字填充,可根据自己需要的修改
//浮点数类型
if( strpos($type,'float') === 0 ){
$preg = '/\((\d+),?(\d+)\)/';
}else{
$preg = '/\((\d+)\)/';
}
preg_match_all($preg,$type,$match);
//获取字段类型中括号里的长度,浮点数取前面的数字长度
$length = $match[1][0];
if( !$length ){
$val = mt_rand(1,9); //没有长度的,如文本等字段,使用一个长度的数字
}else{
$tmp_str = '123456789';
$num = ceil($length/9);
for($i = 1;$i<$num;$i++){
$tmp_str .= '123456789';
}
$val = substr(str_shuffle($tmp_str),0,$length);
}
}
return $val;
}
生成txt数据文件,并执行导入
/*
* 单个表生成txt并执行导入
* $tableName string 表名
* $num int 每张表插入多少条
* $file_path 生成数据.txt文件的保存路径
*/
public function insert_table($tableName,$num,$file_path){
//error_reporting(E_ALL);
set_time_limit(0);
//根据表明获取字段
$columns = $this->columns($tableName);
//获取该表的自增主键id
$auto_increment_id_arr = $this->auto_increment_id();
//该表的自增id
$auto_increment_id = $auto_increment_id_arr[$tableName];
//有自增主键的插入数据,没有的忽略
if( $auto_increment_id ){
//根据插入的条数生成一条条数据
for($i=0;$i<$num;$i++){
$auto_increment_id+=1;
$insert_str = $this->doColumns($columns,$auto_increment_id);
//将该数据追加写入txt文件
//每条数据之间拼接换行符
file_put_contents($file_path,$insert_str.PHP_EOL,FILE_APPEND);
}
//将生成的txt文件导入数据库
//$result = $this->local_infile($file_path,$tableName);
//导入数据的sql,这里未拼接一些换行忽略等语句
$str = " LOAD DATA LOCAL INFILE '".$file_path."' ignore INTO TABLE ".$tableName;
$result = mysql_query($str);
//释放
mysql_free_result($result);
}
}
导入语句使用的最简方式来保证执行成功,记录下一些写法
//字段分隔符为逗号
//$fenge = "\t";
//$ziduan_fenge = " FIELDS TERMINATED BY '".$fenge."' "; //以什么字符作为分隔符,默认的是 tab键
//字段忽略符号
//$hulue = '\/"';
//$ziduan_hulue = " OPTIONALLY ENCLOSED BY '".$hulue."' "; //字段括起字符
//字段转义符号
//$zhuanyi = '\/"';
//$ziduan_zhuanyi = " ESCAPED BY '".$zhuanyi."' ";
//行分隔符
//$hang = '\n';
//$hang_fenge = " LINES TERMINATED BY '".$hang."' ";
$str = " LOAD DATA LOCAL INFILE '".$file_path."' REPLACE INTO TABLE ".$table_name;
//一个比较完整的导入sql
$sql = $str.$ziduan_fenge.$ziduan_hulue.$ziduan_zhuanyi.$hang_fenge;
补充说明
1.字段分隔符用默认的 \t,用其它的需要凭借字段分隔符语句,拼接后在执行sql时经常报分隔符字段错误
2.文件保存路径,用相对路径就好,使用本地路径测试的话,导入的sql需要加上上面字段转义符号的写法,否则会语法错误,加上转义写法sql在navicat能执行成功,使用mysql_query执行时错误,程序不识别这种写法,所以使用个相对文件路径,导入sql尽量简短来省略麻烦
3.数据txt文件生成后执行sql导入,多张表操作的话记得释放结果集
4.拿100万来测试数据的,单个表容易,一次性取出数据库多个表循环操作的话,后面的表数据没能准确插入,还可以继续优化
5.因为需求所以写了一个demo,列出其中主要代码,mysql没有专门研究,但凡有错漏还望大家指正