Go基础之--操作Mysql(一)
关于标准库database/sql
database/sql是golang的标准库之一,它提供了一系列接口方法,用于访问关系数据库。它并不会提供数据库特有的方法,那些特有的方法交给数据库驱动去实现。
database/sql库提供了一些type。这些类型对掌握它的用法非常重要。
DB
数据库对象。 sql.DB类型代表了数据库。和其他语言不一样,它并是数据库连接。golang中的连接来自内部实现的连接池,连接的建立是惰性的,当你需要连接的时候,连接池会自动帮你创建。通常你不需要操作连接池。一切都有go来帮你完成。
Results
结果集。数据库查询的时候,都会有结果集。sql.Rows类型表示查询返回多行数据的结果集。sql.Row则表示单行查询结果的结果集。当然,对于插入更新和删除,返回的结果集类型为sql.Result。
Statements
语句。sql.Stmt类型表示sql查询语句,例如DDL,DML等类似的sql语句。可以把当成prepare语句构造查询,也可以直接使用sql.DB的函数对其操作。
而通常工作中我们可能更多的是用https://github.com/jmoiron/sqlx包来操作数据库
sqlx是基于标准库database/sql的扩展,并且我们可以通过sqlx操作各种类型的数据如
和其他语言不通的是,查询数据库的时候需要创建一个连接,对于go而言则是需要创建一个数据库对象,连接将会在查询需要的时候,由连接池创建并维护,使用sql.Open函数创建数据库对象,第一个参数是数据库驱动名,第二个参数是一个连接字符串
关于数据库的增删查改
增加数据
关于增加数据几个小知识点:
- 关于插入数据的时候占位符是通过问号:?
- 插入数据的后可以通过LastInsertId可以获取插入数据的id
- 通过RowsAffected可以获取受影响的行数
- 执行sql语句是通过exec
一个简单的使用例子:
package main import (
"github.com/jmoiron/sqlx"
_ "github.com/go-sql-driver/mysql"
"fmt"
) func main() {
Db,err:=sqlx.Open("mysql","root:123456@tcp(192.168.14.7:3306)/godb")
if err != nil{
fmt.Println("connect to mysql failed,",err)
return
}
defer Db.Close()
fmt.Println("connect to mysql success")
//执行sql语句,切记这里的占位符是?
result,err := Db.Exec("INSERT INTO user_info(username,sex,email)VALUES (?,?,?)","user01","男","8989@qq.com")
if err != nil{
fmt.Println("insert failed,",err)
}
// 通过LastInsertId可以获取插入数据的id
userId,err:= result.LastInsertId()
// 通过RowsAffected可以获取受影响的行数
rowCount,err:=result.RowsAffected()
fmt.Println("user_id:",userId)
fmt.Println("rowCount:",rowCount) }
通过Exec方法插入数据,返回的结果是一个sql.Result类型
查询数据
下面是一个查询的例子代码:
//执行查询操作
rows,err := Db.Query("SELECT email FROM user_info WHERE user_id>=5")
if err != nil{
fmt.Println("select db failed,err:",err)
return
}
// 这里获取的rows是从数据库查的满足user_id>=5的所有行的email信息,rows.Next(),用于循环获取所有
for rows.Next(){
var s string
err = rows.Scan(&s)
if err != nil{
fmt.Println(err)
return
}
fmt.Println(s)
}
rows.Close()
使用了Query方法执行select查询语句,返回的是一个sql.Rows类型的结果集
迭代后者的Next方法,然后使用Scan方法给变量s赋值,以便取出结果。最后再把结果集关闭(释放连接)。
同样的我们还可以通过Exec方式执行查询语句
但是因为Exec返回的是一个sql.Result类型,从官网这里:
https://golang.google.cn/pkg/database/sql/#type Result
我们可以直接这个接口里只有两个方法:LastInsertId(),RowsAffected()
我们还可以通过Db.Get()方法获取查询的数据,将查询的数据保存到一个结构体中
//Get执行查询操作
type user_info struct {
Username string `db:"username"`
Email string `db:"email"`
}
var userInfo user_info
err = Db.Get(&userInfo,"SELECT username,email FROM user_info WHERE user_id=5")
if err != nil{
fmt.Println(err)
return
}
fmt.Println(userInfo)
这样获取的一个数据,如果我们需要获取多行数据信息还可以通过Db.Select方法获取数据,代码例子为:
var userList []*user_info
err = Db.Select(&userList,"SELECT username,email FROM user_info WHERE user_id>5")
if err != nil{
fmt.Println(err)
return
}
fmt.Println(userList)
for _,v:= range userList{
fmt.Println(v)
}
通过Db.Select方法将查询的多行数据保存在一个切片中,然后就可以通过循环的方式获取每行数据
更新数据
下面是一个更新的例子,这里是通过Exec的方式执行的
//更新数据
results,err := Db.Exec("UPDATE user_info SET username=? where user_id=?","golang",5)
if err != nil{
fmt.Println("update data fail,err:",err)
return
}
fmt.Println(results.RowsAffected())
删除数据
下面是一个删除的例子,同样是通过Exec的方式执行的
//删除数据
results,err := Db.Exec("DELETE from user_info where user_id=?",5)
if err != nil{
fmt.Println("delete data fail,err:",err)
return
}
fmt.Println(results.RowsAffected())
通过上面的简单例子,对golang操作mysql的增删查改,有了一个基本的了解,下面整理一下重点内容
sql.DB
当我们调用sqlx.Open()可以获取一个sql.DB对象,sql.DB是数据库的抽象,切记它不是数据库连接,sqlx.Open()只是验证数据库参数,并没不创建数据库连接。sql.DB提供了和数据库交互的函数,同时也管理维护一个数据库连接池,并且对于多gegoroutines也是安全的
sql.DB表示是数据库抽象,因此你有几个数据库就需要为每一个数据库创建一个sql.DB对象。因为它维护了一个连接池,因此不需要频繁的创建和销毁。
连接池
只用sql.Open函数创建连接池,可是此时只是初始化了连接池,并没有创建任何连接。连接创建都是惰性的,只有当真正使用到连接的时候,连接池才会创建连接。连接池很重要,它直接影响着你的程序行为。
连接池的工作原来却相当简单。当你的函数(例如Exec,Query)调用需要访问底层数据库的时候,函数首先会向连接池请求一个连接。如果连接池有空闲的连接,则返回给函数。否则连接池将会创建一个新的连接给函数。一旦连接给了函数,连接则归属于函数。函数执行完毕后,要不把连接所属权归还给连接池,要么传递给下一个需要连接的(Rows)对象,最后使用完连接的对象也会把连接释放回到连接池。
请求连接的函数有几个,执行完毕处理连接的方式也不同:
- db.Ping() 调用完毕后会马上把连接返回给连接池。
- db.Exec() 调用完毕后会马上把连接返回给连接池,但是它返回的Result对象还保留这连接的引用,当后面的代码需要处理结果集的时候连接将会被重用。
- db.Query() 调用完毕后会将连接传递给sql.Rows类型,当然后者迭代完毕或者显示的调用.Clonse()方法后,连接将会被释放回到连接池。
- db.QueryRow()调用完毕后会将连接传递给sql.Row类型,当.Scan()方法调用之后把连接释放回到连接池。
- db.Begin() 调用完毕后将连接传递给sql.Tx类型对象,当.Commit()或.Rollback()方法调用后释放连接。
每个连接都是惰性的,如何验证sql.Open调用之后,sql.DB对象可用,通过db.Ping()初始化
代码例子:
package main import (
"github.com/jmoiron/sqlx"
_ "github.com/go-sql-driver/mysql"
"fmt"
) func main() {
Db, err := sqlx.Open("mysql", "root:123456@tcp(192.168.50.166:3306)/godb")
if err != nil {
fmt.Println("connect to mysql failed,", err)
return
} defer Db.Close()
fmt.Println("connect to mysql success") err = Db.Ping()
if err != nil{
fmt.Println(err)
return
}
fmt.Println("ping success")
}
需要知道:当调用了ping之后,连接池一定会初始化一个数据连接
连接失败
database/sql 其实帮我们做了很多事情,我们不用见擦汗连接失败的情况,当我们进行数据库操作的时候,如果连接失败,database/sql 会帮我们处理,它会自动连接2次,这个如果查看源码中我们可以看到如下的代码:
// ExecContext executes a query without returning any rows.
// The args are for any placeholder parameters in the query.
func (db *DB) ExecContext(ctx context.Context, query string, args ...interface{}) (Result, error) {
var res Result
var err error
for i := 0; i < maxBadConnRetries; i++ {
res, err = db.exec(ctx, query, args, cachedOrNewConn)
if err != driver.ErrBadConn {
break
}
}
if err == driver.ErrBadConn {
return db.exec(ctx, query, args, alwaysNewConn)
}
return res, err
}
上述代码中变量maxBadConnRetries小时如果连接失败尝试的次数,默认是2
关于连接池配置
db.SetMaxIdleConns(n int) 设置连接池中的保持连接的最大连接数。默认也是0,表示连接池不会保持释放会连接池中的连接的连接状态:即当连接释放回到连接池的时候,连接将会被关闭。这会导致连接再连接池中频繁的关闭和创建。
db.SetMaxOpenConns(n int) 设置打开数据库的最大连接数。包含正在使用的连接和连接池的连接。如果你的函数调用需要申请一个连接,并且连接池已经没有了连接或者连接数达到了最大连接数。此时的函数调用将会被block,直到有可用的连接才会返回。设置这个值可以避免并发太高导致连接mysql出现too many connections的错误。该函数的默认设置是0,表示无限制。
db.SetConnMaxLifetime(d time.Duration) 设置连接可以被使用的最长有效时间,如果过期,连接将被拒绝
Go基础之--操作Mysql(一)的更多相关文章
- Go语言基础之操作MySQL
Go语言操作MySQL MySQL是常用的关系型数据库,本文介绍了Go语言如何操作MySQL数据库. Go操作MySQL 连接 Go语言中的database/sql包提供了保证SQL或类SQL数据库的 ...
- Go基础之--操作Mysql(二)
在上一篇文章中主要整理了Golang连接mysql以及一些基本的操作,并进行了大概介绍,这篇文章对增删查改进行详细的整理 读取数据 在上一篇文章中整理查询数据的时候,使用了Query的方法查询,其实d ...
- Go基础之--操作Mysql(三)
事务是数据库的一个非常重要的特性,尤其对于银行,支付系统,等等.database/sql提供了事务处理的功能.通过Tx对象实现.db.Begin会创建tx对象,后者的Exec和Query执行事务的数据 ...
- python 操作 mysql基础补充
前言 本篇的主要内容为整理mysql的基础内容,分享的同时方便日后查阅,同时结合python的学习整理python操作mysql的方法以及python的ORM. 一.数据库初探 在开始mysql之前先 ...
- Mysql的二进制安装和基础入门操作
前言:Mysql数据库,知识非常的多,要想学精学通这块知识,估计也要花费和学linux一样的精力和时间.小编也是只会些毛皮,给大家分享一下~ 一.MySQL安装 (1)安装方式: 1 .程序包yum安 ...
- Mysql数据库的二进制安装和基础入门操作
前言:Mysql数据库,知识非常的多,要想学精学通这块知识,估计也要花费和学linux一样的精力和时间.小编也是只会些毛皮,给大家分享一下~ 一.MySQL安装 (1)安装方式: 1 .程序包yum安 ...
- php最全基础,数组,函数,超全局变量,时间,回话,文件,php操作mysql
共享一份学习php最全基础语法知识的笔记 原文链接:http://www.cnblogs.com/oscn/p/3607757.html:略有修改 http://www.cnblogs.com/l ...
- python操作mysql基础一
python操作mysql基础一 使用Python操作MySQL的一些基本方法 前奏 为了能操作数据库, 首先我们要有一个数据库, 所以要首先安装Mysql, 然后创建一个测试数据库python_te ...
- MySQL数据库的二进制安装、源码编译和基础入门操作
一.MySQL安装 (1)安装方式: 1 .程序包yum安装 优点:安装快,简单 缺点:定死了各个文件的地方,需要修改里边的相关配置文件,很麻烦 2 .二进制格式的程序包:展开至特定路径,并经过简单配 ...
随机推荐
- 五、Html表单标签
表单,表单控件的主要作用就是收集用户体验,当用户提交表单时,用户输入的内容将作为请求参数提交到远程服务器. 1,form标签 <form>:创建表单,该元素不会生成可视化的界面,但是其他控 ...
- Java数据结构和算法(十四)——堆
在Java数据结构和算法(五)——队列中我们介绍了优先级队列,优先级队列是一种抽象数据类型(ADT),它提供了删除最大(或最小)关键字值的数据项的方法,插入数据项的方法,优先级队列可以用有序数组来实现 ...
- 本篇将记录python开发过程中常见问题
1.Django 外键on_delete的使用 之前用的Django1.8 换成2.0后,出现以下问题: TypeError: init() missing 1 required positional ...
- TOMCAT原理详解及请求过程
Tomcat: Tomcat是一个JSP/Servlet容器.其作为Servlet容器,有三种工作模式:独立的Servlet容器.进程内的Servlet容器和进程外的Servlet容器. Tomcat ...
- 安装php扩展phpredis
下载phpredis-master.tar.gz下载地址:http://pan.baidu.com/s/1i37R8TB 解包tar zxvf phpredis-master.tar.gzcd php ...
- MySQL二进制日志binlog简单使用
MySQL数据库进行了哪些CUD操作,通过binlog二进制文件可以查看.binlog不仅可以记录CUD的操作(select操作不包括在内),还是主从备份的基础.主库的操作记录成binlog文件,定期 ...
- Ubuntu下的Samba服务器配置
一. samba的安装: sudo apt-get insall samba 二. 创建共享目录: mkdir /home/phinecos/share sodu chmod 777 /home/ge ...
- arm-点亮led灯
点亮指路灯:学习四环节:led原理图分析,芯片手册导读,思维导图设计,为什么要使用led:通常led是作为程序调试的重要手段.led原理图:led实质为发光二极管,当其两端电压一定时,即处于导通状态. ...
- Java多线程应用总结
一.基本方法 进程和线程一样,都是实现并发的一个基本单位.线程是比进程更小的执行单位,线程是在进程的基础上进行的进一步划分.所谓多线程,是指一个进程在执行过程中可以产生多个更小的程序单元,这些更小的单 ...
- linux server 常见参数修改
文件描述符(file descriptors) /etc/security/limits.conf 这里是当前用户允许打开的文件描述符限制,可以用ulimit -n查看. 修改成如下配置: * h ...