Go语言入门(十) Mysql与Redis操作

Mysql与Redis操作

Mysql开发

  • 安装mysql,创建test库
  • 创建表
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:(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:(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拆分成两部分,命令部分和数据部分
    • 首先把命令部分发送给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)
   }
}
  • 更新操作(插入,更新,delete)
    • 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() 提交事务
    • 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,sqlit
  • 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:(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)
}

Hash表操作

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()
}