前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >golang源码分析:go-mysql(3)mysql客户端

golang源码分析:go-mysql(3)mysql客户端

作者头像
golangLeetcode
发布2023-09-06 19:21:34
5430
发布2023-09-06 19:21:34
举报
文章被收录于专栏:golang算法架构leetcode技术php

mysql Client进行一次查询需要三个核心操作,获得连接、测试连是否可用、发送请求:

代码语言:javascript
复制
conn, _ := client.Connect("127.0.0.1:3306", "root", "", "test")
conn.Ping()
r, _ := conn.Execute(`insert into table (id, name) values (1, "abc")`)

首先我们看下获取连接的过程:github.com/go-mysql-org/go-mysql@v1.7.0/client/conn.go

代码语言:javascript
复制
func Connect(addr string, user string, password string, dbName string, options ...func(*Conn)) (*Conn, error) {
        dialer := &net.Dialer{}
        return ConnectWithDialer(ctx, "", addr, user, password, dbName, dialer.DialContext, options...)
代码语言:javascript
复制
func ConnectWithDialer(ctx context.Context, network string, addr string, user string, password string, dbName string, dialer Dialer, options ...func(*Conn)) (*Conn, error) {
  c := new(Conn)
  conn, err := dialer(ctx, network, addr)
  if err = c.handshake(); err != nil {
    

握手过程中需要进行身份认证:

代码语言:javascript
复制
  func (c *Conn) handshake() error {
        if err = c.readInitialHandshake(); err != nil {
        if err := c.writeAuthHandshake(); err != nil {
        if err := c.handleAuthResult(); err != nil {

标识连接的过程如下:

代码语言:javascript
复制
type Conn struct {
  *packet.Conn


  user      string
  password  string
  db        string
  tlsConfig *tls.Config
  proto     string


  // server capabilities
  capability uint32
  // client-set capabilities only
  ccaps uint32


  attributes map[string]string


  status uint16


  charset string


  salt           []byte
  authPluginName string


  connectionID uint32
}

认证完成后就可以获得server端分配的本次连接的连接ID:github.com/go-mysql-org/go-mysql@v1.7.0/client/auth.go

代码语言:javascript
复制
func (c *Conn) readInitialHandshake() error {
        data, err := c.ReadPacket()
        return errors.Annotate(c.handleErrorPacket(data), "read initial handshake error")
        c.connectionID = binary.LittleEndian.Uint32(data[pos : pos+4])
        pos += 4

一般通过conn.Ping()命令测试连接的可用性

代码语言:javascript
复制
func (c *Conn) Ping() error {
    if err := c.writeCommand(COM_PING); err != nil {
    if _, err := c.readOK(); err != nil {

可以看到它是一个单独的命令,mysql的命令列表如下:

代码语言:javascript
复制
const (
  COM_SLEEP byte = iota
  COM_QUIT
  COM_INIT_DB
  COM_QUERY
  COM_FIELD_LIST
  COM_CREATE_DB
  COM_DROP_DB
  COM_REFRESH
  COM_SHUTDOWN
  COM_STATISTICS
  COM_PROCESS_INFO
  COM_CONNECT
  COM_PROCESS_KILL
  COM_DEBUG
  COM_PING
  COM_TIME
  COM_DELAYED_INSERT
  COM_CHANGE_USER
  COM_BINLOG_DUMP
  COM_TABLE_DUMP
  COM_CONNECT_OUT
  COM_REGISTER_SLAVE
  COM_STMT_PREPARE
  COM_STMT_EXECUTE
  COM_STMT_SEND_LONG_DATA
  COM_STMT_CLOSE
  COM_STMT_RESET
  COM_SET_OPTION
  COM_STMT_FETCH
  COM_DAEMON
  COM_BINLOG_DUMP_GTID
  COM_RESET_CONNECTION
)

执行请求的场景可以分为两种:不带参数的请求和带参数的请求:github.com/go-mysql-org/go-mysql@v1.7.0/client/conn.go,不带参数的请求直接执行,带参数的需要先预编译,然后执行。

代码语言:javascript
复制
func (c *Conn) Execute(command string, args ...interface{}) (*Result, error) {
        if len(args) == 0 {
          return c.exec(command)
        if s, err := c.Prepare(command); err != nil {
        r, err = s.Execute(args...)

执行的过程就是向server发送COM_QUERY命令

代码语言:javascript
复制
func (c *Conn) exec(query string) (*Result, error) {
        if err := c.writeCommandStr(COM_QUERY, query); err != nil {
        return c.readResult(false)

github.com/go-mysql-org/go-mysql@v1.7.0/client/req.go

代码语言:javascript
复制
func (c *Conn) writeCommandStr(command byte, arg string) error {
  return c.writeCommandBuf(command, utils.StringToByteSlice(arg))
}
代码语言:javascript
复制
func (c *Conn) writeCommandBuf(command byte, arg []byte) error {
        err := c.WritePacket(data.B)

github.com/go-mysql-org/go-mysql@v1.7.0/packet/conn.go

代码语言:javascript
复制
func (c *Conn) WritePacket(data []byte) error {

预编译的请求发送在github.com/go-mysql-org/go-mysql@v1.7.0/client/stmt.go,对应命令:COM_STMT_PREPARE

代码语言:javascript
复制
func (c *Conn) Prepare(query string) (*Stmt, error) {
        if err := c.writeCommandStr(COM_STMT_PREPARE, query); err != nil {
        data, err := c.ReadPacket()
        s := new(Stmt)
代码语言:javascript
复制
func (c *Conn) writeCommandStr(command byte, arg string) error {
    return c.writeCommandBuf(command, utils.StringToByteSlice(arg))
代码语言:javascript
复制
func (s *Stmt) Execute(args ...interface{}) (*Result, error) {
        if err := s.write(args...); err != nil {
        return s.conn.readResult(true)

发送命令的过程如下,它先填充字段类型信息,然后填充字段的值,然后进行发送:

代码语言:javascript
复制
func (s *Stmt) write(args ...interface{}) error {
for i := range args {
  switch v := args[i].(type) {
    case int8:
      paramTypes[i<<1] = MYSQL_TYPE_TINY
      paramValues[i] = []byte{byte(v)}
s.conn.ResetSequence()
return s.conn.WritePacket(data)
}

每次发生之前都会重置序列号。

代码语言:javascript
复制
func (c *Conn) ResetSequence() {
  c.Sequence = 0
}

mysql的类型信息定义如下:

代码语言:javascript
复制

const (
  MYSQL_TYPE_DECIMAL byte = iota
  MYSQL_TYPE_TINY
  MYSQL_TYPE_SHORT
  MYSQL_TYPE_LONG
  MYSQL_TYPE_FLOAT
  MYSQL_TYPE_DOUBLE
  MYSQL_TYPE_NULL
  MYSQL_TYPE_TIMESTAMP
  MYSQL_TYPE_LONGLONG
  MYSQL_TYPE_INT24
  MYSQL_TYPE_DATE
  MYSQL_TYPE_TIME
  MYSQL_TYPE_DATETIME
  MYSQL_TYPE_YEAR
  MYSQL_TYPE_NEWDATE
  MYSQL_TYPE_VARCHAR
  MYSQL_TYPE_BIT

  //mysql 5.6
  MYSQL_TYPE_TIMESTAMP2
  MYSQL_TYPE_DATETIME2
  MYSQL_TYPE_TIME2
)

const (
  MYSQL_TYPE_JSON byte = iota + 0xf5
  MYSQL_TYPE_NEWDECIMAL
  MYSQL_TYPE_ENUM
  MYSQL_TYPE_SET
  MYSQL_TYPE_TINY_BLOB
  MYSQL_TYPE_MEDIUM_BLOB
  MYSQL_TYPE_LONG_BLOB
  MYSQL_TYPE_BLOB
  MYSQL_TYPE_VAR_STRING
  MYSQL_TYPE_STRING
  MYSQL_TYPE_GEOMETRY
)

总结一下,mysql client的实现起来很简单,建立连接,按照mysql协议编码,发送请求到服务端。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2023-04-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 golang算法架构leetcode技术php 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
云数据库 MySQL
腾讯云数据库 MySQL(TencentDB for MySQL)为用户提供安全可靠,性能卓越、易于维护的企业级云数据库服务。其具备6大企业级特性,包括企业级定制内核、企业级高可用、企业级高可靠、企业级安全、企业级扩展以及企业级智能运维。通过使用腾讯云数据库 MySQL,可实现分钟级别的数据库部署、弹性扩展以及全自动化的运维管理,不仅经济实惠,而且稳定可靠,易于运维。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档