最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

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

正文

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

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

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

兼容策略

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

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

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

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

三種方案比較

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

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

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

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

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

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

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

•優(yōu)點:切換過程最簡單,成本最低

•缺點:此方案沒有兜底方案,切換到tidb,無法再回切到mysql或者同步數(shù)據(jù)回mysql風(fēng)險較大,無法保證數(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ù)庫配置
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

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

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

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

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

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

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

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

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

相關(guān)文章

  • MySQL的?DDL和DML和DQL的基本語法詳解

    MySQL的?DDL和DML和DQL的基本語法詳解

    SQL語句,即結(jié)構(gòu)化查詢語言(Structured?Query?Language),是一種特殊目的的編程語言,是一種數(shù)據(jù)庫查詢和程序設(shè)計語言,用于存取數(shù)據(jù)以及查詢、更新和管理關(guān)系數(shù)據(jù)庫系統(tǒng),這篇文章主要介紹了MySQL的?DDL和DML和DQL的基本語法,需要的朋友可以參考下
    2022-07-07
  • 新手把mysql裝進(jìn)docker中碰到的各種問題

    新手把mysql裝進(jìn)docker中碰到的各種問題

    這篇文章主要給大家介紹了新手第一次把mysql裝進(jìn)docker中可能碰到的各種問題,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用mysql具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-06-06
  • mysql密碼忘記后如何修改密碼(2022年最新版詳細(xì)教程保姆級)

    mysql密碼忘記后如何修改密碼(2022年最新版詳細(xì)教程保姆級)

    因為長時間不操作mysql而忘記root密碼的朋友估計不在少數(shù),下面這篇文章主要給大家介紹了關(guān)于mysql密碼忘記后如何修改密碼的相關(guān)資料,本教程是2022年最新版詳細(xì)教程保姆級,需要的朋友可以參考下
    2022-04-04
  • mysql 5.5 安裝配置簡單教程

    mysql 5.5 安裝配置簡單教程

    這篇文章主要為大家詳細(xì)介紹了mysql 5.5 安裝配置簡單教程,純文字描述mysql 5.5 安裝配置方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-11-11
  • MySQL備份與恢復(fù)之熱拷貝(4)

    MySQL備份與恢復(fù)之熱拷貝(4)

    熱拷貝支持服務(wù)運行中進(jìn)行備份,速度快,性能好,但它的劣勢在于只能備份MyIsam的表,無法備份InnoDB的表,對熱拷貝感興趣的朋友可以參考一下這篇文章
    2015-08-08
  • mysql優(yōu)化之路----hash索引優(yōu)化

    mysql優(yōu)化之路----hash索引優(yōu)化

    本文是筆者自己做的關(guān)于mysql的優(yōu)化方面的小測試,暫時僅僅做了hash索引優(yōu)化的測試,以后會做更多方面,希望能夠給您帶來收獲,祝您工作愉快。
    2014-08-08
  • Mysql日志文件和日志類型介紹

    Mysql日志文件和日志類型介紹

    這篇文章主要介紹了Mysql日志文件和日志類型介紹,本文講解了日志文件類型、錯誤日志、通用查詢?nèi)罩?、慢速查詢?nèi)罩尽⒍M(jìn)制日志等內(nèi)容,需要的朋友可以參考下
    2014-12-12
  • MySQL JOIN之完全用法

    MySQL JOIN之完全用法

    最近在做mysql的性能憂化,做到多表連接查詢,比較頭疼,看了一些join的資料,終于搞定,這里分享出來!
    2009-12-12
  • 三種常用的MySQL 數(shù)據(jù)類型

    三種常用的MySQL 數(shù)據(jù)類型

    這篇文章主要介紹了MySQL 的數(shù)據(jù)類型的的相關(guān)資料,文中講解非常細(xì)致,幫助大家更好的理解和學(xué)習(xí)MySQL,感興趣的朋友可以了解下
    2020-06-06
  • MySQL函數(shù)之字符串函數(shù)解讀

    MySQL函數(shù)之字符串函數(shù)解讀

    MySQL提供了多種字符串函數(shù),如CONCAT、CONCAT_WS、LENGTH、CHAR_LENGTH、LEFT、RIGHT、REPLACE、SUBSTRING、TRIM、FIND_IN_SET和FORMAT,用于處理數(shù)據(jù)庫中的字符串?dāng)?shù)據(jù)
    2024-12-12

最新評論

汕头市| 东乡县| 安康市| 长乐市| 鹤峰县| 盐源县| 昌吉市| 崇信县| 玉门市| 三都| 天水市| 五峰| 密山市| 明水县| 襄樊市| 乐至县| 邵阳市| 肇州县| 山阳县| 明溪县| 重庆市| 富宁县| 喜德县| 三江| 江津市| 武山县| 浦城县| 精河县| 漳浦县| 吴川市| 开远市| 潮安县| 慈利县| 陈巴尔虎旗| 武穴市| 遂昌县| 开原市| 县级市| 镇平县| 贡觉县| 阳春市|