中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

如何使用go連接clickhouse

發布時間:2023-03-17 10:21:05 來源:億速云 閱讀:183 作者:iii 欄目:開發技術

這篇文章主要介紹“如何使用go連接clickhouse”的相關知識,小編通過實際案例向大家展示操作過程,操作方法簡單快捷,實用性強,希望這篇“如何使用go連接clickhouse”文章能幫助大家解決問題。

    近段時間業務在一個局點測試clickhouse,用java寫的代碼在環境上一直連接不上clickhouse服務,報錯信息也比較奇怪,No client available,研發查了一段時間沒查出來,讓運維這邊繼續查:

    如何使用go連接clickhouse

    運維同學查了各種監聽配置,防火墻這些,都沒什么問題,但是沒有明確證據能夠提供證明通過http方式能訪問到數據庫,時間拖得比較久,項目上就急了,讓盡快找到問題,所以就用go寫了個小工具拉到集群上試試看8123這個端口到底能不能正常提供服務。

    正文

    先安裝必要的庫,clickhouse官方提供了2個版本的庫,v1和v2,v1版本已經明確不會繼續更新了,所以用新不用舊哈,可以用官方庫的方式或者用dsn的方式,這個我下面一起說,安裝庫的命令:

    如何使用go連接clickhouse

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

    構造結構體

    編寫結構體,存放基本信息:

    type Clickhouse struct {
    	Host       string    // 服務端主機
    	Port       int       // 端口
    	DB         string    // 數據庫
    	User       string    // 用戶名
    	Password   string    // 密碼
    	Connection *sql.DB   // 建立連接后存放連接
    	Rows       *sql.Rows // 運行sql后的結果存放
    }

    Connection主要是用來建立連接后把相關信息存放,這樣方便繼續調用其他的方法,因為我的主要目的是測試數據庫能否連通和運行Sql,所以這里Rows用來存放測試的select語句的結果。

    參數讀取

    這塊沒什么好說的,連接的參數直接從命令行讀取,用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")
    )

    前面幾個參數不用解釋,主要是querymodequery是要運行的sql語句,我們默認就認為跑的是select語句,然后是mode,允許選擇模式,用戶可以使用driver或者dsn兩種模式進行連接,我寫了兩個不同的方法,其實也可以在一個Connect方法里做判斷,看個人習慣;

    建立連接

    接下來我們建立數據庫連接:

    // 
    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,
    		},
    		// 必須添加協議方式
    		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
    }

    參考官網的實例,實現兩種連接方式,關閉方法就直接把sql.DB和sql.Rows都關閉就可以了:

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

    發起查詢

    查詢使用Query方法進行:

    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
    }

    查詢的結果我保存到Rows里,方便后面的解析

    結果解析

    比較麻煩的就是結果的解析了,用過database/sql庫的哥們都知道,這個庫只提供了基礎的一些接口,查詢出來一般用Scan去獲取數據,用法類似這樣:

    如何使用go連接clickhouse

    問題就在于,Scan要指定和sql查詢出來一樣多的變量,對于我們這個小工具來說,sql是不一定的,所以查詢出來的字段數量肯定yes不定的,如何動態處理這個問題,肯定是不能直接寫一個結構體解決的,先看我的代碼:

    func (c *Clickhouse) Show() {
    	cols, err := c.Rows.Columns()
    	if err != nil {
    		log.Printf("Failed to get table columns, %s.\n", err.Error())
    		return
    	}
    	// 一行數據,使用any是為了避開數據類型的問題
    	var rows = make([]any, len(cols))
    	// 存實際的值,是byte數組,長度以列的數量為準
    	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))
    		}
    		// 逐行打印出來
    		fmt.Println(strings.Join(vString, ","))
    	}
    }

    大概思路是這樣:

    • Scan需要傳入每個用來綁定單行數據值的變量,所以values是實際存儲數據的byte數組,然后把數組的每個元素的地址再存入到rows數組中;

    • 現在可以用rows[index]這樣的方式來訪問values中的值了,把rows直接作為入參傳入到Scan,在每次循環中,把values的值轉成逗號分割的字符串,直接打印

    結果驗證

    OK,現在邏輯完成了,我們運行測試一下,

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

    如何使用go連接clickhouse

    只查詢2個字段,2行數據:

    如何使用go連接clickhouse

    關于“如何使用go連接clickhouse”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識,可以關注億速云行業資訊頻道,小編每天都會為大家更新不同的知識點。

    向AI問一下細節

    免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

    AI

    保康县| 会同县| 太谷县| 鲁山县| 安溪县| 河间市| 沈阳市| 盈江县| 苍山县| 固始县| 南丹县| 大名县| 宁阳县| 岚皋县| 望奎县| 淅川县| 马龙县| 普兰店市| 舒城县| 隆子县| 柳林县| 郁南县| 罗定市| 通化县| 浮山县| 宣武区| 南开区| 昆明市| 当阳市| 玉龙| 天峨县| 多伦县| 襄城县| 陇南市| 嘉祥县| 喀喇沁旗| 龙川县| 丘北县| 安泽县| 洪泽县| 年辖:市辖区|