Go(10)MysqlおよびRedis操作の概要

MysqlとRedisの操作

MySQLの開発

  • mysqlをインストールし、テストライブラリを作成する
  • テーブルを作成
mysql> CREATE TABLE `user` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `name` varchar(20) DEFAULT '', `age` int(11) DEFAULT '0', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;
mysql> insert into user (name,age)values('jim',18)

SQLクエリ

  • 単一行クエリ:Db.QueryRole
  • 複数行クエリ:Db.Query
import (
   "fmt"
   _"github.com/go-sql-driver/mysql"
   "database/sql"
)

type User struct {
   Id   int64     `db:"id"`
   Name string    `db:"name"`
   Age  int       `db:"age"`
}

func connMysql() {
   dns := "root:123456@tcp(localhost:3306)/test"
   conn,err := sql.Open("mysql",dns)
   if err != nil {
      fmt.Printf("connect mysql err:%v\n",err)
      return
   }

   err = conn.Ping()

   if err != nil {
      fmt.Printf("ping faild,err :%v\n",err)
   }

   fmt.Printf("connect mysql successfully!\n")
   QueryRow(conn)
   Query(conn)

   defer conn.Close()
}

func QueryRow(Db *sql.DB) {
   id := 1
   //单行数据查询
   row := Db.QueryRow("select id,name,age from user where id=?",id)
   var user User
   err := row.Scan(&user.Id,&user.Name,&user.Age)
   if err == sql.ErrNoRows {
      fmt.Printf("not found data by id:%v\n",id)
   }

   if err != nil {
      fmt.Printf("scan faild,err: %v\n",err)
      return
   }
   fmt.Printf("user:%#v\n",user)
}

func Query(Db *sql.DB)  {
   id := 0
   //多行数据查询
   rows,err := Db.Query("select id,name,age from user where id>?",id)
   //一定要关闭结果集
   defer func() {
      if rows != nil {
         rows.Close()
      }
   }()
   //查询异常捕获
   if err == sql.ErrNoRows {
      fmt.Printf("not found data by id:%v\n",id)
   }

   if err != nil {
      fmt.Printf("scan faild,err: %v\n",err)
      return
   }

   //遍历所有数据
   for rows.Next() {
      var user User
      err := rows.Scan(&user.Id,&user.Name,&user.Age)
      if err == sql.ErrNoRows {
         fmt.Printf("not found data by id:%v\n",id)
      }

      if err != nil {
         fmt.Printf("scan faild,err: %v\n",err)
         return
      }
      fmt.Printf("user:%#v\n",user)
   }
}
func main() {
   connMysql()
}

MySQLの挿入更新と削除

  • DB.Exec()を使用
import (
   "fmt"
   _"github.com/go-sql-driver/mysql"
   "database/sql"
)

type User struct {
   Id   int64     `db:"id"`
   Name string    `db:"name"`
   Age  int       `db:"age"`
}

func Insert(DB *sql.DB) {
   username := "alex"
   age := 18
   result,err := DB.Exec("insert into user(name,age) values(?,?)",username,age)

   if err != nil {
      fmt.Printf("sql exec insert faild:err:%v\n",err)
      return
   }

   id,err := result.LastInsertId()
   if err != nil {
      fmt.Printf("last insert id faild,err:%v\n",err)
      return
   }

   affectRows,err := result.RowsAffected()
   if err != nil {
      fmt.Printf("Rows affects faild,err:%v\n",err)
      return
   }
   fmt.Printf("last insert id:%d, affect rows:%d\n",id,affectRows)
}

func Update(DB *sql.DB) {
   username := "bbq"
   age := 12
   result,err := DB.Exec("update user set name=?,age=? where id=?",username,age,3)

   if err != nil {
      fmt.Printf("sql exec update faild:err:%v\n",err)
      return
   }

   affectRows,err := result.RowsAffected()
   if err != nil {
      fmt.Printf("Rows affects faild,err:%v\n",err)
      return
   }
   fmt.Printf("affect rows:%d\n",affectRows)
}

func Delete(DB *sql.DB) {
   id := 5
   result,err := DB.Exec("delete from user where id=?",id)

   if err != nil {
      fmt.Printf("sql exec delete faild:err:%v\n",err)
      return
   }

   affectRows,err := result.RowsAffected()
   if err != nil {
      fmt.Printf("Rows affects faild,err:%v\n",err)
      return
   }
   fmt.Printf("affect rows:%d\n",affectRows)
}

func connMysql() {
   dns := "root:123456@tcp(localhost:3306)/test"
   conn,err := sql.Open("mysql",dns)
   if err != nil {
      fmt.Printf("connect mysql err:%v\n",err)
      return
   }

   err = conn.Ping()

   if err != nil {
      fmt.Printf("ping faild,err :%v\n",err)
   }

   fmt.Printf("connect mysql successfully!\n")
   //QueryRow(conn)
   //Query(conn)
   //Insert(conn)
   //Update(conn)
   Delete(conn)
   defer conn.Close()
}

mysqlの前処理

  • 一般的なSQL処理フロー

    • クライアントがSQLステートメントをステッチする
    • クライアントがsqlステートメントをmysqlサーバーに送信する
    • mysqlサーバーはsqlステートメントを解析して実行し、出力をクライアントに返します。
  • 前処理プロセス

    • SQLをコマンド部分とデータ部分の2つの部分に分割する
    • 最初にコマンド部分をmysqlサーバーに送信し、mysqlはsql前処理を実行します
    • 次に、データ部分をmysqlサーバーに送信し、mysqlプレースホルダーを置き換えます
    • mysqlはsqlステートメントを実行し、結果をクライアントに返します
  • 前処理の利点
    • 同じSQLが繰り返し実行され、パフォーマンスは非常に高くなります
    • SQLインジェクションの問題を回避する

前処理の例

  • クエリ操作
    • Db.Prepare(sql string)(* sql.Stmt、error)
    • Stmt.Query()
func PrepareQuery(DB *sql.DB) {
   //第一部分:发送命令和占位符
   stmt,err := DB.Prepare("select id,name,age from user where id>?")
   if err != nil {
      fmt.Printf("prepare faild,error:%v\n",err)
      return
   }
   //第二部分:发数据,并执行sql
   id := 1
   rows,err := stmt.Query(id)
   //一定要关闭结果集
   defer func() {
      if rows != nil {
         rows.Close()
      }
      if stmt != nil {
         stmt.Close()
      }
   }()
   //查询异常捕获
   if err == sql.ErrNoRows {
      fmt.Printf("not found data by id:%v\n",id)
   }

   if err != nil {
      fmt.Printf("scan faild,err: %v\n",err)
      return
   }

   //遍历所有数据
   for rows.Next() {
      var user User
      err := rows.Scan(&user.Id,&user.Name,&user.Age)
      if err == sql.ErrNoRows {
         fmt.Printf("not found data by id:%v\n",id)
      }

      if err != nil {
         fmt.Printf("scan faild,err: %v\n",err)
         return
      }
      fmt.Printf("user:%#v\n",user)
   }
}
  • 更新操作(挿入、更新、削除)
    • Db.Prepare(sql string)(* sql.Stmt、error)
    • Stmt.Exec()
func PrepareInsert(DB *sql.DB) {
   //第一部分:发送命令和占位符
   stmt,err := DB.Prepare("insert into user (name,age) values (?,?);")
   if err != nil {
      fmt.Printf("prepare faild,error:%v\n",err)
      return
   }
   //第二部分:发数据,并执行sql
   username := "zhangqiqi"
   age := 29
   result,err := stmt.Exec(username,age)

   if err != nil {
      fmt.Printf("sql exec insert faild:err:%v\n",err)
      return
   }

   id,err := result.LastInsertId()
   if err != nil {
      fmt.Printf("last insert id faild,err:%v\n",err)
      return
   }

   affectRows,err := result.RowsAffected()
   if err != nil {
      fmt.Printf("Rows affects faild,err:%v\n",err)
      return
   }
   fmt.Printf("last insert id:%d, affect rows:%d\n",id,affectRows)
}

mysqlトランザクションインスタンス

  • データの整合性を確保
  • mysqlトランザクション操作
    • DB.Begin()はトランザクションを開始します
    • DB.Commit()commitトランザクション
    • DB.Roback()はトランザクションをロールバックします
func Transaction(DB *sql.DB) {
   tx,err := DB.Begin()
   if err != nil {
      fmt.Printf("begin faild,err:%v\n",err)
      return
   }

   _,err = tx.Exec("insert into user (name,age)values (?,?)","jemmy",80)

   if err != nil {
      tx.Rollback()
      return
   }

   _,err = tx.Exec("update user set name=?,age=? where id=6","jemmxiny",60)

   if err != nil {
      tx.Rollback()
      return
   }

   err = tx.Commit()

   if err != nil {
      tx.Rollback()   //数据异常就回滚
      return
   }
}

sqlxライブラリの紹介と使用

  • sqlxの機能:

    • 使いやすさ
    • データベース、mysql、postgresql、oracle、sqliteのサポート
  • sqlxの使用
    • クエリ:sqlx.DB.Getおよびsqlx.DB.Select
    • 更新、挿入、削除:sqlx.DB.Exex()
    • 事务:sqlx.DB.Begin()、sqlx.DB.Commit()、sqlx.DB.Rollback
go get github.com/jmoiron/sqlx

使用例

import (
   "database/sql"
   "fmt"
   "github.com/jmoiron/sqlx"
   _ "github.com/go-sql-driver/mysql"
)

type User struct {
   Id   int64     `db:"id"`
   Name string    `db:"name"`
   Age  int       `db:"age"`
}

func connMysql() {
   dns := "root:123456@tcp(localhost:3306)/test"
   conn,err := sqlx.Connect("mysql",dns)
   if err != nil {
      fmt.Printf("connect mysql err:%v\n",err)
      return
   }
   //超时测试
   err = conn.Ping()

   if err != nil {
      fmt.Printf("ping faild,err :%v\n",err)
   }
   fmt.Printf("connect mysql successfully!\n")
   //关闭连接
   //QueryRow(conn)
   //Query(conn)
   Insert(conn)
   defer conn.Close()

}

func QueryRow(Db *sqlx.DB) {
   id := 100
   //单行数据查询
   var user User
   err := Db.Get(&user,"select id,name,age from user where id=?",id)
   //空行数据
   if err == sql.ErrNoRows {
      fmt.Printf("no record to found\n")
      return
   }
   if err != nil {
      fmt.Printf("get faild,err:%v\n",err)
      return
   }
   fmt.Printf("user:%#v\n",user)
}

func Query(Db *sqlx.DB)  {
   var user []*User
   id := 1
   //多行数据查询
   err := Db.Select(&user,"select id, name, age from user where id>?",id)
   if err == sql.ErrNoRows {
      fmt.Printf("no record found\n")
      return
   }

   if err != nil {
      fmt.Printf("select rows faild,err:%v\n",err)
      return
   }
   //输出查询结果
   fmt.Printf("user:%#v\n",user)
   for _,v := range user {
      fmt.Printf("%v\n",v)
   }
}

func Insert(Db *sqlx.DB) {
   username := "alex"
   age := 18
   result,err := Db.Exec("insert into user(name,age) values(?,?)",username,age)

   if err != nil {
      fmt.Printf("sql exec insert faild:err:%v\n",err)
      return
   }

   id,err := result.LastInsertId()
   if err != nil {
      fmt.Printf("last insert id faild,err:%v\n",err)
      return
   }

   affectRows,err := result.RowsAffected()
   if err != nil {
      fmt.Printf("Rows affects faild,err:%v\n",err)
      return
   }
   fmt.Printf("last insert id:%d, affect rows:%d\n",id,affectRows)
}

func main() {
   connMysql()
}

Redis開発

  • サードパーティライブラリを使用する:github.com/garyburd/redigo/redis

redisの使用

func initRedis() (conn redis.Conn,err error) {
    conn,err = redis.Dial("tcp","127.0.0.1:6379")
   if err != nil {
      fmt.Printf("conn redis error:%v\n",err)
      return
   }
   fmt.Printf("conn redis succ\n")
   return
}

func testSetGet(conn redis.Conn)  {
   key := "abc"
   _,err := conn.Do("set",key,"this is a test!")
   if err != nil {
      fmt.Printf("set value faild,eror:%v\n",err)
      return
   }

   data,err := redis.String(conn.Do("get",key))
   if err != nil {
      fmt.Printf("get faild,err:%v\n",err)
      return
   }

   fmt.Printf("key:%s, value:%v\n",key,data)
}

func main() {
   conn,err := initRedis()
   if err != nil {
      return
   }
   testSetGet(conn)
}

ハッシュテーブル操作

func testSetGet(conn redis.Conn)  {
   key := "abc"
   _,err := conn.Do("hset","books",key,"this is a test!")
   if err != nil {
      fmt.Printf("set value faild,eror:%v\n",err)
      return
   }

   data,err := redis.String(conn.Do("hget","books",key))
   if err != nil {
      fmt.Printf("get faild,err:%v\n",err)
      return
   }

   fmt.Printf("key:%s, value:%v\n",key,data)
}

Redis同時操作

func testMSetGet(conn redis.Conn) {
   key := "abc"
   key1 := "def"
   _,err := conn.Do("mset",key,key1)
   if err != nil {
      fmt.Printf("set value faild,eror:%v\n",err)
      return
   }

   //多值操作返回的数据用strings接收
   data,err := redis.Strings(conn.Do("mget",key,key1))
   if err != nil {
      fmt.Printf("get faild,err:%v\n",err)
      return
   }

   //循环取值
   for _,val := range data {
      fmt.Printf("key:%s, value:%v\n",key,val)
   }
}

キューを設定する

パブリッシュおよびサブスクライブ

func testQuenu(conn redis.Conn) {
   _,err := conn.Do("lpush","book_list","this is a test!","daadada")
   if err != nil {
      fmt.Printf("lpush value faild,eror:%v\n",err)
      return
   }

   data,err := redis.String(conn.Do("rpop","book_list"))
   if err != nil {
      fmt.Printf("get faild,err:%v\n",err)
      return
   }

   fmt.Printf("value:%s\n",data)
}

接続プール

func newPool(serverAddr string,passwd string) (pool *redis.Pool) {
   return &redis.Pool{
      MaxIdle:         16,
      MaxActive:       1024,
      IdleTimeout:     240,
      Dial: func() (redis.Conn,error) {
         conn,err := redis.Dial("tcp",serverAddr)
         if err != nil {
            return nil,err
         }
         if len(passwd) > 0 {
            _,err := conn.Do("auth",passwd)
            if err != nil {
               return nil,err
            }
         }
         return conn,err
      },
      TestOnBorrow: func(c redis.Conn,t time.Time) error {
         if time.Since(t) < time.Minute {
            return nil
         }
         _,err := c.Do("ping")
         return err
      },
   }
}

func testRedisPool() {
   pool := newPool("127.0.0.1:6379","")
   conn := pool.Get()
   conn.Do("set","abcd","23134534665437372132")
   val,err := redis.String(conn.Do("get","abcd"))
   if err != nil {
      fmt.Printf("get faild,err:%v\n",err)
   }
   fmt.Printf("val:%v,err:%v\n",val,err)
   //把连接归还到连接池
   conn.Close()
}

おすすめ

転載: blog.51cto.com/13812615/2486436