【Golang】Go sqlx操作mysql教程

sqlx是Go数据库操作包,它在database/sql包的基础上增加了更加高效的数据库操作函数,也就是说使用sqlx操作数据库比使用database/sql更加方便。

1.sqlx关键概念介绍

sqlx定义了下面几个关键类型:

1sqlx.DB - 代表一个数据库 2sqlx.Tx - 代表一个事务 3sqlx.Rows - 代表sql查询结果的多行记录 4sqlx.Row - 代表sql查询结果的一条记录
使用sqlx的关键步骤:
1根据mysql地址和帐号密码,创建sqlx.DB对象 2通过sqlx.DB对象的sql查询函数,操作数据库

2.安装包

1//安装sqlx包 2go get github.com/jmoiron/sqlx 3 4//安装mysql驱动 5go get github.com/go-sql-driver/mysql

3.导入包

1import ( 2 //导入mysql驱动 3 _ "github.com/go-sql-driver/mysql" 4 //导入sqlx包 5 "github.com/jmoiron/sqlx" 6)

3.连接数据库

1//定义数据库对象 2var pool *sqlx.DB 3 4//定义mysql数据源,配置数据库地址,帐号以及密码, dsn格式下面会解释 5dsn := "root:123456@tcp(localhost:3306)/tizi365?charset=utf8&parseTime=True&loc=Local" 6 7//根据数据源dsn和mysql驱动, 创建数据库对象 8pool, err := sqlx.Open("mysql", dsn) 9if err != nil { 10 panic(err) 11}

MYSQL dsn格式:

{username}:{password}@tcp({host}:{port})/{Dbname}?charset=utf8&parseTime=True&loc=Local

  • 参数说明:
1参数 说明 2{username} 数据库帐号 3{password} 数据库密码 4{host} 数据库地址 5{port} 数据库端口 6{Dbname} 数据库名字

说明: charset=utf8 用于设置字符集,parseTime=True表示将数据库时间类型转换成Go时间类型

4.数据库连接池设置

sqlx.DB内置了数据库连接池,在你调用sql查询函数的时候,自动从连接池申请连接,可以通过下面方式设置连接池参数:

1//设置连接池最大连接数 2pool.SetMaxOpenConns(100) 3 4//设置连接池最大空闲连接数 5pool.SetMaxIdleConns(20)

5.sql语句绑定参数

绑定参数指的是:在sql语句中通过占位符(?), 定义一些参数,然后在执行sql语句的时候再把参数传递进去。

说明: sql语句绑定参数,除了方便我们拼接sql语句参数之外,还有一个重要的功能就是参数的安全检查和过滤,避免sql注入攻击。

例子:

1//这里通过占位符(?),定义了两个参数 2sql := "select * from tablename where cat=? and uid=?" 3 4//执行sql,并且传入两个参数, 函数的第二个参数101对应sql语句的第一个问号,第三个参数5对应第二个问号 5db.Queryx(sql, 101, 5) 6提示:sqlx.DB提供的查询函数,都支持参数绑定,教程后续会有相应的例子

6.插入数据

sqlx为我们定义两个函数用于执行插入,更新以及执行DDL语句(创建表,修改表等等):

1Exec 2MustExec

这两个函数的作用是一样的,区别就是处理错误的机制不一样,MustExec遇到错误的时候直接抛出一个panic错误,程序就退出了;Exec是将错误和执行结果一起返回,由我们自己处理错误。

我们先定义一个mysql表结构并创建表:

1//定义表结构 2schema := `CREATE TABLE place ( 3 id int primary key auto_increment, 4 country varchar(50), 5 city varchar(50) NULL default '', 6 telcode int);` 7 8// 调用Exec函数执行sql语句,创建表 9_, err := pool.Exec(schema) 10//错误处理 11if err != nil { 12 panic(err) 13}

插入数据的例子:

1//定义sql语句, 通过占位符 问号( ? ) 定义了三个参数 2countryCitySql := `INSERT INTO place (country, city, telcode) VALUES (?, ?, ?)` 3 4//通过Exec插入数据, 这里传入了三个参数,对应sql语句定义的三个问号所在的位置 5result1,err := db.Exec(countryCitySql, "中国", "香港", 852) 6//错误处理 7if err != nil { 8 fmt.Println("插入失败!") 9} 10//插入成功后,获取insert id 11id, _ := result.LastInsertId()
1//通过MustExec插入数据, 如果sql语句出错,则直接抛出panic错误 2result2 := db.MustExec(countryCitySql, "South Africa", "Johannesburg", 27) 3 4//插入成功后,获取插入id 5id2, _ := result2.LastInsertId()

提示: mysql表如果存在自增id,则可以通过Exec返回的结果对象的LastInsertId,查询新插入数据的ID

7.更新数据

1//定义sql语句,通过问号定义了三个参数 2sql := "update place set telcode=?, city=? where id=?" 3 4//通过Exec更新数据, 这里传入了三个参数,对应sql语句定义的三个问号所在的位置 5result1,err := db.Exec(sql, 100, "香港", 1) 6//错误处理 7if err != nil { 8 fmt.Println("更新失败!") 9} 10 11//查询更新影响行数 12rowsAffected, _ := result1.RowsAffected()

8.查询数据

8.1.通过Get和Select函数查询数据 Get函数主要用于查询一条记录,Select用于查询多条记录。

例子:

1//定义保存查询结果的struct变量 2p := Place{} 3 4// 查询一条记录, 并且往sql语句传入参数 1,替换sql语句中的问号,最后将查询结果保存到struct对象中 5err = pool.Get(&p, "SELECT * FROM place LIMIT ?", 1) 6 7 8var total int 9 10//统计表的总记录数,并将查询结果保存到一个变量中 11err = pool.Get(&total, "SELECT count(*) FROM place") 12 13 14//定义一个保存多条记录的struct数组变量 15pp := []Place{} 16 17// 通过Select查询多条记录,并且将结果保存至pp变量中 18// 这里相当于将一条记录的字段值都映射到struct字段中 19err = pool.Select(&pp, "SELECT * FROM place WHERE telcode > ?", 50) 20 21var names []string 22// 通过Select查询多条记录,并且将结果保存至names变量中 23// 这里仅查询一个字段 24err = pool.Select(&names, "SELECT name FROM place LIMIT 10")

8.2.通过Queryx和QueryRowx查询数据 相对于Get和Select函数,Queryx和QueryRowx函数要繁琐一些。 Queryx可以用于查询多条记录,QueryRowx函数用于查询一条记录。

Queryx例子1

1// 查询所有的数据,这里返回的是sqlx.Rows对象 2rows, err := pool.Queryx("SELECT country, city, telcode FROM place") 3//错误检测 4if err !=nil { 5 panic(err) 6} 7 8// 循环遍历每一行记录,rows.Next()函数用于判断是否还有下一行数据 9for rows.Next() { 10 //这里定义三个变量用于接收每一行数据 11 var country string 12 var city string 13 var telcode int 14 15 //调用Scan函数,将当记录的数据保存到变量中,这里参数的顺序跟上面sql语句中select后面的字段顺序一致。 16 err = rows.Scan(&country, &city, &telcode) 17}

Queryx例子2, 将每一行记录保存到struct/map/数组变量中 Rows对象支持将每一行的数据保存到struct、map或者数组中。

1//定义保存数据的结构体, 默认struct字段名(小写)跟表的字段名一致。 2type Place struct { 3 Country string 4 //因为city字段允许null,所以这里可以使用sql.NullString类型 5 City sql.NullString 6 //如果struct字段名跟表的字段名不一样,可以通过db标签设置数据库字段名 7 TelephoneCode int `db:"telcode"` 8} 9 10//查询数据 11rows, err := pool.Queryx("SELECT * FROM place") 12 13//遍历数据 14for rows.Next() { 15 //下面演示如何将数据保存到struct、map和数组中 16 //定义struct对象 17 var p Place 18 19 //定义map类型 20 m := make(map[string]interface{}) 21 22 //定义slice类型 23 s := make([]interface{}, 0) 24 25 //使用StructScan函数将当前记录的数据保存到struct对象中 26 err = rows.StructScan(&p) 27 //保存到map 28 err = rows.MapScan(&m) 29 //保存到数组 30 err = rows.SliceScan(&s) 31}

QueryRowx例子

1 2QueryRowx操作跟Queryx类似,区别就是返回一行数据 3 4//查询数据 5row, err := pool.QueryRowx("SELECT country, city, telcode FROM place where id = ?", 1) 6 7//定义保存数据的结构体, 默认struct字段名(小写)跟表的字段名一致。 8type Place struct { 9 Country string 10 City sql.NullString 11 Telcode int 12} 13 14var p Place 15 16//使用StructScan函数将当前记录的数据保存到struct对象中 17err = row.StructScan(&p) 18提示: sqlx.Row跟sqlx.Rows对象获取数据的方式一样,支持将数据保存到map,slice,struct中,可以参考上面Queryx的例子。 19 209.删除数据 21//定义sql语句,通过问号定义了一个参数 22sql := "delete from place where id=?" 23 24//通过Exec删除数据, 这里传入了一个参数,对应sql语句定义的问号所在的位置 25result1,err := pool.Exec(sql, 1) 26 27//获取删除影响行数 28rowsAffected, _ := result1.RowsAffected() 29 30//错误处理 31if err != nil { 32 fmt.Println("更新失败!") 33} 3410.事务处理 35sqlx使用mysql事务的格式: 36 37//开始一个事务,返回一个事务对象tx 38tx, err := pool.Beginx() 39 40//使用事务对象tx, 执行事务 41err = tx.Queryx(...) 42err = tx.Exec(...) 43err = tx.Exec(...) 44 45if err != nil { 46 //回滚事务 47 tx.Rollback() 48} 49 50//提交事务 51err = tx.Commit() 52提示:注意上面的事务格式,使用的是事务对象tx执行sql,而不是数据库对象,数据库对象执行sql每次都会申请一个新的数据库连接,会导致事务无效。 53 54mysql事务例子: 55 56//开始一个事务,返回一个事务对象tx 57tx, err := pool.Beginx() 58 59//执行事务 60err1 = tx.Exec("delete from place where id=?", 1) 61err2 = tx.Exec("delete from place where id=?", 2) 62 63if err1 != nil || err2 != nil { 64 //回滚事务 65 tx.Rollback() 66} 67 68//提交事务 69tx.Commit()
点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

2020年前端实用代码段,为你的工作保驾护航

有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )