发布网友 发布时间:2022-04-19 15:21
共4个回答
懂视网 时间:2022-05-02 23:20
db, err := sql.Open("mysql", "root:root@/uestcbook")
(1)sql.Open("mysql", "username:pwd@/databasename")
功能:返回一个DB对象,DB对象对于多个goroutines并发使用是安全的,DB对象内部封装了连接池。
实现:open函数并没有创建连接,它只是验证参数是否合法。然后开启一个单独goroutines去监听是否需要建立新的连接,当有请求建立新连接时就创建新连接。
注意:open函数应该被调用一次,通常是没必要close的。
(2)DB.Exec()
功能:执行不返回行(row)的查询,比如INSERT,UPDATE,DELETE
实现:DB交给内部的exec方法负责查询。exec会首先调用DB内部的conn方法从连接池里面获得一个连接。然后检查内部的driver.Conn实现了Execer接口没有,如果实现了该接口,会调用Execer接口的Exec方法执行查询;否则调用Conn接口的Prepare方法负责查询。
(3)DB.Query()
功能:用于检索(retrieval),比如SELECT
实现:DB交给内部的query方法负责查询。query首先调用DB内部的conn方法从连接池里面获得一个连接,然后调用内部的queryConn方法负责查询。
(4)DB.QueryRow()
功能:用于返回单行的查询
实现:转交给DB.Query()查询
(5)db.Prepare()
功能:返回一个Stmt。Stmt对象可以执行Exec,Query,QueryRow等操作。
实现:DB交给内部的prepare方法负责查询。prepare首先调用DB内部的conn方法从连接池里面获得一个连接,然后调用driverConn的prepareLocked方法负责查询。
Stmt相关方法:
st.Exec()
st.Query()
st.QueryRow()
st.Close()
(6)db.Begin()
功能:开启事务,返回Tx对象。调用该方法后,这个TX就和指定的连接绑定在一起了。一旦事务提交或者回滚,该事务绑定的连接就还给DB的连接池。
实现:DB交给内部的begin方法负责处理。begin首先调用DB内部的conn方法从连接池里面获得一个连接,然后调用Conn接口的Begin方法获得一个TX。
TX相关方法:
//内部执行流程和上面那些差不多,只是没有先去获取连接的一步,因为这些操作是和TX关联的,Tx建立的时候就和一个连接绑定了,所以这些操作内部共用一个TX内部的连接。
tx.Exec()
tx.Query()
tx.QueryRow()
tx.Prepare()
tx.Commit()
tx.Rollback()
tx.Stmt()//用于将一个已存在的statement和tx绑定在一起。一个statement可以不和tx关联,比如db.Prepare()返回的statement就没有和TX关联。
几个主要struct的内部主要的数据结构
(1)Exec
result, err := db.Exec( "INSERT INTO users (name, age) VALUES (?, ?)", "gopher", 27, )
(2)Query
rows, err := db.Query("SELECT name FROM users WHERE age = ?", age) if err != nil { log.Fatal(err) } for rows.Next() { var name string if err := rows.Scan(&name); err != nil { log.Fatal(err) } fmt.Printf("%s is %d ", name, age) } if err := rows.Err(); err != nil { log.Fatal(err) }
(3)QueryRow
var age int64 row := db.QueryRow("SELECT age FROM users WHERE name = ?", name) err := row.Scan(&age)
(4)Prepared statements
age := 27 stmt, err := db.Prepare("SELECT name FROM users WHERE age = ?") if err != nil { log.Fatal(err) } rows, err := stmt.Query(age) // process rows
4. 事务
tx, err := db.Begin() if err != nil { log.Fatal(err) }
5. 各种方式效率分析
问题:db.exec和statement.exec和tx.exec的区别?
实例如下:
package main import ( "strconv" "database/sql" _ "github.com/go-sql-driver/mysql" "fmt" "time" "log" ) var db = &sql.DB{} func init(){ db,_ = sql.Open("mysql", "root:root@/book") } func main() { insert() query() update() query() delete() } func update(){ //方式1 update start := time.Now() for i := 1001;i<=1100;i++{ db.Exec("UPdate user set age=? where uid=? ",i,i) } end := time.Now() fmt.Println("方式1 update total time:",end.Sub(start).Seconds()) //方式2 update start = time.Now() for i := 1101;i<=1200;i++{ stm,_ := db.Prepare("UPdate user set age=? where uid=? ") stm.Exec(i,i) stm.Close() } end = time.Now() fmt.Println("方式2 update total time:",end.Sub(start).Seconds()) //方式3 update start = time.Now() stm,_ := db.Prepare("UPdate user set age=? where uid=?") for i := 1201;i<=1300;i++{ stm.Exec(i,i) } stm.Close() end = time.Now() fmt.Println("方式3 update total time:",end.Sub(start).Seconds()) //方式4 update start = time.Now() tx,_ := db.Begin() for i := 1301;i<=1400;i++{ tx.Exec("UPdate user set age=? where uid=?",i,i) } tx.Commit() end = time.Now() fmt.Println("方式4 update total time:",end.Sub(start).Seconds()) //方式5 update start = time.Now() for i := 1401;i<=1500;i++{ tx,_ := db.Begin() tx.Exec("UPdate user set age=? where uid=?",i,i) tx.Commit() } end = time.Now() fmt.Println("方式5 update total time:",end.Sub(start).Seconds()) } func delete(){ //方式1 delete start := time.Now() for i := 1001;i<=1100;i++{ db.Exec("DELETE FROM USER WHERE uid=?",i) } end := time.Now() fmt.Println("方式1 delete total time:",end.Sub(start).Seconds()) //方式2 delete start = time.Now() for i := 1101;i<=1200;i++{ stm,_ := db.Prepare("DELETE FROM USER WHERE uid=?") stm.Exec(i) stm.Close() } end = time.Now() fmt.Println("方式2 delete total time:",end.Sub(start).Seconds()) //方式3 delete start = time.Now() stm,_ := db.Prepare("DELETE FROM USER WHERE uid=?") for i := 1201;i<=1300;i++{ stm.Exec(i) } stm.Close() end = time.Now() fmt.Println("方式3 delete total time:",end.Sub(start).Seconds()) //方式4 delete start = time.Now() tx,_ := db.Begin() for i := 1301;i<=1400;i++{ tx.Exec("DELETE FROM USER WHERE uid=?",i) } tx.Commit() end = time.Now() fmt.Println("方式4 delete total time:",end.Sub(start).Seconds()) //方式5 delete start = time.Now() for i := 1401;i<=1500;i++{ tx,_ := db.Begin() tx.Exec("DELETE FROM USER WHERE uid=?",i) tx.Commit() } end = time.Now() fmt.Println("方式5 delete total time:",end.Sub(start).Seconds()) } func query(){ //方式1 query start := time.Now() rows,_ := db.Query("SELECT uid,username FROM USER") defer rows.Close() for rows.Next(){ var name string var id int if err := rows.Scan(&id,&name); err != nil { log.Fatal(err) } //fmt.Printf("name:%s ,id:is %d ", name, id) } end := time.Now() fmt.Println("方式1 query total time:",end.Sub(start).Seconds()) //方式2 query start = time.Now() stm,_ := db.Prepare("SELECT uid,username FROM USER") defer stm.Close() rows,_ = stm.Query() defer rows.Close() for rows.Next(){ var name string var id int if err := rows.Scan(&id,&name); err != nil { log.Fatal(err) } // fmt.Printf("name:%s ,id:is %d ", name, id) } end = time.Now() fmt.Println("方式2 query total time:",end.Sub(start).Seconds()) //方式3 query start = time.Now() tx,_ := db.Begin() defer tx.Commit() rows,_ = tx.Query("SELECT uid,username FROM USER") defer rows.Close() for rows.Next(){ var name string var id int if err := rows.Scan(&id,&name); err != nil { log.Fatal(err) } //fmt.Printf("name:%s ,id:is %d ", name, id) } end = time.Now() fmt.Println("方式3 query total time:",end.Sub(start).Seconds()) } func insert() { //方式1 insert //strconv,int转string:strconv.Itoa(i) start := time.Now() for i := 1001;i<=1100;i++{ //每次循环内部都会去连接池获取一个新的连接,效率低下 db.Exec("INSERT INTO user(uid,username,age) values(?,?,?)",i,"user"+strconv.Itoa(i),i-1000) } end := time.Now() fmt.Println("方式1 insert total time:",end.Sub(start).Seconds()) //方式2 insert start = time.Now() for i := 1101;i<=1200;i++{ //Prepare函数每次循环内部都会去连接池获取一个新的连接,效率低下 stm,_ := db.Prepare("INSERT INTO user(uid,username,age) values(?,?,?)") stm.Exec(i,"user"+strconv.Itoa(i),i-1000) stm.Close() } end = time.Now() fmt.Println("方式2 insert total time:",end.Sub(start).Seconds()) //方式3 insert start = time.Now() stm,_ := db.Prepare("INSERT INTO user(uid,username,age) values(?,?,?)") for i := 1201;i<=1300;i++{ //Exec内部并没有去获取连接,为什么效率还是低呢? stm.Exec(i,"user"+strconv.Itoa(i),i-1000) } stm.Close() end = time.Now() fmt.Println("方式3 insert total time:",end.Sub(start).Seconds()) //方式4 insert start = time.Now() //Begin函数内部会去获取连接 tx,_ := db.Begin() for i := 1301;i<=1400;i++{ //每次循环用的都是tx内部的连接,没有新建连接,效率高 tx.Exec("INSERT INTO user(uid,username,age) values(?,?,?)",i,"user"+strconv.Itoa(i),i-1000) } //最后释放tx内部的连接 tx.Commit() end = time.Now() fmt.Println("方式4 insert total time:",end.Sub(start).Seconds()) //方式5 insert start = time.Now() for i := 1401;i<=1500;i++{ //Begin函数每次循环内部都会去连接池获取一个新的连接,效率低下 tx,_ := db.Begin() tx.Exec("INSERT INTO user(uid,username,age) values(?,?,?)",i,"user"+strconv.Itoa(i),i-1000) //Commit执行后连接也释放了 tx.Commit() } end = time.Now() fmt.Println("方式5 insert total time:",end.Sub(start).Seconds()) }
之前关于golang操作数据库的博客:
Go实战–go语言操作sqlite数据库(The way to go)
Go实战–golang中使用MongoDB(mgo)
Go实战–golang中使用redis(redigo和go-redis/redis)
导入包
import (
"database/sql"
"fmt"
_ "github.com/go-sql-driver/mysql"
)
连接数据库
db, err := sql.Open("mysql", "root:wangshubo@/test?charset=utf8")
checkErr(err)
插入数据
stmt, err := db.Prepare("INSERT user_info SET id=?,name=?")
checkErr(err)
res, err := stmt.Exec(1, "wangshubo")
checkErr(err)
更新数据
stmt, err = db.Prepare("update user_info set name=? where id=?")
checkErr(err)
res, err = stmt.Exec("astaxieupdate", id)
checkErr(err)
查询
rows, err := db.Query("SELECT * FROM user_info")
checkErr(err)
删除
stmt, err = db.Prepare("delete from user_info where id=?")
checkErr(err)
res, err = stmt.Exec(id)
checkErr(err)
使用go语言数据库
标签:为什么 多个 存在 for int path driver follow 绝对路径
热心网友 时间:2022-05-02 20:28
1、简单易学。
Go语言的作者本身就很懂C语言,所以同样Go语言也会有C语言的基因,所以对于程序员来说,Go语言天生就会让人很熟悉,容易上手。
2、并发性好。
Go语言天生支持并发,可以充分利用多核,轻松地使用并发。 这是Go语言最大的特点。
描述
Go的语法接近C语言,但对于变量的声明有所不同。Go支持垃圾回收功能。Go的并行模型是以东尼·霍尔的通信顺序进程(CSP)为基础,采取类似模型的其他语言包括Occam和Limbo,但它也具有Pi运算的特征,比如通道传输。
在1.8版本中开放插件(Plugin)的支持,这意味着现在能从Go中动态加载部分函数。
与C++相比,Go并不包括如枚举、异常处理、继承、泛型、断言、虚函数等功能,但增加了 切片(Slice) 型、并发、管道、垃圾回收、接口(Interface)等特性的语言级支持。
热心网友 时间:2022-05-02 21:46
为什么要使用Go语言:
从工程的角度上来看,对于大多数后台应用场景,选择Golang是极为明智的选择。 这样可以很轻松的兼顾运行性能、开发效率及维护难度这三大让诸多程序猿欲仙欲死的奇点。
Go有什么优势:
可直接编译成机器码,不依赖其他库,glibc的版本有一定要求,部署就是扔一个文件上去就完成了。
静态类型语言,但是有动态语言的感觉,静态类型的语言就是可以在编译的时候检查出来隐藏的大多数问题,动态语言的感觉就是有很多的包可以使用,写起来的效率很高。
语言层面支持并发,这个就是Go最大的特色,天生的支持并发,我曾经说过一句话,天生的基因和整容是有区别的,大家一样美丽,但是你喜欢整容的还是天生基因的美丽呢?Go就是基因里面支持的并发,可以充分的利用多核,很容易的使用并发。
内置runtime,支持垃圾回收,这属于动态语言的特性之一吧,虽然目前来说GC不算完美,但是足以应付我们所能遇到的大多数情况,特别是Go1.1之后的GC。
简单易学,Go语言的作者都有C的基因,那么Go自然而然就有了C的基因,那么Go关键字是25个,但是表达能力很强大,几乎支持大多数你在其他语言见过的特性:继承、重载、对象等。
丰富的标准库,Go目前已经内置了大量的库,特别是网络库非常强大,我最爱的也是这部分。
内置强大的工具,Go语言里面内置了很多工具链,最好的应该是gofmt工具,自动化格式化代码,能够让团队review变得如此的简单,代码格式一模一样,想不一样都很困难。
跨平台编译,如果你写的Go代码不包含cgo,那么就可以做到window系统编译linux的应用,如何做到的呢?Go引用了plan9的代码,这就是不依赖系统的信息。
内嵌C支持,前面说了作者是C的作者,所以Go里面也可以直接包含c代码,利用现有的丰富的C库。
Go适合用来做什么:
服务器编程,以前你如果使用C或者C++做的那些事情,用Go来做很合适,例如处理日志、数据打包、虚拟机处理、文件系统等。
分布式系统,数据库代理器等。
网络编程,这一块目前应用最广,包括Web应用、API应用、下载应用。
内存数据库,前一段时间google开发的groupcache,couchbase的部分组建。
云平台,目前国外很多云平台在采用Go开发,CloudFoundy的部分组建,前VMare的技术总监自己出来搞的apcera云平台。
热心网友 时间:2022-05-02 23:20
1、可直接编译成机器码,不依赖其他库,glibc的版本有一定要求,部署就是扔一个文件上去就完成了。