数据库做分表之后,没法使用简单的 auto_increment id 来做 primary key,为了维持 id 在多个物理分表上的全局唯一,我们需要一种替代 auto_increment 方式的统一 id 生成方法。 所有的 id 都统一从这里生成,确保不同分表的 id 是全局唯一的。只要保证了不同物理分表的 id 是全局唯一的,我们就能很容易的在不同分表之间迁移数据,而不同担心 id 冲突。
这里我们采用 存储过程来为所有的表统一生成 id ,结构如下:
$sequence_table_fields = array(
'generator' => 'VARCHAR(32) NOT NULL PRIMARY KEY', # id 生成器名称
'id' => 'BIGINT(32) UNSIGNED NOT NULL DEFAULT 0', # 生成器对应的 id
);
$this->createTable('{{sequence}}', $sequence_table_fields, 'ENGINE=InnoDB DEFAULT CHARSET=utf8');
// 为 article_title表 生成 id
$this->insert('{{sequence}}', array('generator' => 'article_title', 'id' => 0));
// 为 article_content表 生成 id
$this->insert('{{sequence}}', array('generator' => 'article_content', 'id' => 0));
// 存储过程,用于生成 id
$this->execute("
CREATE PROCEDURE `p_sequence_id_gen`(generatorName varchar(32))
BEGIN
START TRANSACTION;
UPDATE `sequence` SET `id` = LAST_INSERT_ID(`id` + 1) WHERE `generator` = generatorName;
SELECT LAST_INSERT_ID();
COMMIT;
END
");
存储过程的调用,直接用于生成表id
class StoreProcedureHelper {
private static function call_p_sequence_id_gen($generatorName){
$command = Yii::app()->db->createCommand('call p_sequence_id_gen("'.$generatorName.'")');
return $command->queryScalar();
}
public static function generateArtitleTitleId(){
return self::call_p_sequence_id_gen('article_title');
}
public static function generateArtitleContentId(){
return self::call_p_sequence_id_gen('article_content');
}
}