-1

我正在将一个文本文件解析为一个空的 sqlite 数据库,以便使用 php 处理文件数据。我建立数据库连接:

try {
  $db = new PDO('sqlite:temp.db');
  $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
catch(PDOException $e) {
  echo 'Connection failed: ' . $e->getMessage();
  die($error);
}

由于用户文件数据很大、未排序并且具有多个内部外键依赖项,因此我在外键上使用 DEFERRABLE INITIALLY DEFERRED 将数据作为单个事务插入。只要我的原始输入数据正确,这种方法就可以很好地工作。当发生用户输入错误时,我会得到整个事务的单个通用异常(当然会回滚)。用户错误通常(但并非唯一)表现为未定义的外键引用。

任何人都可以提出一种获取更多信息的方法,例如导致异常的事务中的单个插入语句,或丢失的特定外键,这将有助于跟踪用户输入错误?

由于用户输入数据没有顺序,并且数据结构复杂,因此在提交之前验证它会非常复杂,如果可能的话,我想避免手动编码该方面。

4

2 回答 2

2
// $queries is a query by query array of your insert data

// we'll assume any sub-arrays are initialized appropriately on demand
$primary_keys = array();
$foreign_keys = array();

foreach ($queries as $idx => $data) {
    // build your query appropriately

    // if this is an insert to a table with a primary key
    // that will be referenced by a foreign key:
        $primary_keys[$table_inserting_to][$idx] = $data['primary_key']; // the primary key value we're inserting

    // elseif this is an insert to a table with a foreign key
    // that references a primary key that could fail:
        $foreign_keys[$table_inserting_to][$idx] = $data['foreign_key']; // the foreign key value we're inserting

    // run your query
}

// commit your transaction

// whoops, we failed
// build the associations we need to check
$links = array('table_with_foreign_key' => 'table_with_primary_key', 'table_with_foreign_key_2' => 'table_with_primary_key_2');
$errors = array();
foreach ($links as $foreign => $primary) {
    $failed_keys = array_diff($foreign_keys[$foreign], $primary_keys[$primary]);
    foreach ($failed_keys as $key) {
        $errors[] = "Foreign key check $foreign to $primary, $key could not be found on query idx ".array_search($key, $foreign_keys[$foreign]);
    }
}

...如果您需要考虑数据库中已经存在的主键,您可以随时查询它们以初始化$primary_keys数组。

于 2013-05-16T20:58:09.137 回答
0

此答案基于您使用准备好的语句的假设

如果不是这种情况,您应该进行必要的调整。

A. 收集数组内的参数

$params = array(':name' => 'foo', ':cat' => 'bar', ':val' => 'baz', [...]);

B. 在调用之前execute($params),请执行以下操作,在文件中注册您正在使用的参数:

file_put_contents('file.log', implode(';', $params) . "\r\n"); //or "\n" on linux, "\r" on mac

C、打电话execute($params)

D.如果查询成功,转到A,否则,死。

使用这个简单的算法,您将拥有一个日志文件(名为file.log),其中包含已成功插入的所有参数以及错误的参数(在最后一行)。

可能的改进:

此算法效率不高,因为您多次打开和关闭文件。如果您关心效率,请遵循以下说明:

十、定义$log = array();

A. 收集数组内的参数

$params = array(':name' => 'foo', ':cat' => 'bar', ':val' => 'baz', [...]);

B. 在调用之前execute($params),请执行以下操作来存储您正在使用的参数:

$log[] = implode(';', $params) . "\r\n"; //or "\n" on linux, "\r" on mac

C、打电话execute($params)

D.如果查询成功,转到A,否则,file_put_contents('file.log', implode("\r\n", $log));

最后考虑

将上述建议与错误引发的 PDO 异常结合起来。它的堆栈对于调试目的总是非常有用的。

要使用 pdo 启用异常,请在连接后使用此命令:

$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
于 2013-05-14T14:33:33.360 回答