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

使用go連接clickhouse方式

 更新時(shí)間:2024年04月12日 09:29:48   作者:Meepoljd  
這篇文章主要介紹了使用go連接clickhouse方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

前言

近段時(shí)間業(yè)務(wù)在一個(gè)局點(diǎn)測(cè)試clickhouse,用java寫(xiě)的代碼在環(huán)境上一直連接不上clickhouse服務(wù),報(bào)錯(cuò)信息也比較奇怪,No client available,研發(fā)查了一段時(shí)間沒(méi)查出來(lái),讓運(yùn)維這邊繼續(xù)查:

運(yùn)維同學(xué)查了各種監(jiān)聽(tīng)配置,防火墻這些,都沒(méi)什么問(wèn)題,但是沒(méi)有明確證據(jù)能夠提供證明通過(guò)http方式能訪問(wèn)到數(shù)據(jù)庫(kù),時(shí)間拖得比較久,項(xiàng)目上就急了,讓盡快找到問(wèn)題,所以就用go寫(xiě)了個(gè)小工具拉到集群上試試看8123這個(gè)端口到底能不能正常提供服務(wù)。

正文

先安裝必要的庫(kù),clickhouse官方提供了2個(gè)版本的庫(kù),v1和v2,v1版本已經(jīng)明確不會(huì)繼續(xù)更新了,所以用新不用舊哈,可以用官方庫(kù)的方式或者用dsn的方式,這個(gè)我下面一起說(shuō),安裝庫(kù)的命令:

go get github.com/ClickHouse/clickhouse-go/v2

構(gòu)造結(jié)構(gòu)體

編寫(xiě)結(jié)構(gòu)體,存放基本信息:

type Clickhouse struct {
	Host       string    // 服務(wù)端主機(jī)
	Port       int       // 端口
	DB         string    // 數(shù)據(jù)庫(kù)
	User       string    // 用戶名
	Password   string    // 密碼
	Connection *sql.DB   // 建立連接后存放連接
	Rows       *sql.Rows // 運(yùn)行sql后的結(jié)果存放
}

Connection主要是用來(lái)建立連接后把相關(guān)信息存放,這樣方便繼續(xù)調(diào)用其他的方法,因?yàn)槲业闹饕康氖菧y(cè)試數(shù)據(jù)庫(kù)能否連通和運(yùn)行Sql,所以這里Rows用來(lái)存放測(cè)試的select語(yǔ)句的結(jié)果。

參數(shù)讀取

這塊沒(méi)什么好說(shuō)的,連接的參數(shù)直接從命令行讀取,用flag包就好:

var (
	host  = flag.String("host", "localhost", "clickhouse host")
	port  = flag.Int("port", 8123, "clickhouse port")
	user  = flag.String("user", "default", "clichouse user")
	pass  = flag.String("password", "", "clickhouse password")
	db    = flag.String("db", "default", "clickhouse database")
	query = flag.String("query", "show tables", "query you will run")
	mode  = flag.String("mode", "driver", "driver or dsn")
)

前面幾個(gè)參數(shù)不用解釋?zhuān)饕?code>query和mode,query是要運(yùn)行的sql語(yǔ)句,我們默認(rèn)就認(rèn)為跑的是select語(yǔ)句,然后是mode,允許選擇模式,用戶可以使用driver或者dsn兩種模式進(jìn)行連接,我寫(xiě)了兩個(gè)不同的方法,其實(shí)也可以在一個(gè)Connect方法里做判斷,看個(gè)人習(xí)慣;

建立連接

接下來(lái)我們建立數(shù)據(jù)庫(kù)連接:

// 
func (c *Clickhouse) Conn() {
	c.Connection = clickhouse.OpenDB(&clickhouse.Options{
		Addr: []string{fmt.Sprintf("%s:%d", c.Host, c.Port)},
		Auth: clickhouse.Auth{
			Database: c.DB,
			Username: c.User,
			Password: c.Password,
		},
		Settings: clickhouse.Settings{
			"max_execution_time": 60,
		},
		DialTimeout: 5 * time.Second,
		Compression: &clickhouse.Compression{
			Method: clickhouse.CompressionBrotli,
			Level:  5,
		},
		// 必須添加協(xié)議方式
		Protocol: clickhouse.HTTP,
	})

}

func (c *Clickhouse) ConnDsn() {
	conn, err := sql.Open("clickhouse", fmt.Sprintf("http://%s:%d/%s?username=%s&password=%s", c.Host, c.Port, c.DB, c.User, c.Password))
	if err != nil {
		log.Printf("Connect to the server failed, %s.\n", err.Error())
		return
	}
	c.Connection = conn
}

參考官網(wǎng)的實(shí)例,實(shí)現(xiàn)兩種連接方式,關(guān)閉方法就直接把sql.DB和sql.Rows都關(guān)閉就可以了:

func (c *Clickhouse) Close() {
	c.Connection.Close()
	c.Rows.Close()
}

發(fā)起查詢(xún)

查詢(xún)使用Query方法進(jìn)行:

func (c *Clickhouse) Select(query string) {
	rows, err := c.Connection.Query(query)
	if err != nil {
		log.Printf("Query select failed, %s.\n", err.Error())
		return
	}
	c.Rows = rows
}

查詢(xún)的結(jié)果我保存到Rows里,方便后面的解析

結(jié)果解析

比較麻煩的就是結(jié)果的解析了,用過(guò)database/sql庫(kù)的哥們都知道,這個(gè)庫(kù)只提供了基礎(chǔ)的一些接口,查詢(xún)出來(lái)一般用Scan去獲取數(shù)據(jù),用法類(lèi)似這樣:

問(wèn)題就在于,Scan要指定和sql查詢(xún)出來(lái)一樣多的變量,對(duì)于我們這個(gè)小工具來(lái)說(shuō),sql是不一定的,所以查詢(xún)出來(lái)的字段數(shù)量肯定yes不定的,如何動(dòng)態(tài)處理這個(gè)問(wèn)題,肯定是不能直接寫(xiě)一個(gè)結(jié)構(gòu)體解決的,先看我的代碼:

func (c *Clickhouse) Show() {
	cols, err := c.Rows.Columns()
	if err != nil {
		log.Printf("Failed to get table columns, %s.\n", err.Error())
		return
	}
	// 一行數(shù)據(jù),使用any是為了避開(kāi)數(shù)據(jù)類(lèi)型的問(wèn)題
	var rows = make([]any, len(cols))
	// 存實(shí)際的值,是byte數(shù)組,長(zhǎng)度以列的數(shù)量為準(zhǔn)
	var values = make([][]byte, len(cols))
	for i := 0; i < len(cols); i++ {
		rows[i] = &values[i]
	}
	// 打印表頭
	fmt.Println(strings.Join(cols, ","))
	for c.Rows.Next() {
		if err = c.Rows.Scan(rows...); err != nil {
			fmt.Println(err)
			return
		}
		var vString []string
		for _, v := range values {
			vString = append(vString, string(v))
		}
		// 逐行打印出來(lái)
		fmt.Println(strings.Join(vString, ","))
	}
}

大概思路是這樣:

  • Scan需要傳入每個(gè)用來(lái)綁定單行數(shù)據(jù)值的變量,所以values是實(shí)際存儲(chǔ)數(shù)據(jù)的byte數(shù)組,然后把數(shù)組的每個(gè)元素的地址再存入到rows數(shù)組中;
  • 現(xiàn)在可以用rows[index]這樣的方式來(lái)訪問(wèn)values中的值了,把rows直接作為入?yún)魅氲絊can,在每次循環(huán)中,把values的值轉(zhuǎn)成逗號(hào)分割的字符串,直接打印

結(jié)果驗(yàn)證

OK,現(xiàn)在邏輯完成了,我們運(yùn)行測(cè)試一下,

go run main.go -host hostname -password paswword -query "select * from clusters" -db system -mode dsn

只查詢(xún)2個(gè)字段,2行數(shù)據(jù):

結(jié)語(yǔ)

完成,然后把工具放到生產(chǎn)環(huán)境一測(cè)試,查詢(xún)都正常,這下開(kāi)發(fā)哥們要繼續(xù)查他的程序問(wèn)題了

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • 用gin開(kāi)發(fā)的golang項(xiàng)目三種開(kāi)發(fā)模式方式

    用gin開(kāi)發(fā)的golang項(xiàng)目三種開(kāi)發(fā)模式方式

    這篇文章主要介紹了用gin開(kāi)發(fā)的golang項(xiàng)目三種開(kāi)發(fā)模式方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-01-01
  • 深入了解Golang中reflect反射的使用

    深入了解Golang中reflect反射的使用

    這篇文章主要介紹了深入了解Golang中reflect反射的使用,Go語(yǔ)言中的反射是一種機(jī)制,可以在運(yùn)行時(shí)動(dòng)態(tài)地獲取類(lèi)型信息和操作對(duì)象,以及調(diào)用對(duì)象的方法和屬性等,需要詳細(xì)了解可以參考下文
    2023-05-05
  • go字符串拼接方式及性能比拼小結(jié)

    go字符串拼接方式及性能比拼小結(jié)

    在golang中字符串的拼接方式有多種,本文將會(huì)介紹比較常用的幾種方式,并且對(duì)各種方式進(jìn)行壓測(cè),具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-01-01
  • Go語(yǔ)言中使用urfave/cli命令行框架

    Go語(yǔ)言中使用urfave/cli命令行框架

    這篇文章介紹了Go語(yǔ)言中使用urfave/cli命令行框架的方法,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-07-07
  • go語(yǔ)言調(diào)用c語(yǔ)言的so動(dòng)態(tài)庫(kù)的實(shí)現(xiàn)

    go語(yǔ)言調(diào)用c語(yǔ)言的so動(dòng)態(tài)庫(kù)的實(shí)現(xiàn)

    在Go語(yǔ)言開(kāi)發(fā)過(guò)程中,有時(shí)需要調(diào)用C或C++編寫(xiě)的so動(dòng)態(tài)庫(kù),本文介紹了如何在Go語(yǔ)言中調(diào)用so庫(kù)的步驟和注意事項(xiàng),包括環(huán)境準(zhǔn)備、編譯生成.so文件、Go文件編寫(xiě)、以及可能遇到的問(wèn)題和解決方法,感興趣的可以了解一下
    2024-10-10
  • Go語(yǔ)言中如何確保Cookie數(shù)據(jù)的安全傳輸

    Go語(yǔ)言中如何確保Cookie數(shù)據(jù)的安全傳輸

    這篇文章主要介紹了Go語(yǔ)言中如何確保Cookie數(shù)據(jù)的安全傳輸,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-03-03
  • Go語(yǔ)言設(shè)置JSON的默認(rèn)值操作

    Go語(yǔ)言設(shè)置JSON的默認(rèn)值操作

    這篇文章主要介紹了Go語(yǔ)言設(shè)置JSON的默認(rèn)值操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-12-12
  • 一文帶你吃透Go語(yǔ)言中的原子操作

    一文帶你吃透Go語(yǔ)言中的原子操作

    原子操作是解決并發(fā)編程中共享數(shù)據(jù)訪問(wèn)問(wèn)題的一種常見(jiàn)機(jī)制,下面就來(lái)和大家深入介紹原子操作的原理、用法以及在解決并發(fā)問(wèn)題中的應(yīng)用,需要的可以參考一下
    2023-06-06
  • Go語(yǔ)言共享內(nèi)存讀寫(xiě)實(shí)例分析

    Go語(yǔ)言共享內(nèi)存讀寫(xiě)實(shí)例分析

    這篇文章主要介紹了Go語(yǔ)言共享內(nèi)存讀寫(xiě)方法,實(shí)例分析了共享內(nèi)存的原理與讀寫(xiě)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-02-02
  • 如何使用Go語(yǔ)言獲取當(dāng)天、昨天、明天、某天0點(diǎn)時(shí)間戳以及格式化時(shí)間

    如何使用Go語(yǔ)言獲取當(dāng)天、昨天、明天、某天0點(diǎn)時(shí)間戳以及格式化時(shí)間

    這篇文章主要給大家介紹了關(guān)于如何使用Go語(yǔ)言獲取當(dāng)天、昨天、明天、某天0點(diǎn)時(shí)間戳以及格式化時(shí)間的相關(guān)資料,格式化時(shí)間戳是將時(shí)間戳轉(zhuǎn)換為特定的日期和時(shí)間格式,文中通過(guò)代碼示例介紹的非常詳細(xì),需要的朋友可以參考下
    2023-10-10

最新評(píng)論