需要针对 PHP 7.0.3 未定义函数 mysqli::set_local_infile_handler() 的解决方法

Need workaround against PHP 7.0.3 undefined function mysqli::set_local_infile_handler()

我在一个项目中工作,需要从远程服务器下载一个大文件,其中包含大约 500 万条记录的管道分隔数据。

下载完成后需要将数据加载到数据库中。目前我一直在使用 MySQL 数据库,所以我没有考虑其他选择。

我使用面向对象 MySQLi 并调用 LOAD DATA LOCAL INFILE 查询。 完成需要一个半小时到两个小时,我需要一种显示进度的方法,我找到的唯一选项是 set_local_infile_handler 方法。似乎此方法的目的是允许程序员在将数据提供给查询之前更改数据的格式,但作为我发现的唯一选择,我想将它用于我的进度目的。

然而我得到的是:

PHP Fatal error: Uncaught Error: Call to undefined method mysqli::set_local_infile_handler() in C:\Repositories\project\tools\loaddata.php:65

我要求:

我尝试了一些想法(只有 10 万条记录):

我整天都在用这个,所以我一定尝试过一些其他的东西,但要么我不记得它们,要么它们暂时无关紧要。 提前致谢。

我没有看到代码中的错误,它可以在没有本地 infile 方法的情况下工作,但这里是:

require_once("connectvars.php");
$filepath = $_SERVER["argv"][1];
$bloqIdx=0;

$conn = mysqli_init();
$conn->real_connect($mysvr,$myusr,$mypwd,$mydb);
// $conn = new mysqli($mysvr,$myusr,$mypwd,$mydb);
if ($conn->connect_error) {
    trigger_error("SQL".$conn->connect_error,E_USER_ERROR);
    die("Connect Error");
}

function countData($stream, &$buffer, $buflen, &$errmsg) {
    global $bloqIdx;
    $len = strlen($buffer);
    if ($bloqIdx%1000==0) echo ".";
    return $len;
}
function getRowsInserted() {
    global $conn;
    $result = $conn->query("show status where Variable_name='innodb_rows_inserted')";
    $rowsInserted=0;
    if ($result && $conn->affected_rows>0 && $row = $result->fetch_assoc()) $rowsInserted=$row["Value"];
    $result->close();
    return $rowsInserted;
}

$conn->query("truncate mytable");

$riStart = getRowsInserted();
$start = time();
$query = "LOAD DATA LOCAL INFILE '$filepath' INTO TABLE mytable FIELDS TERMINATED by '|' LINES TERMINATED BY '\n'";
$conn->set_local_infile_handler("countData");
$conn->query($query);
$conn->set_local_infile_default();
$minutes = abs(time() - $start)/60;
$riEnd = getRowsInserted()-$riStart;
echo "Finished Loading $riEnd rows from $filepath for ".round($minutes,2)." minutes\n";

$conn->close();

通过注释行:

$conn->set_local_infile_handler("countData");

$conn->set_local_infile_default();

代码有效,但没有进度信息。

http://php.net/manual/en/mysqli.set-local-infile-handler.php 有效版本显然是 (PHP 5, PHP 7)

如果您真的需要测试代码,作为参数的文本文件可以是这样的:

1|one|alpha|C|2012-10-21 17:44:18
2|two|beta|C|2013-02-05 12:23:57
3|three|gamma|C|2012-12-10 07:18:09
4|four|delta|X|2012-11-27 11:51:32
5|five|phi|C|2013-01-07 14:03:29

和table脚本:

create table `mytable` (
  `id` INT NOT NULL,
  `num` CHAR(10) NULL,
  `code` CHAR(13) NULL,
  `status` CHAR(1) NULL,
  `registered` DATETIME NULL,
  INDEX `mycode` (`code` ASC, `registered` ASC),
  PRIMARY KEY (`id`))
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8
COLLATE = utf8_bin;

可以将它们分成 2 个不同的进程。

第一个进程 运行 每分钟由一个 cron 作业执行,并查找是否存在某种触发器(如 tmp 文件)。当找到触发器时,它会删除触发器(tmp 文件),下载大文件,将文件重命名为包含要插入的总行数的格式,然后开始将行插入数据库。

第二个进程是gui。它为用户提供了一个创建触发器(tmp 文件)的按钮,然后定期检查下载文件是否存在。一旦第一个进程将下载文件重命名为给定格式,它就可以解析文件名以获得总行数,然后定期查询数据库以确定现有行数并将其作为完成百分比呈现给用户。

现在我将这个案例报告为一个错误。今天加了一条评论。此方法已被删除。

https://bugs.php.net/bug.php?id=77786