亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

詳解go如何使用xorm在執(zhí)行前改寫?SQL

 更新時(shí)間:2023年06月08日 10:08:53   作者:LinkinStar  
這篇文章主要為大家介紹了詳解go如何使用xorm在執(zhí)行前改寫SQL的實(shí)現(xiàn)過程詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

前言

有時(shí)候你需要再 SQL 執(zhí)行之前對于 SQL 語句進(jìn)行改寫,有可能是修改表名字段名,有可能只是添加注釋,這些看起來奇怪的操作其實(shí)有時(shí)候是為了幫助在數(shù)據(jù)庫之前的 proxy 來實(shí)現(xiàn)某些功能,比如最常見的分庫分表,讀寫分離,多租戶等等。

使用Hint語法

舉個(gè)具體的例子:

有些數(shù)據(jù)庫中間件支持在 SQL 語句之前添加注釋來實(shí)現(xiàn)讀寫分離

如何在讀寫模式為可讀可寫(自動讀寫分離)的集群地址中使用Hint語法。

使用限制

僅讀寫模式為可讀可寫(自動讀寫分離)的集群地址支持Hint語法,只讀模式下的集群地址和主地址均不支持Hint語法。關(guān)于集群地址的讀寫模式信息,請參見集群地址的讀寫模式。

注意事項(xiàng)

Hint的路由優(yōu)化級別最高,不受一致性級別和事務(wù)拆分的約束,使用前請進(jìn)行評估。

使用方法

支持在SQL語句前加上/*FORCE_MASTER*//*FORCE_SLAVE*/強(qiáng)制指定這條SQL的路由方向。

例如select * from test默認(rèn)會路由到只讀節(jié)點(diǎn),改為/*FORCE_MASTER*/ select * from test就會路由到主節(jié)點(diǎn)。

支持在SQL語句前加上/*force_node='<節(jié)點(diǎn)ID>'*/強(qiáng)制指定在某節(jié)點(diǎn)執(zhí)行某查詢命令。

例如/*force_node='pi-bpxxxxxxxx'*/ show processlist,該show processlist命令只在pi-bpxxxxxxxx節(jié)點(diǎn)執(zhí)行。如果該節(jié)點(diǎn)發(fā)生故障,則返回報(bào)錯(cuò)force hint server node is not found, please check.。

支持在SQL語句前加上/*force_proxy_internal*/set force_node = '<節(jié)點(diǎn)ID>'強(qiáng)制指定在某節(jié)點(diǎn)執(zhí)行所有查詢命令。

例如/*force_proxy_internal*/set force_node = 'pi-bpxxxxxxxx',執(zhí)行該命令后,后續(xù)所有查詢命令只發(fā)往pi-bpxxxxxxxx節(jié)點(diǎn),如果該節(jié)點(diǎn)發(fā)生故障,則返回報(bào)錯(cuò)set force node 'rr-bpxxxxx' is not found, please check.。

說明

  • 若您需要通過MySQL官方命令行執(zhí)行上述Hint語句,請?jiān)诿钚兄屑由?c參數(shù),否則該Hint會被MySQL官方命令行過濾導(dǎo)致Hint失效,具體請參見MySQL官方命令行。
  • 通常不建議使用/*force_proxy_internal*/語法,會導(dǎo)致后續(xù)所有查詢請求都發(fā)往該節(jié)點(diǎn),讀寫分離失效。
  • Hint語句里不要有改變環(huán)境變量的語句,例如/*FORCE_SLAVE*/ set names utf8; 等,這類語句可能導(dǎo)致后續(xù)的業(yè)務(wù)出錯(cuò)。

支持在SQL語句前加上/*FORCE_MASTER*//*FORCE_SLAVE*/強(qiáng)制指定這條SQL的路由方向

所以當(dāng)我們使用 orm 庫的時(shí)候,就需要有一個(gè)類似鉤子的東西,能在執(zhí)行之前想辦法將 sql 改寫為所需要的樣子,這就是今天的需求。

嘗試過程

如果你只想知道如何使用,可跳過本段,直接去看最后的實(shí)現(xiàn)部分

一開始我做了各種嘗試,由于 xorm 本身其實(shí)并沒有相關(guān)文檔說明,尋找并嘗試了半天,雖然最后實(shí)現(xiàn)了,但是路徑比較曲折。

嘗試 1 ContextHook

最開始我想到的就是肯定是 Hook,不錯(cuò),如我所料,確實(shí)有 Hook,并且里面有執(zhí)行的 SQL,我非常高興,然后直接開干。

// Hook represents a hook behaviour
type Hook interface {
    BeforeProcess(c *ContextHook) (context.Context, error)
    AfterProcess(c *ContextHook) error
}
// ContextHook represents a hook context
type ContextHook struct {
    start       time.Time
    Ctx         context.Context
    SQL         string        // log content or SQL
    Args        []interface{} // if it's a SQL, it's the arguments
    Result      sql.Result
    ExecuteTime time.Duration
    Err         error // SQL executed error
}

于是我直接實(shí)現(xiàn)了一個(gè)自定義的 Hook 然后使用 BeforeProcess 方法,在執(zhí)行 SQL 前,替換了 ContextHook 其中的 SQL

代碼非常簡單,我就不展示了,然后調(diào)試了半天,發(fā)現(xiàn)打印的 SQL 已經(jīng)被改寫了,但實(shí)際執(zhí)行卻還是原來的 SQL。

為什么?于是我去翻了源碼,發(fā)現(xiàn),見鬼,這個(gè) ContextHook 里面的 SQL 僅僅是為了日志打印用的。也就是說,這個(gè) Hook 其實(shí)目的很明確,就是為了打印日志和計(jì)算 SQL 執(zhí)行時(shí)間用的。

嘗試 2 Events

在嘗試 Event 之前我其實(shí)找了很多曲線救國的方式,但確實(shí)實(shí)現(xiàn)不了。然后我在文檔里面找到了 Events。
比如:BeforeUpdate() BeforeDelete() 等等。問題是,Event 無法獲取到需要執(zhí)行的 SQL,事件僅能拿到需要執(zhí)行的條件,而還沒有解析成 SQL,所以這個(gè)方案也不行

嘗試 3 Filter

于是我翻遍了源碼,看看源碼之前到底有什么操作能幫助我來完成這件事,然后發(fā)現(xiàn)了 Filter

// Filter is an interface to filter SQL
type Filter interface {
    Do(sql string) string
}

Filter 原本的作用是幫助 dialect 去過濾一些特殊數(shù)據(jù)庫的特殊 SQL 來幫助 xorm 來適配各種類型的數(shù)據(jù)庫。我發(fā)現(xiàn)在 SQL 執(zhí)行之前,只有它能獲取到 SQL 并改寫,并且改寫后的 SQL 能被執(zhí)行。但,你從上面的接口也看到了,F(xiàn)ilter 除了 SQL,其他什么也沒有。于是我其實(shí)返回去嘗試了很多其他的解法,發(fā)現(xiàn)仍然無解,最后去官方倉庫提交了 PR,將 context 信息傳遞了進(jìn)去,至此,就有了后面的實(shí)現(xiàn)。

實(shí)現(xiàn)

首先需要自定義 Dialect 和 Filter,因?yàn)?go 沒有繼承,所以使用組合的方式來實(shí)現(xiàn)多態(tài),將原來的 dialects.Dialect 定義包裝,并重寫 Filters 方法用于獲取到我們自定義的 Filter。

注意,mysql 默認(rèn)是沒有 Filter 的,其他數(shù)據(jù)庫可能存在 Filter,可能需要將原來的拿過來并在末尾 append 一個(gè)自定義的 Filter。替換 SQL 就很簡單了,你只需要按照你的需求,改寫 SQL 并返回就可以了。如果你和我一樣需要額外的信息,可以從 context 中獲取,比如傳遞用戶信息,或者 id,用于分庫分表或?qū)崿F(xiàn)多租戶等。

type MyDialect struct {
    dialects.Dialect
}
func (d *MyDialect) Filters() []dialects.Filter {
    return []dialects.Filter{&amp;MyFilter{}}
}
type MyFilter struct {
}
func (m *MyFilter) Do(ctx context.Context, sql string) string {
    return "/** 獲取信息,改寫sql **/" + sql
}

然后 xorm 只有 NewEngineWithDialectAndDB 方法執(zhí)行自定義 Dialect ,所以用這個(gè)方法創(chuàng)建 Engine。并且使用 OpenDialect 方法將默認(rèn)原先 xorm 的 mysql 對應(yīng)的 Dialect 拿出來封裝成自己的。

driver := "mysql"
    connection := "root:root@tcp(127.0.0.1:3306)/test?charset=utf8mb4"
    dialect, err := dialects.OpenDialect(driver, connection)
    if err != nil {
        panic(err)
    }
    s := &MyDialect{Dialect: dialect}
    dbs, err := core.Open(driver, connection)
    if err != nil {
        panic(err)
    }
    engine, err := xorm.NewEngineWithDialectAndDB(driver, connection, s, dbs)
    if err != nil {
        panic(err)
    }

總結(jié)

其實(shí)總的實(shí)現(xiàn)并不難,但過程還是異常艱辛,不過好在后面的路都很順暢了,有了 SQL 你就可以解析它,比如解析需要操作的表名和操作語句,查詢走 A,插入走 B 等等。最后我碼住一些 Golang 的 MySQL proxy,或許你也需要。PS:目前我沒有使用以下的庫,僅僅是將抽離了下面的幾個(gè)庫里面的協(xié)議部分,偽造了 MySQL 服務(wù)來使用。

以上就是詳解go如何使用xorm在執(zhí)行前改寫 SQL的詳細(xì)內(nèi)容,更多關(guān)于go xorm改寫SQL的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Go實(shí)現(xiàn)分布式系統(tǒng)高可用限流器實(shí)戰(zhàn)

    Go實(shí)現(xiàn)分布式系統(tǒng)高可用限流器實(shí)戰(zhàn)

    這篇文章主要為大家介紹了Go實(shí)現(xiàn)分布式系統(tǒng)高可用限流器實(shí)戰(zhàn),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-06-06
  • 詳解Go語言中io/ioutil工具的使用

    詳解Go語言中io/ioutil工具的使用

    這篇文章主要為大家詳細(xì)介紹了Go語言中io/ioutil工具的使用,從而簡化文件操作。文中是示例代碼講解詳細(xì),感興趣的小伙伴可以了解一下
    2022-05-05
  • Go語言中常見的文件操作分享

    Go語言中常見的文件操作分享

    文件操作應(yīng)該是應(yīng)用程序里非常常見的一種操作,無論是哪種應(yīng)用場景,幾乎都離不開文件的基本操作。Go語言中提供了三個(gè)不同的包去處理文件,下午就來說說它們的具體使用
    2023-01-01
  • Go使用MongoDB的操作指南(增刪改查)

    Go使用MongoDB的操作指南(增刪改查)

    MongoDB 是一種高性能、開源、文檔型的 NoSQL 數(shù)據(jù)庫,廣泛應(yīng)用于 Web 應(yīng)用、大數(shù)據(jù)以及云計(jì)算領(lǐng)域,Go 語言則以其快速、開發(fā)效率高、代碼可維護(hù)性強(qiáng)著稱,本指南將詳細(xì)介紹如何在 Go 語言中使用 MongoDB 進(jìn)行數(shù)據(jù)庫操作,需要的朋友可以參考下
    2024-08-08
  • golang中使用proto3協(xié)議導(dǎo)致的空值字段不顯示的問題處理方案

    golang中使用proto3協(xié)議導(dǎo)致的空值字段不顯示的問題處理方案

    這篇文章主要介紹了golang中使用proto3協(xié)議導(dǎo)致的空值字段不顯示的問題處理方案,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-10-10
  • Golang?json?庫中的RawMessage功能原理

    Golang?json?庫中的RawMessage功能原理

    今天我們來學(xué)習(xí)一個(gè) Golang 官方 json 庫提供了一個(gè)經(jīng)典能力RawMessage,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-05-05
  • 詳解Go語言中獲取文件路徑的不同方法與應(yīng)用場景

    詳解Go語言中獲取文件路徑的不同方法與應(yīng)用場景

    在使用?Go?開發(fā)項(xiàng)目時(shí),估計(jì)有不少人遇到過無法正確處理文件路徑的問題,本文將嘗試從簡單到復(fù)雜,詳細(xì)介紹?Go?中獲取路徑的不同方法及應(yīng)用場景,希望對大家有所幫助
    2024-02-02
  • Go解析不定JSON數(shù)據(jù)的方法詳解

    Go解析不定JSON數(shù)據(jù)的方法詳解

    在開發(fā)中常常會碰到很多JSON類型的數(shù)據(jù)進(jìn)行交互,而其中有很多JSON數(shù)據(jù)你是不能確定它的字段和結(jié)構(gòu)的,而Go語言是一門靜態(tài)強(qiáng)類型的語言,在進(jìn)行JSON解析的時(shí)候必須要確定字段的類型,本文給大家介紹了Go如何解析不定JSON數(shù)據(jù),需要的朋友可以參考下
    2024-03-03
  • go語言制作的zip壓縮程序

    go語言制作的zip壓縮程序

    這篇文章主要介紹了go語言制作的zip壓縮程序,其主體思路是首先創(chuàng)建一個(gè)讀寫緩沖,然后用壓縮器包裝該緩沖,用Walk方法來將所有目錄下的文件寫入zip,有需要的小伙伴參考下。
    2015-03-03
  • 淺析Go語言中的方法集合與選擇receiver類型

    淺析Go語言中的方法集合與選擇receiver類型

    這篇文章主要為大家詳細(xì)介紹了Go語言中的方法集合與選擇receiver類型的相關(guān)知識,文中的示例代碼講解詳細(xì),對我們深入學(xué)習(xí)go語言有一定的幫助,需要的可以參考下
    2023-11-11

最新評論