代码之家  ›  专栏  ›  技术社区  ›  Marcel Jackwerth

MySQL中的作用域/复合代理键

  •  0
  • Marcel Jackwerth  · 技术社区  · 15 年前

    以下是我当前数据库的摘录(为了便于理解,更改了表名):

    Pet(ownerFK, id, name, age)
    Owner(id, name)
    

    哪里 id auto_increment

    我想要代理密钥 Pet.id Pet.ownerFK 或者换句话说,有一个复合键 [ownerFk, id]

    INSERT Pet(1, ?, "Garfield", 8);
    INSERT Pet(1, ?, "Pluto", 12);
    INSERT Pet(2, ?, "Mortimer", 1);
    
    SELECT * FROM Pet;
      RESULT:
       Pet(1, 1, "Garfield", 8)
       Pet(1, 2, "Pluto", 12)
       Pet(2, 1, "Mortimer", 1)
    

    我目前正在使用这个 feature of MyISAM 其中“您可以指定 AUTO_INCREMENT 在多列索引中的次列上。在本例中,生成的 列计算如下: MAX(auto_increment_column) + 1 WHERE prefix=given-prefix . 当您要将数据放入有序的组中时,这非常有用。”

    有没有什么办法可以达到这种效果 InnoDB ?

    我发现了一些关于这个问题的帖子,其中许多人建议在插入之前写锁表。我对这个不太熟悉,但是对于这一个,表写锁不是有点大修吗?如果可能的话,我宁愿考虑写安全的事务(我以前从来没有这样做过)——有一个 Owner.current_pet_counter 作为辅助字段。

    所以另一个可以接受的解决方案是。。。

     Pet(id, ownerFK, scopedId, name, age), KEY(id), UNIQUE(ownerFK, scopedId)
     Owner(id, name, current_pet_counter)
    
     START TRANSACTION WITH CONSISTENT SNAPSHOT;
     SELECT @new=current_pet_counter FROM Owner WHERE id = :owner_id;
     INSERT Pet(?, :owner_id, @new, "Pluto", 21);
     UPDATE Owners SET current_pet_counter = @new + 1 WHERE id = :owner_id;
     COMMIT;
    

    我还没有在MySQL中使用transactions/TransactionVar,所以我不知道这是否会有严重的问题。 注: 身份证件 曾经给过宠物一次的。这就是为什么我不使用 MAX() 这个解决方案有什么警告吗?

    1 回复  |  直到 15 年前
        1
  •  1
  •   bobince    15 年前

    我不这么认为。如果您真的必须拥有该模式,那么可以使用事务选择MAX(id)WHERE ownerFK,然后插入。

    通常情况下,您希望id本身真正成为一个合适的主键,ownerFK用于分组,如果需要的话,还需要一个单独的秩列,用于按每个所有者的特定顺序放置宠物,以及一个唯一的索引(ownerFK,rank)。