在我的应用程序中,我有一个导入功能,允许用户将数据从csv文件导入我的应用程序,并导出现有数据。)
问题是导入的文件可能有很多记录,而在导入方法中我创建了很多相关的对象,因此在某些情况下它会导致内存耗尽错误。
我正在寻找优化代码的方法。我已经在使用$ em-> clear和gc_collect_cycles函数,我知道Doctrine2批处理方法。 可以创建一个后台进程来导入文件(例如运行控制台命令吗?
这种情况的最佳做法是什么? 我知道例如OroCrm Project使用命令作为安装程序,同时向用户显示加载器并且它们的安装运行非常顺利。
期待您的意见。 谢谢。
答案 0 :(得分:0)
您当然可以运行控制台命令。但是,Doctrine 2并不适合批量操作,很快就会耗尽燃气。
我有一个使用PDO的进程,它定期扫描具有110K记录的csv文件,并更新多达五个不同的表。它甚至可以在我每月5美元的共享主机服务器上运行。
制作PDO服务:
# =============================================================
pdo:
class: PDO
arguments:
dsn: '%database_dsn%' # mysql:dbname=appgames
user: '%database_user%'
password: '%database_password%'
calls:
- [setAttribute, [ 3, 2]] # \PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION
- [setAttribute, [19, 2]] # \PDO::ATTR_DEFAULT_FETCH_MODE \PDO::FETCH_ASSOC
- [setAttribute, [20, 0]] # \PDO::ATTR_EMULATE_PREPARES
准备一些陈述:
public function prepareLevelInsert()
{
$key = 'levelInsert';
if (isset($this->prepared[$key])) return $this->prepared[$key];
$sql = <<<EOT
INSERT INTO levels
( id, name, sport, domain, domainSub, status)
VALUES (:key,:name,:sport,:domain,:domainSub, 'Active')
;
EOT;
return $this->prepared[$key] = $this->conn->prepare($sql);
}
然后浏览您的文件
// $conn is the PDO object or a
// DBAL connection object obtained from $entityManager->getConnection();
$conn->beginTransaction();
while($row = fgetcsv($fp))
{
// Pull level data
$level = array('name' => $row['levelName'] ... rest of values ...);
// And insert
$this->prepareLevelInsert()->execute($level);
}
$conn->commit();
有点单调乏味但速度比使用Doctrine 2快。