P129 内容回顾
P130 今日内容
P131 MYsql介绍
P132 使用GO语言链接mysql
需要下载第三方的数据库驱动
提供了所有泛用的接口
可以安全的多个goroutine一起启动
DB是一个数据库句柄,包含底层的多个数据库链接,用到一个数据库连接一个数据库,就比较耗时,可以用连接池提前连接起来。
把包下载下来
open连接数据库,返回一个指针
open不会校验用户名密码是否正确,只会判断上面的dsn连接。ip,端口格式是否正确
ping会去校验dsn是否能连接
校验格式
ping是真正尝试连接数据库
上面导入的包已经是mysql,下面的为何还要指明用mysql连接
导入包的时候,初始化注入一个叫mysql的指针
P133 查询单条记录
需要初始化这样一个操作
这个db一定是一个全局的变量
创建一个表,插入一点数据
建立一个结构体存查询的数据
拿到的结果,需要是指针,防止数据修改scan自带关闭
条件可以改成占位符
必须对rowobj对象调用scan方法,因为该方法会释放数据库连接
设置数据库连接池的最大连接数
连接数满了,就一直在等那里释放
maxidleconns最大空闲连接数
query之后直接scan,避免忘记scan
P134 134查询多条记录
db.Query返回多行结果
多行查询,需要循环取值
现在就查出来两条数据
P135插入更新和删除操作
如果是插入数据的操作,能够拿到插入数据的id
更新数据,可以返回影响的行数
数据库里的数据就变更了
删除数据
P136 MySQL预处理
预处理是先把语句缓存好,后面就直接传条件数据,分命令部分和数据部分。
先把命令部分发给mysql服务端,mysql服务端进行sql预处理。
后续把数据部分发给mysql服务端,mysql服务端对sql语句进行占位符替换。
mysql执行完整的sql语句并将结果返回给客户端。
为什么要预处理?
优化mysql服务器重复执行sql的方法,提升效率。
prepare会把sql语句先发给mysql服务端,返回一个准备好的状态用于之后的查询和命令。
exec执行的时候只要传变量进去就行
P137 MySQI事务操作
一样需要驱动
执行失败就进行回滚
P138 sqlx的使用
导入sqlx
先前都需要一个个scan,现在直接get就可以
现在是获取不到值的
改成大写,sqlx.get看你传的参数不知道是什么参数。要传指针,因为要修改值。
切片需要初始化
必须要传一个pointer进来
sqlx查询单条用get,多条用select
不同的数据库使用的占位符不一样,mysql用?号,oracle用:name
P139 sq注入演示
不要相信用户输入的内容,防止sql注入
or 1=1 相当于永远成立
这样也可以
像这样可以使用预处理,先把设定好的语句加载到mysql,然后对参数进行校验
P140 redis示例
set插入值,get获得值
传进来的配置是一个结构体
这里不能:=,因为你现在用的是全局的
指针,结构体
zset里面带分数
给golang加分数
每一个语言分数也出来了
前三个语言
P141 消息队列介绍
P142 nsq使用
nsq是比较最细的一个go语言开发的,新互联网公司用的比较多
下载下来
lookup相当于hub一样,能够自动发现启动的nsqd节点,可以做到无感知的扩容
nsqdmin是一个管理平台
nsqd启动的时候根据你配置的nslookupd地址,会发送心跳包。
nsqadmin可以看到有多少个节点在工作。
consumer去消费这些任务
一个topic可以有多个channel的通道,每个channel都会收到topic所有消息的副本。
消息默认不持久化,可以配置持久化,持久化后,采用的方式是内存+硬盘的模式。
保证每条消息至少传递一次,消息不保证有序。
先开启一个nslookupd
启动nsqd
注册进去
nsqadmin
// nsq_producer/main.go
package main
import (
"bufio"
"fmt"
"os"
"strings"
"github.com/nsqio/go-nsq"
)
// NSQ Producer Demo
var producer *nsq.Producer
// 初始化生产者
func initProducer(str string) (err error) {
config := nsq.NewConfig()
producer, err = nsq.NewProducer(str, config)
if err != nil {
fmt.Printf("create producer failed, err:%v\n", err)
return err
}
return nil
}
func main() {
nsqAddress := "127.0.0.1:4150"
err := initProducer(nsqAddress)
if err != nil {
fmt.Printf("init producer failed, err:%v\n", err)
return
}
reader := bufio.NewReader(os.Stdin) // 从标准输入读取
for {
data, err := reader.ReadString('\n')
if err != nil {
fmt.Printf("read string from stdin failed, err:%v\n", err)
continue
}
data = strings.TrimSpace(data)
if strings.ToUpper(data) == "Q" { // 输入Q退出
break
}
// 向 'topic_demo' publish 数据
err = producer.Publish("topic_demo", []byte(data))
if err != nil {
fmt.Printf("publish msg to nsq failed, err:%v\n", err)
continue
}
}
}
消费者
// nsq_consumer/main.go
package main
import (
"fmt"
"os"
"os/signal"
"syscall"
"time"
"github.com/nsqio/go-nsq"
)
// NSQ Consumer Demo
// MyHandler 是一个消费者类型
type MyHandler struct {
Title string
}
// HandleMessage 是需要实现的处理消息的方法
func (m *MyHandler) HandleMessage(msg *nsq.Message) (err error) {
fmt.Printf("%s recv from %v, msg:%v\n", m.Title, msg.NSQDAddress, string(msg.Body))
return
}
// 初始化消费者
func initConsumer(topic string, channel string, address string) (err error) {
config := nsq.NewConfig()
config.LookupdPollInterval = 15 * time.Second
c, err := nsq.NewConsumer(topic, channel, config)
if err != nil {
fmt.Printf("create consumer failed, err:%v\n", err)
return
}
consumer := &MyHandler{
Title: "沙河1号",
}
c.AddHandler(consumer)
// if err := c.ConnectToNSQD(address); err != nil { // 直接连NSQD
if err := c.ConnectToNSQLookupd(address); err != nil { // 通过lookupd查询
return err
}
return nil
}
func main() {
err := initConsumer("topic_demo", "first", "127.0.0.1:4161")
if err != nil {
fmt.Printf("init consumer failed, err:%v\n", err)
return
}
c := make(chan os.Signal) // 定义一个信号的通道
signal.Notify(c, syscall.SIGINT) // 转发键盘中断信号到c
<-c // 阻塞
}
只需要修改地址
发送几条消息,就多几条,内存存满了会去存磁盘
无需创建topic,发送数据的时候会自动创建topic
现在启动一个消费者
每16秒会去查最新的nsqd列表
P143 刷leetcode做题
一般刷leetcode左边有描述
问题的解决点在于有一个前置的虚拟的空的节点