Kami mempunyai pelayan pusat dan beberapa pelayan serantau seperti d1, d2, d3, d4, d5.
Ada beberapa jadual untuk disalin. Untuk kesederhanaan, mari kita anggap bahawa kita mempunyai jadual yang dipanggil tblFoo yang wujud pada d1, d2, d3, d4, d5 dan c dan mempunyai struktur yang sama pada semua pelayan ini. Peraturannya mudah sahaja:
Matlamatnya adalah untuk memastikan jika perubahan (masukkan, kemas kini, padam) dibuat kepada tblFoo pada pelayan d, ia harus segera ditukar pada pelayan c juga. Ini berfungsi dengan baik untuk operasi sisipan (kerana id, iaitu pkFooID, mempunyai atribut auto_increment mengikut definisi). Ini juga berfungsi untuk mengemas kini dan memadam operasi, tetapi kami mempunyai beberapa kebimbangan dengan operasi ini. Berikut ialah kod (versi ringkas):
namespace App\ORM; use Cake\ORM\Query as ORMQuery; // 其他一些use语句 class Query extends ORMQuery { // 大量的代码... /** * 重写同名方法以处理与c的同步 */ public function execute() { // 一些表需要复制。如果是这样的表,则我们需要执行一些额外的步骤。否则,我们只需调用父方法 if (($this->_repository->getIgnoreType() || (!in_array($this->type(), ['select']))) && $this->isReplicate() && ($this->getConnection()->configName() !== 'c')) { // 获取表 $table = $this->_repository->getTable(); // 复制查询 $replica = clone $this; // 将复制品的连接设置为c,因为我们需要在中央应用地区的更改 $replica->setParentConnectionType('d')->setConnection(ConnectionManager::get('c')); $replica->setIgnoreType($this->_repository->getIgnoreType()); // 首先执行复制品,因为我们需要引用c的ID而不是反过来 $replica->execute(); // 如果是插入操作,我们还需要处理ID if (!empty($this->clause('insert'))) { // 加载主键的名称,以便稍后使用它来查找最大值 $primaryKey = $this->_repository->getPrimaryKey(); // 获取最高的ID值,这将始终是一个正数,因为我们已经在复制品上执行了查询 $firstID = $replica->getConnection() ->execute("SELECT LAST_INSERT_ID() AS {$primaryKey}") ->fetchAll('assoc')[0][$primaryKey]; // 获取列 $columns = $this->clause('values')->getColumns(); // 为了添加主键 $columns[] = $primaryKey; // 然后用这个调整后的数组覆盖插入子句 $this->insert($columns); // 获取值 $values = $this->clause('values')->getValues(); // 以及它们的数量 $count = count($values); // 可能已经将多个行插入到复制品中作为此查询的一部分,我们需要复制所有它们的ID,而不是假设有一个单独的插入记录 for ($index = 0; $index < $count; $index++) { // 将适当的ID值添加到所有要插入的记录中 $values[$index][$primaryKey] = $firstID + $index; } // 用这个调整后的数组覆盖值子句,其中包含PK值 $this->clause('values')->values($values); } } if ($this->isQueryDelete) { $this->setIgnoreType(false); } // 无论如何都执行查询,无论它是复制表还是非复制表 // 如果是复制表,则我们已经在if块中对查询进行了调整 return parent::execute(); } }
Masalah yang perlu dibimbangkan ialah : Jika kami melaksanakan kemas kini atau memadam kenyataan pada d1, yang syaratnya boleh dipenuhi pada pelayan serantau lain (d2, d3, d4, d5), maka kemas kini dan padam kenyataan dilaksanakan dengan betul pada d1 , tetapi Sebaik sahaja pernyataan yang sama dilaksanakan pada d1, kami mungkin mengemas kini/memadam rekod secara tidak sengaja di kawasan lain daripada pelayan c.
Untuk menyelesaikan masalah ini, penyelesaian yang disyorkan adalah untuk mengesahkan pernyataan dan membuang pengecualian jika salah satu daripada syarat berikut tidak dipenuhi:
Jadual tanpa gelagat replikasi akan dilaksanakan seperti biasa Sekatan di atas hanya digunakan pada jadual dengan gelagat replikasi, seperti tblFoo dalam contoh kami.
Bagaimanakah saya boleh mengesahkan kemas kini/memadam pertanyaan dalam laksanakan penulisan semula saya supaya hanya kunci utama atau asing boleh dicari dan hanya operator = atau IN boleh digunakan?
Ini adalah cara saya menyelesaikan masalah saya.
Model dengan kelakuan penyalinan melakukan pengesahan berikut:
Untuk
Query
类,我们有一个isReplicate
方法,触发我们需要的验证,where
kaedah telah ditindih untuk memastikan syarat disahkan dengan betul: