欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Mysql遷移到TiDB雙寫數(shù)據(jù)庫(kù)兜底方案詳解

 更新時(shí)間:2023年01月03日 14:41:38   作者:石磊  
這篇文章主要為大家介紹了Mysql遷移到TiDB雙寫數(shù)據(jù)庫(kù)兜底方案詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

正文

TiDB 作為開(kāi)源 NewSQL 數(shù)據(jù)庫(kù)的典型代表之一,同樣支持 SQL,支持事務(wù) ACID 特性。在通訊協(xié)議上,TiDB 選擇與 MySQL 完全兼容,并盡可能兼容 MySQL 的語(yǔ)法。因此,基于 MySQL 數(shù)據(jù)庫(kù)開(kāi)發(fā)的系統(tǒng),大多數(shù)可以平滑遷移至 TiDB,而幾乎不用修改代碼。對(duì)用戶來(lái)說(shuō),遷移成本極低,過(guò)渡自然。

然而,仍有一些 MySQL 的特性和行為,TiDB 目前暫時(shí)不支持或表現(xiàn)與 MySQL 有差異。除此之外,TiDB 提供了一些擴(kuò)展語(yǔ)法和功能,為用戶提供更多的便利。

TiDB 仍處在快速發(fā)展的道路上,對(duì) MySQL 功能和行為的支持方面,正按 路線圖 的規(guī)劃在前行。

兼容策略

先從總體上概括 TiDB 和 MySQL 兼容策略,如下表:

通訊協(xié)議SQL語(yǔ)法功能和行為
完全兼容兼容絕大多數(shù)兼容大多數(shù)

截至 4.0 版本,TiDB 與 MySQL 的區(qū)別總結(jié)如下表:

?MySQLTiDB
隔離級(jí)別支持讀未提交、讀已提交、可重復(fù)讀、串行化,默認(rèn)為可重復(fù)讀樂(lè)觀事務(wù)支持快照隔離,悲觀事務(wù)支持快照隔離和讀已提交
鎖機(jī)制悲觀鎖樂(lè)觀鎖、悲觀鎖
存儲(chǔ)過(guò)程支持不支持
觸發(fā)器支持不支持
事件支持不支持
自定義函數(shù)支持不支持
窗口函數(shù)支持部分支持
JSON支持不支持部分 MySQL 8.0 新增的函數(shù)
外鍵約束支持忽略外鍵約束
字符集?只支持 ascii、latin1、binary、utf8、utf8mb4
增加/刪除主鍵支持通過(guò) alter-primary-key 配置開(kāi)關(guān)提供
CREATE TABLE tblName AS SELECT stmt支持不支持
CREATE TEMPORARY TABLE支持TiDB 忽略 TEMPORARY 關(guān)鍵字,按照普通表創(chuàng)建
DML affected rows支持不支持
AutoRandom 列屬性不支持支持
Sequence 序列生成器不支持支持

三種方案比較

雙寫方案:同時(shí)往mysql和tidb寫入數(shù)據(jù),兩個(gè)數(shù)據(jù)庫(kù)數(shù)據(jù)完全保持同步

•優(yōu)點(diǎn):此方案最安全,作為兜底方案不需擔(dān)心數(shù)據(jù)庫(kù)回滾問(wèn)題,因?yàn)閿?shù)據(jù)完全一致,可以無(wú)縫回滾到mysql

•缺點(diǎn):新方案,調(diào)研方案實(shí)現(xiàn),成本較高

讀寫分離:數(shù)據(jù)寫入mysql,從tidb讀,具體方案是切換到線上以后,保持讀寫分離一周時(shí)間左右,這一周時(shí)間用來(lái)確定tidb數(shù)據(jù)庫(kù)沒(méi)有問(wèn)題,再把寫操作也切換到tidb

•優(yōu)點(diǎn): 切換過(guò)程,mysql和tidb數(shù)據(jù)保持同步,滿足數(shù)據(jù)回滾到mysql方案

•缺點(diǎn):mysql和tidb數(shù)據(jù)庫(kù)同步存在延時(shí),對(duì)部分寫入數(shù)據(jù)要求實(shí)時(shí)查詢的會(huì)導(dǎo)致查詢失敗,同時(shí)一旦整體切換到tidb,無(wú)法回切到mysql

直接切換:直接一步切換到tidb

•優(yōu)點(diǎn):切換過(guò)程最簡(jiǎn)單,成本最低

•缺點(diǎn):此方案沒(méi)有兜底方案,切換到tidb,無(wú)法再回切到mysql或者同步數(shù)據(jù)回mysql風(fēng)險(xiǎn)較大,無(wú)法保證數(shù)據(jù)是否可用

Django雙寫mysql與tidb策略

settings.py中新增配置
# Dev Database settings
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'name',
        'USER': 'root',
        'PASSWORD': '123456',
        'HOST': 'db',
    },
    'replica': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'name',
        'USER': 'root',
        'PASSWORD': '123456',
        'HOST': 'db',
    },
    'bak': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'name',
        'USER': 'root',
        'PASSWORD': '123456',
        'HOST': 'db',
    },
}
# 多重寫入數(shù)據(jù)庫(kù)配置
MULTI_WRITE_DB = "bak"

雙寫中間件 basemodel.py

import copy
import logging
import traceback
from django.db import models, transaction, router
from django.db.models.deletion import Collector
from django.db.models import sql
from django.db.models.sql.constants import CURSOR
from jcdp.settings import MULTI_WRITE_DB, DATABASES
multi_write_db = MULTI_WRITE_DB
# 重寫QuerySet
class BaseQuerySet(models.QuerySet):
    def create(self, **kwargs):
        return super().create(**kwargs)
    def update(self, **kwargs):
        try:
            rows = super().update(**kwargs)
            if multi_write_db in DATABASES:
                self._for_write = True
                query = self.query.chain(sql.UpdateQuery)
                query.add_update_values(kwargs)
                with transaction.mark_for_rollback_on_error(using=multi_write_db):
                    query.get_compiler(multi_write_db).execute_sql(CURSOR)
        except Exception:
            logging.error(traceback.format_exc())
            raise
        return rows
    def delete(self):
        try:
            deleted, _rows_count = super().delete()
            if multi_write_db in DATABASES:
                del_query = self._chain()
                del_query._for_write = True
                del_query.query.select_for_update = False
                del_query.query.select_related = False
                collector = Collector(using=multi_write_db)
                collector.collect(del_query)
                collector.delete()
        except Exception:
            logging.error(traceback.format_exc())
            raise
        return deleted, _rows_count
    def raw(self, raw_query, params=None, translations=None, using=None):
        try:
            qs = super().raw(raw_query, params=params, translations=translations, using=using)
            if multi_write_db in DATABASES:
                super().raw(raw_query, params=params, translations=translations, using=multi_write_db)
        except Exception:
            logging.error(traceback.format_exc())
            raise
        return qs
    def bulk_create(self, objs, batch_size=None, ignore_conflicts=False):
        try:
            for obj in objs:
                obj.save()
        except Exception:
            logging.error(traceback.format_exc())
            raise
        # objs = super().bulk_create(objs, batch_size=batch_size, ignore_conflicts=ignore_conflicts)
        # if multi_write_db in DATABASES:
        #     self._db = multi_write_db
        #     super().bulk_create(objs, batch_size=batch_size, ignore_conflicts=ignore_conflicts)
        return objs
    def bulk_update(self, objs, fields, batch_size=None):
        try:
            super().bulk_update(objs, fields, batch_size=batch_size)
            if multi_write_db in DATABASES:
                self._db = multi_write_db
                super().bulk_update(objs, fields, batch_size=batch_size)
        except Exception:
            logging.error(traceback.format_exc())
            raise
class BaseManager(models.Manager):
    _queryset_class = BaseQuerySet
class BaseModel(models.Model):
    objects = BaseManager()
    class Meta:
        abstract = True
    def delete(
            self, using=None, *args, **kwargs
    ):
        try:
            instance = copy.deepcopy(self)
            super().delete(using=using, *args, **kwargs)
            if multi_write_db in DATABASES:
                super(BaseModel, instance).delete(using=multi_write_db, *args, **kwargs)
        except Exception:
            logging.error(traceback.format_exc())
            raise
    def save_base(self, raw=False, force_insert=False,
                  force_update=False, using=None, update_fields=None):
        try:
            using = using or router.db_for_write(self.__class__, instance=self)
            assert not (force_insert and (force_update or update_fields))
            assert update_fields is None or update_fields
            cls = self.__class__
            # Skip proxies, but keep the origin as the proxy model.
            if cls._meta.proxy:
                cls = cls._meta.concrete_model
            meta = cls._meta
            # A transaction isn't needed if one query is issued.
            if meta.parents:
                context_manager = transaction.atomic(using=using, savepoint=False)
            else:
                context_manager = transaction.mark_for_rollback_on_error(using=using)
            with context_manager:
                parent_inserted = False
                if not raw:
                    parent_inserted = self._save_parents(cls, using, update_fields)
                self._save_table(
                    raw, cls, force_insert or parent_inserted,
                    force_update, using, update_fields,
                )
            if multi_write_db in DATABASES:
                super().save_base(raw=raw,
                                  force_insert=raw,
                                  force_update=force_update,
                                  using=multi_write_db,
                                  update_fields=update_fields)
            # Store the database on which the object was saved
            self._state.db = using
            # Once saved, this is no longer a to-be-added instance.
            self._state.adding = False
        except Exception:
            logging.error(traceback.format_exc())
            raise

上述配置完成以后,在每個(gè)應(yīng)用的models.py中引用新的BaseModel類作為模型基類即可實(shí)現(xiàn)雙寫目的

class DirectoryStructure(BaseModel):
    """
    目錄結(jié)構(gòu)
    """
    view = models.CharField(max_length=128, db_index=True)  # 視圖名稱 eg:部門視圖 項(xiàng)目視圖
    sub_view = models.CharField(max_length=128, unique=True, db_index=True)  # 子視圖名稱
    sub_view_num = models.IntegerField()  # 子視圖順序號(hào)

注:目前該方法尚不支持多對(duì)多模型的雙寫情景,如有業(yè)務(wù)需求,還需重寫ManyToManyField類,方法參考猴子補(bǔ)丁方式

遷移數(shù)據(jù)庫(kù)過(guò)程踩坑記錄

TIDB配置項(xiàng)差異:確認(rèn)數(shù)據(jù)庫(kù)配置:ONLY_FULL_GROUP_BY 禁用 (mysql默認(rèn)禁用)

TIDB不支持事務(wù)savepoint,代碼中需要顯式關(guān)閉savepoint=False

TIDB由于是分布式數(shù)據(jù)庫(kù),對(duì)于自增主鍵字段的自增策略與mysq有差異,若業(yè)務(wù)代碼會(huì)與主鍵id關(guān)聯(lián),需要注意

以上就是Mysql遷移到TiDB雙寫數(shù)據(jù)庫(kù)兜底方案詳解的詳細(xì)內(nèi)容,更多關(guān)于Mysql遷移TiDB雙寫數(shù)據(jù)庫(kù)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Mysql數(shù)據(jù)庫(kù)值的添加、修改、刪除及清空操作實(shí)例

    Mysql數(shù)據(jù)庫(kù)值的添加、修改、刪除及清空操作實(shí)例

    這篇文章主要給大家介紹了關(guān)于Mysql數(shù)據(jù)庫(kù)值的添加、修改、刪除及清空操作的相關(guān)資料,文中通過(guò)示例代碼以及圖文介紹的非常詳細(xì),需要的朋友可以參考下
    2021-06-06
  • MySQL中CONCAT和GROUP_CONCAT方法的區(qū)別詳解

    MySQL中CONCAT和GROUP_CONCAT方法的區(qū)別詳解

    本文主要介紹了MySQL中CONCAT和GROUP_CONCAT方法的區(qū)別詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-01-01
  • Mysql啟動(dòng)報(bào)ERROR:2002的分析與解決

    Mysql啟動(dòng)報(bào)ERROR:2002的分析與解決

    這篇文章主要給大家介紹了關(guān)于Mysql啟動(dòng)時(shí)報(bào)ERROR:2002問(wèn)題的分析與解決方法,文中通過(guò)示例代碼介紹將該問(wèn)題分析的非常詳細(xì),對(duì)同樣遇到這個(gè)問(wèn)題的朋友們具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起看看吧。
    2017-08-08
  • 淺談MySQL的性能優(yōu)化

    淺談MySQL的性能優(yōu)化

    這篇文章主要介紹了淺談MySQL的性能優(yōu)化,MySQL性能優(yōu)化是通過(guò)對(duì)數(shù)據(jù)庫(kù)的配置、查詢優(yōu)化以及索引優(yōu)化等手段提高數(shù)據(jù)庫(kù)的響應(yīng)速度和處理能力,本文從多個(gè)層面對(duì)mysql性能優(yōu)化進(jìn)行了小結(jié),需要的朋友可以參考下
    2023-08-08
  • CentOS 7下mysql 5.7 安裝教程

    CentOS 7下mysql 5.7 安裝教程

    這篇文章主要為大家詳細(xì)介紹了CentOS 7下mysql 5.7 安裝教程,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-08-08
  • mysql 搜尋附近N公里內(nèi)數(shù)據(jù)的簡(jiǎn)單實(shí)例

    mysql 搜尋附近N公里內(nèi)數(shù)據(jù)的簡(jiǎn)單實(shí)例

    下面小編就為大家?guī)?lái)一篇mysql 搜尋附近N公里內(nèi)數(shù)據(jù)的簡(jiǎn)單實(shí)例。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-04-04
  • MYSQL與SQLserver之間存儲(chǔ)過(guò)程的轉(zhuǎn)換方式

    MYSQL與SQLserver之間存儲(chǔ)過(guò)程的轉(zhuǎn)換方式

    這篇文章主要介紹了MYSQL與SQLserver之間存儲(chǔ)過(guò)程的轉(zhuǎn)換方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-11-11
  • MySQL的主鍵命名策略相關(guān)

    MySQL的主鍵命名策略相關(guān)

    這篇文章主要介紹了MySQL的主鍵命名策略的的相關(guān)資料,幫助大家更好的理解和使用MySQL數(shù)據(jù)庫(kù),感興趣的朋友可以了解下
    2021-01-01
  • Linux下卸載MySQL數(shù)據(jù)庫(kù)

    Linux下卸載MySQL數(shù)據(jù)庫(kù)

    如何在Linux平臺(tái)卸載MySQL呢?這篇文章主要介紹了Linux下卸載MySQL數(shù)據(jù)庫(kù)的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-06-06
  • MySQL安裝配置以及安裝失敗解決過(guò)程

    MySQL安裝配置以及安裝失敗解決過(guò)程

    我們?cè)谙螺d完MYSQL時(shí),安裝可能會(huì)遇到或大或小的問(wèn)題,下面這篇文章主要給大家介紹了關(guān)于MySQL安裝配置以及安裝失敗解決的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-04-04

最新評(píng)論