Go_ORM & MQ(待续)
作者:互联网
(相当于Java的MyBatis)
Go操作MySQL
Go语言内置了 database/sql 包,保证了SQL或类SQL数据库的泛用接口,并不提供具体的数据库驱动。使用database/sql包必须注入至少一个数据库驱动。
下载
下载依赖: go get -u github.com/go-sql-driver/mysql
会保存在$GOPATH/src/
目录下
使用MySQL驱动
函数签名
func Open(drivername,dataSourceName string)(*DB ,error)
DB是一个数据库(操作)句柄,代表一个具有零到多个底层连接到连接池。它可以安全的被多个go协程同时使用。
sql包会自动创建和释放连接;它也会维护一个闲置连接的连接池。如果数据库具有单链接状态概念,该状态只有在事务被观察时才可信。一旦调用了DB.Begin,返的回Tx会绑定到单个连接。当事务Tx到Commit或RollBack后,该事务使用的连接会归还到DB中的闲置连接池。
启用
package main
import{
"database/sql"
_ "github.com/go-sql-driver/mysql"//导入但不直接使用,相当于使用init()方法
}
func main(){
//数据库信息
dataSourceName:="root:123456@tcp(127.0.0.1:3306)/database"//用户名:密码
//连接数据库
db,err:=sql.Open("mysql",dataSourceName)//不会校验用户名密码,只会校验格式。
if err!=nil{//格式不正确报错
fmt.Println("open failed,error:%v",err)
}
err=db.Ping()
if err!=nil{//密码不正确报错
fmt.Println("open failed,error:%v",err)
}
}
如果写在main函数中,当在其他函数写query或者insert的时候,无法使用main中的变量。
所以应该把变量定义在main之外
增删改查
package main
import{
"database/sql"
_ "github.com/go-sql-driver/mysql"//导入但不直接使用,相当于使用init()方法
}
var db *sql.DB
func initDB(err error){
//数据库信息
dataSourceName:="root:123456@tcp(127.0.0.1:3306)/database"//用户名:密码@端口
//连接数据库
db,err=sql.Open("mysql",dataSourceName)//注意没有:冒号
if err!=nil{//格式不正确报错
return
}
err=db.Ping()
if err!=nil{//密码不正确报错
return
}
//设置数据库连接池最大连接数,用完之后新来的会等待
db.SetMaxOpenConns(10)//可以省略不写
return
}
//结构体
type user struct{
ig int
name string
age int
}
func main(){
err:=initDB()
if err!=nil{
fmt.Println("Db init failed,err",err)
}
fmt.Println("链接数据库成功")
//查询单条记录db.QueryRow方法
sqlStr:="select * from user where id=1;"
rowObj:=db.QueryRow(sqlStr)//从连接池拿一个连接出来去数据库查询单挑记录,返回的是Row对象
//动态查询
//sqlStr:="select * from user where id=?;"
//rowObj:=db.QueryRow(sqlStr,1)
var u1 user
rowObj.Scan(&u1.id,&u1.name,&u1.age)//使用完之后会自动关闭连接
fmt.Println("u1:%v",u1)
//查询多条记录db.Query方法
sqlStr2:="select * from user where id>1;"
rows,err:=db.Query(sqlStr2)
if err!=nil{
fmt.Println("error")
}
defer rows.Close()//重要,需要手动关闭
//读取结果
for rows.Next(){
var u user
err:=rows.Scan(&u1.id,&u1.name,&u1.age)
}
//插入、更新、删除数据db.Exec方法
sqlStr3:="insert into user(name,age) values (?,?)"
ret,err:=db.Exec(sqlStr3,"Kramer",24)
if err != nill{
fmt.Println("error")
}
theID,err:=ret.LastInsertId()//新插入数据的id
//n,err:=ret.RowsAffected()//受影响的行数
if err != nill{
fmt.Println("error")
}
fmt.Println("insert success,ID:",theID)
}
MySQL预处理
普通SQL语句执行过程:
1、SQL语句进行占位符替换得到完整SQL语句
2、客户端发送完整SQL语句到MySQL服务端
3、MySQL服务端执行完整SQL语句并返回结果给客户端
预处理执行过程:
1、把SQL语句拆分成两部分,命令部分和数据部分
2、先把命令部分发送给MySQL服务端,MySQL服务端进行SQL预处理
3、把数据部分发送给MySQL服务端,MySQL服务端对SQL语句进行占位符替换
4、MySQL服务端执行完整SQL语句并返回结果给客户端
预处理好处:
优化MySQL服务器重复执行SQL对方法,提升服务器性能,
避免SQL注入问题
适用范围:频繁使用的SQL语句
Go实现MySQL预处理
语法:func (db *DB)Prepare(query string)(*Stmt,error)
Prepare方法先将sql语句发送给MySQL服务端,返回一个准备好的状态用于止呕的查询和命令。返回值可以同时执行多个查询和命令。
func prepareQueryDemo(){
sqlStr;="select * from user where id>?"
stmt,err:=db.Prepare(sqlStr)
if err != nill{
fmt.Println("error")
return
}
defer stmt.Close()//重要
rows,err:=stmt.Query(0)
//增删改用stmt.Exec()
//_,err:=stmt.Exec(xxx,xx,xx...)这行多执行几次完成批量操作
if err != nill{
fmt.Println("error")
return
}
defer rows.Close()//重要,需要手动关闭
//循环读取结果集中的数据
for rows.Next(){
var u user
err:=rows.Scan(&u1.id,&u1.name,&u1.age)
if err != nill{
fmt.Println("error")
return
}
fmt.Println(u)
}
}
MySQL事务
GO实现MySQL事务
依赖于以下的方法来实现
//开启事务
func (db *DB)Begin()(*Tx,err)
//提交事务
func (tx *Tx)Commit()error
//回滚事务
func (tx *Tx)Rollback()error
示例:
func transactionDemo() {
tx, err := db.Begin() // 开启事务
if err != nil {
if tx != nil {
tx.Rollback() // 回滚
}
fmt.Printf("begin trans failed, err:%v\n", err)
return
}
sqlStr1 := "Update user set age=30 where id=?"
ret1, err := tx.Exec(sqlStr1, 2)
if err != nil {
tx.Rollback() // 回滚
fmt.Printf("exec sql1 failed, err:%v\n", err)
return
}
affRow1, err := ret1.RowsAffected()
if err != nil {
tx.Rollback() // 回滚
fmt.Printf("exec ret1.RowsAffected() failed, err:%v\n", err)
return
}
sqlStr2 := "Update user set age=40 where id=?"
ret2, err := tx.Exec(sqlStr2, 3)
if err != nil {
tx.Rollback() // 回滚
fmt.Printf("exec sql2 failed, err:%v\n", err)
return
}
affRow2, err := ret2.RowsAffected()
if err != nil {
tx.Rollback() // 回滚
fmt.Printf("exec ret1.RowsAffected() failed, err:%v\n", err)
return
}
fmt.Println(affRow1, affRow2)
if affRow1 == 1 && affRow2 == 1 {
fmt.Println("事务提交啦...")
tx.Commit() // 提交事务
} else {
tx.Rollback()
fmt.Println("事务回滚啦...")
}
fmt.Println("exec trans success!")
}
sqlx
第三方库,简化操作,提升效率
需要再 import “github.com/jmoiron/sqlx”
注意:结构体字段名需要和数据库字段名对应
//查询单行记录
func queryRowDemo(){
sqlStr:="select id,name,age from user where id =?"
var u user
err:=db.Get(&u,sqlStr,1)//区别在于直接传入变量u
if err!=nil{
fmt.Println("error:"err)
return
}
fmt.Printf("n=%v",u)
}
//查询多行记录
func queryMultiRowDemo(){
sqlStr:="select id,name,age from user where id >?"
var users []user
err:=db.Select(&users,sqlStr,0)
if err!=nil{
fmt.Println("error:"err)
return
}
fmt.Println("users:%v",users)
}
Redis
连接Redis
使用第三方库https://github.com/go-redis/resdis连接Redis数据库并进行操作。
安装命令:go get -u github.com/go-redis/redis
//声明一个全局的redisdb变量
var redisdb *redis.Client
//初始化连接
func initRedis()(err error){
redisdb=redis.NewClient(&redis.Options{
Addr:"localhost:6379",
Password:"",
DB:0,
})
_,err:=redisdb.Ping().Result()
if err!=nil{
return err
}
return nil
}
func main(){
err:=initinitRedis()
if err!=nil{
fmt.Println("connect err:",err)
}
fmt.Println("connect success ")
}
基本使用
NSQ
分布式消息队列,优点:
1、分布式和分散拓扑,没有单点故障,支持容错和高可用性,并提供可靠的信息交付保证
2、支持横向扩展,没有任何集中式代理
3、易于配置和部署,内置了管理界面
适用场景:
异步操作、应用解耦、流量削峰…
安装
使用
(暂时跳过)
标签:待续,nil,err,fmt,db,Println,ORM,error,Go 来源: https://blog.csdn.net/m0_46199937/article/details/120553294