1

我有一个具有以下属性(列){ PKA,a1,a2...} 的父表 A 和具有以下属性 {FKA,b1,b2...} 的子表 B PKA 是表的主键(自动增量) A 和表 B 没有任何主键,但它有一个引用表 A 的 PKA 列的外键列 FKA(1:n 关系)

添加条目:当我在表 A 中添加条目时...我使用 PDO API lastInsertId() 来插入记录并使用此值在表 B 中填充 FKA。

问题:1. 但是,在删除条目时,我没有找到可以以类似方式使用的 API 'lastDeleteId()'

更大的问题:当我的删除发生在表 A 上时,根据设计,删除命令是: DELETE from table A where a1 = 。此 a1 列是非唯一的,因此 DELETE 命令可以返回需要从表 B 中刷新的多个 PKA 键

注意事项:

  1. 我正在使用 PDO API
  2. MySQL 表(这里正在考虑)是 InnoDB
  3. 我在事务模式下运行(beginTransaction() 和 commit()/rollback() 之间的多个 SQL 调用
  4. 不寻找 CASCADE ON DELETE 选项

感谢您的任何指示。

4

4 回答 4

2

您可以在删除查询之后立即使用此查询,也可以将其用作批量清理方法,该方法将追溯适用于未与依赖父级一起删除的任何子级:

DELETE
    FROM  table_a
    WHERE a1 = ?;
SELECT    id
    FROM  table_b
    WHERE FKA NOT IN(SELECT id FROM table_a);

或者您可以使用相同的 WHERE 子句在删除查询之前运行它:

START TRANSACTION;
    SELECT    id
        FROM  table_b
        WHERE FKA NOT IN(
            SELECT id
                FROM table_a
                WHERE a1 = ?;
        );
    DELETE
        FROM  table_a
        WHERE a1 = ?;
COMMIT;

第二种方法需要包装在事务中,以确保您仅删除在选择时匹配的 id,即使其他线程可能已输入与这些过滤器匹配的新数据。

编辑 - 方法问题

如果您正在使用$pdo->beginTransaction(),然后发出一条SELECT语句,获取 id,在应用程序级别使用它们,然后发出delete语句,这将使事务保持活动状态,并且某些记录可能被锁定在该事务中,特别是如果您FOR UPDATE在初始select声明和/或如果您有高ISOLATION LEVELs。

如果您在应用程序层使用耗时的操作,这将在数据库中长时间保持活动锁,并降低应用程序的并发连接容量。

我擅长避免与数据库服务器进行多次通信会话,只要一个就足够了。这就是为什么我一开始不会使用的原因$pdo->beginTransaction()

我会将“获取要删除的 ID”查询扩展为“获取处理已删除记录所需的所有数据”。SELECT我会在事务中的一个通信会话中将查询发送到服务器,即使在应用程序接收到数据时数据已从存储中删除,语句的结果集也将被发送回应用程序有效载荷。

于 2012-07-12T21:50:10.343 回答
1

您所做的是选择要删除的记录的记录 ID 并将它们放在临时表中。然后你首先从子表中删除,然后是父表。在事务中执行此操作,以便在出错时回滚数据。

于 2012-07-12T22:08:08.600 回答
0

我认为最简单的方法可能是将表 A 的内容复制到临时表中,然后执行删除,然后将临时表的 LEFT OUTER JOIN 到更新的表中,并使用它来查找不再具有的行对方。

另外,如果你没有明确地创建一个主键,InnoDB 不是在后台为你创建一个吗?我认为 InnoDB 存储引擎需要一个。

于 2012-07-12T21:49:51.497 回答
0

仅仅考虑您的数据可能不一致的想法怎么样。也就是说,可能存在对已删除的 pk 的引用。每次使用 fk 时都要检查它。

然后添加一个计划任务来清理记录,方法是使用 select from where fk is not in(select pk)进行检查。

于 2012-07-13T01:14:27.763 回答