go包管理工具小结

go dep

安装

执行以下命令安装godep工具。

go get github.com/tools/godep

基本命令

安装好godep之后,在终端输入godep查看支持的所有命令。

godep save     将依赖项输出并复制到Godeps.json文件中
godep go       使用保存的依赖项运行go工具
godep get      下载并安装具有指定依赖项的包
godep path     打印依赖的GOPATH路径
godep restore  在GOPATH中拉取依赖的版本
godep update   更新选定的包或go版本
godep diff     显示当前和以前保存的依赖项集之间的差异
godep version  查看版本信息

使用godep help [command]可以看看具体命令的帮助信息。

使用godep
在项目目录下执行godep save命令,会在当前项目中创建Godeps和vender两个文件夹。

其中Godeps文件夹下有一个Godeps.json的文件,里面记录了项目所依赖的包信息。 vender文件夹下是项目依赖的包的源代码文件。

go dep开发流程

保证程序能够正常编译

执行godep save保存当前项目的所有第三方依赖的版本信息和代码

提交Godeps目录和vender目录到代码库。

如果要更新依赖的版本,可以直接修改Godeps.json文件中的对应项

vender机制

Go1.5版本之后开始支持,能够控制Go语言程序编译时依赖包搜索路径的优先级。

例如查找项目的某个依赖包,首先会在项目根目录下的vender文件夹中查找,如果没有找到就会去$GOAPTH/src目录下查找。

##go module
go module是Go1.11版本之后官方推出的版本管理工具,并且从Go1.13版本开始,go module将是Go语言默认的依赖管理工具。

go mod命令

常用的go mod命令如下:

go mod download    下载依赖的module到本地cache(默认为$GOPATH/pkg/mod目录)
go mod edit        编辑go.mod文件
go mod graph       打印模块依赖图
go mod init        初始化当前文件夹, 创建go.mod文件
go mod tidy        增加缺少的module,删除无用的module
go mod vendor      将依赖复制到vendor下
go mod verify      校验依赖
go mod why         解释为什么需要依赖

module用来定义包名
require用来定义依赖包及版本
indirect表示间接引用

GOPROXY

GOPROXY 的默认值是:

https://proxy.golang.org,direct

这有一个很严重的问题,就是 proxy.golang.org 在国内是无法访问的,
因此这会直接卡住你的第一步,所以你必须在开启 Go modules 的时
,同时设置国内的 Go 模块代理,执行如下命令:

$ go env -w GOPROXY=https://goproxy.cn,direct

命令行开启 Go Modules

目前 Go modules 并不是默认开启,因此Go语言提供了 GO111MODULE 这个环境变量来作为 Go modules 的开关,其允许设置以下参数:

  • auto:只要项目包含了 go.mod 文件的话启用 Go modules,目前在Go1.11至 Go1.14 中仍然是默认值。
  • on:启用 Go modules,推荐设置,将会是未来版本中的默认值。
  • off:禁用 Go modules,不推荐设置。

如果你不确定你当前的值是什么,可以执行go env命令,查看结果:

$ go env
GO111MODULE="off"

如果需要对 GO111MODULE 的值进行变更,推荐通过go env命令进行设置:

$ go env -w GO111MODULE=on

goland中启用go module

代理可以设置为:https://goproxy.cn

初始化项目

go mod init

go.mod 文件

在初始化项目时,会生成一个 go.mod 文件,是启用了 Go modules 项目所必须的最重要的标识.

示例:

module github.com/example
go 1.13

require (
    github.com/jinzhu/gorm v1.9.12 // indirect
)
exclude github.com/jinzhu/gorm v1.9.11
replace github.com/go-kit/kit v0.9.0 => github.com/go-kit/kit v0.8.0
  • module:用于定义当前项目的模块路径。
  • go:用于标识当前模块的 Go 语言版本,值为初始化模块时的版本,升级golang版本时,要注意是否需要更改此处
  • require:用于设置一个特定的模块版本。
  • exclude:用于从使用中排除一个特定的模块版本。
  • replace:用于将一个模块版本替换为另外一个模块版本

go.sum 文件

go.sum 文件详细罗列了当前项目直接或间接依赖的所有模块版本,并写明了那些模块版本的 SHA-256 哈希值以备 Go 在今后的操作中保证项目所依赖的那些模块版本不会被篡改。

cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
....

h1 hash 是 Go modules 将目标模块版本的 zip 文件开包后,针对所有包内文件依次进行 hash,然后再把它们的 hash 结果按照固定格式和算法组成总的 hash 值。

而 h1 hash 和 go.mod hash 两者,要不就是同时存在,要不就是只存在 go.mod hash。那什么情况下会不存在 h1 hash 呢,就是当 Go 认为肯定用不到某个模块版本的时候就会省略它的 h1 hash,就会出现不存在 h1 hash,只存在 go.mod hash 的情况。

替代包

在管理过程中,导入的包为 0.9.0 版本,实际需要0.8.0版本,需要将导入的0.9.0版本
replace替代为 0.8.0 版本

go 1.13

require (
    github.com/jinzhu/gorm v1.9.12 // indirect
)
replace github.com/go-kit/kit v0.9.0 => github.com/go-kit/kit v0.8.0

也可以用命令行模式:

1
go mod edit -replace=old[@v]=new[@v]

参考资料:

学习 Go Modules 这一篇就够:终极入门

go 面试题小结

使用Go编程有什么好处?

1 golang虽然不像jvm那样,一次构建,到处运行。但是golang支持跨平台编译,完全能够适应多平台。

2 内嵌C支持。Go里面也可以直接包含c代码,利用现有的丰富的C库。

3 gofmt,它根据 Go 的建议风格对代码进行格式化。

4 goroutine的轻量级线程,并通过channel进行通信。

5 golang 的调度机制

Go支持类型继承吗?

Go语言中没有类继承,要用多态怎么办?

type shape interface{

    hasArea(name string)bool

}

type square struct {

    length int

}

func (sq square)hasArea(type string) bool {

    if type == "line"

        return false

    else

        return true

}

使用的时候可以这样:

sq := square

fmt.Pringln("Has area?", sq.hasArea())

或者这样

var sq shape

sq = square

fmt.Pringln("Has area?", sq.hasArea())

从上面的例子可以看出,任何能够匹配以上接口中函数定义的结构对象, 
都可以使用这个接口类型。

这样做,就在go语言实现多态了。

Go支持运营商超载吗?

Go支持方法重载吗?

不支持

Go支持指针算术吗?

golang虽说指针变量不能直接参与指针运算, 但是却提供了unsafe包, 能够实现同样的功能。

Golang是否真的没有指针运算

Go支持通用编程吗?

Go编程语言不支持通用/泛型编程

Go是一个区分大小写的语言吗?

区分:例如在方法名上,首字母大写表示方法为public,小写为私有方法

Go中变量的静态类型声明是什么?Go中变量的动态类型声明是什么?

静态类型(static type)是变量声明的时候的声明类型,
在变量声明、new方法创建对象时或者结构体(struct)的元素的类型定义,参数类型等。

接口(interface)类型的变量还有一个动态类型,它是运行时赋值给这个变量的具体的值的类型(当然值为nil的时候没有动态类型)。一个变量的动态类型在运行时可能改变,
这主要依赖它的赋值。

var x interface{}  // x 为零值 nil,静态类型为 interface{}
var v *T           // v 为零值 nil, 静态类型为 *T
x = 42             // x 的值为 42,动态类型为int, 静态类型为interface{}
x = v              // x 的值为 (*T)(nil), 动态类型为 *T, 静态类型为 *T

你能在Go中的单个声明中声明多种类型的变量吗?

var m, n int
a, b := "a", "b";

var(
   no  int
   name string
)

如何在Go中打印变量的类型?

第一种方式,反射:
fmt.Println(reflect.TypeOf(var)) 

第二种方式, %T
var a, b, c = 3, 4, "foo"    
fmt.Printf("a is of type %T\n", a)

什么是指针?

break语句的目的是什么?

break:跳出for循环;break在switch(开关语句)中在执行一条case后跳出语句的作用
continue:跳过当前循环执行下一次循环语句

golang跳转语句goto,break,continue的使用及区别

继续声明的目的是什么?

goto语句的目的是什么?

goto可以跳出多层嵌套循环,
for,while,dowhile本质是用goto语句实现的,goto语句比较底层

除非跳出多个循环嵌套和远程注入技术,否则尽量少用goto

goto会降低程序的可读性,让代码难以调试

利用递归也可以实现循环结构和do while类似

goto语句的本质

解释’for’循环的语法。

https://blog.csdn.net/guofeng93/article/details/90804430

解释在Go中创建函数的语法。

func function_name( [parameter list] ) [return_types] {
   函数体
}

你能从函数中返回多个值吗?

func (file *File) Read(b []byte) (n int, err Error) 

您可以将参数传递给方法的方式有多少?

将参数传递给函数的默认方式是什么?

Go中的函数作为值是什么意思?

在Go中函数也是一种变量,我们可以通过type来定义它,
它的类型就是所有拥有相同的参数,相同的返回值的一种类型

type typeName func(input1 inputType1 , input2 inputType2 [, ...]) (result1 resultType1 [, ...])

什么是功能关闭?

定义的或内置的可调用函数

Go中的方法是什么?

Go中局部变量的默认值是多少?

Go中全局变量的默认值是多少?

Go中指针变量的默认值是多少?

在go语言中,任何类型在声明后没有赋值的情况下,都对应一个零值。

整形如int8、byte、int16、uint、uintprt等,默认值为0。
浮点类型如float32、float64,默认值为0。
布尔类型bool的默认值为false。
复数类型如complex64、complex128,默认值为0+0i。
字符串string的默认值为”“。
错误类型error的默认值为nil。
对于一些复合类型,如指针、切片、字典、通道、接口,默认值为nil。
而数组的默认值要根据其数据类型来确定。
例如:var a [4]int,其默认值为[0 0 0 0]。

解释Printf()函数的用途。

格式化输出。

什么是左值和左值?

实际和形式参数之间有什么区别?

变量声明和变量定义有什么区别?

解释模块化编程。

什么是令牌?

哪个关键字用于执行无条件分支?

什么是阵列?

Go中的零指针是什么?

指针上的指针是什么?

Go的结构是什么?

如何在Go中定义一个结构?

Go中的切片是什么?

如何在Go中定义切片?

如何获取切片中存在的元素数?

Go中slice的len()和cap()函数有什么区别?

长度 、容量

如何获得切片的子切片?

Go的范围是什么?

Go中的map是什么?

如何在Go中创建map?

如何从Go中删除map中的条目?

什么是Go中的类型转换?

Go中的接口是什么?

垃圾回收

逃逸分析

除了 mutex 以外还有那些方式安全读写共享变量?

channel

1 无缓冲 chan 的发送和接收是否同步?

ch := make(chan int) 无缓冲的channel由于没有缓冲发送和接收需要同步.

ch := make(chan int, 2) 有缓冲channel不要求发送和接收操作同步

仅当信道的缓冲区填满后,向其发送数据时才会阻塞(阻塞写)。
当缓冲区为空时,接受方会阻塞(阻塞读)

2 channel 是通过注册 goroutine id 实现?

3 如何用channel实现一个令牌桶

go 令牌桶简易实现

令牌桶算法的基本过程如下:

  • 假如用户配置的平均发送速率为r,则每隔1/r秒一个令牌被加入到桶中;
  • 假设桶最多可以存发b个令牌。如果令牌到达时令牌桶已经满了,那么这个令牌会被丢弃;
  • 当一个n个字节的数据包到达时,就从令牌桶中删除n个令牌,并且数据包被发送到网络;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
package main

import (
"fmt"
"sync"
"time"
)

type Bucket struct {
cap int //容量
ch chan bool
timer *time.Ticker //定时填充token
mu sync.Mutex
}

func NewBucket(cap int, interval time.Duration) *Bucket {
bucket := &Bucket{
cap: cap,
ch: make(chan bool, cap),
timer: time.NewTicker(interval),
}
go bucket.startTicker()
return bucket
}

func (bucket *Bucket) startTicker() {
for i := 0; i < bucket.cap; i++ {
bucket.ch <- true
}
for {
select {
case <-bucket.timer.C:
for i := len(bucket.ch); i < bucket.cap; i++ {
bucket.Add()
}
}
}
}

func (bucket *Bucket) Add() {
bucket.mu.Lock()
defer bucket.mu.Unlock()
if len(bucket.ch) < bucket.cap {
bucket.ch <- true
}
}

func (bucket *Bucket) Get() bool {
select {
case <-bucket.ch:
return true
default:
return false
}
}

func main() {

bucket := NewBucket(5, time.Second)
for i := 0; i < 1000; i++ {
time.Sleep(time.Millisecond * 100)
go DoFunc(bucket, i)
}
for {
}
}

func DoFunc(bucket *Bucket, index int) {
if bucket.Get() {
fmt.Printf("######### success : %d \n", index)
bucket.Add() // 每次请求成功后执行Add是否合理???每一时刻最多可有cap个token可用
} else {
fmt.Printf("######### failed : %d \n", index)
}
}

golang 采用什么并发模型?体现在哪里?

Golang并发模型

说说 golang 中常用的并发模式?

JSON 标准库对 nil slice 和 空 slice 的处理是一致的吗?

Go程序能链接C/C++程序吗

为什么Go没有泛型

为什么Go没有异常

因为go开发者认为,所有异常皆可打印。

为什么用CSP思想构建并发如何知道变量分配到堆还是栈

为什么没有goroutine ID

restful熟悉吗?都有哪些请求方法,分别代表什么意思?

手写循环队列进程虚拟空间分布,全局变量放哪里?

c++ 和 go对比

怎么理解云计算

go使用踩过什么坑

go内存模型,什么是小对象,go get,go tool,go test,go vetgo什么情况下会发生内存泄漏?

go为什么高并发好?

Golang 从语言级别支持并发,通过轻量级协程 Goroutine 来实现程序并发运行。

** Goroutine 非常轻量 **,主要体现在以下两个方面:

  • 上下文切换代价小: Goroutine 上下文切换只涉及到三个寄存器(PC / SP / DX)的值修改;
    而对比线程的上下文切换则需要涉及模式切换(从用户态切换到内核态)、
    以及 16 个寄存器、PC、SP…等寄存器的刷新;

  • 内存占用少 :线程栈空间通常是 2M,Goroutine 栈空间最小 2K;

Golang 程序中可以轻松支持10w 级别的 Goroutine 运行,
而线程数量达到 1k 时,内存占用就已经达到 2G。

Go语言 CPU 性能、内存分析调试方法大汇总

pprof

go的分布式

谈谈go的未来

gogc

go的调度

go调度器

go struct能不能比较 空struct{}用处

因为是强类型语言,所以不同类型的结构不能作比较,
但是同一类型的实例值是可以比较的,实例不可以比较,因为是指针类型

map[inter]struct{}

go defer(for defer)

select可以用于什么

常用于gorotine的完美退出
golang 的 select 就是监听 IO 操作,当 IO 操作发生时,触发相应的动作
每个case语句里必须是一个IO操作,确切的说,应该是一个面向channel的IO操作    

context包的用途

client如何实现长连接

server是设置超时时间,for循环遍历的

主协程如何等其余协程完再操作

slice,len,cap,共享,扩容

map如何顺序读取

map不能顺序读取,是因为他是无序的,想要有序读取,
首先的解决的问题就是,把key变为有序,
所以可以把key放入切片,对切片进行排序,遍历切片,通过key取值。

实现set

type inter interface{}
type Set struct {
    m map[inter]bool
    sync.RWMutex
}

func New() *Set {
    return &Set{
    m: map[inter]bool{},
    }
}
func (s *Set) Add(item inter) {
    s.Lock()
    defer s.Unlock()
    s.m[item] = true
}

实现消息队列(多生产者,多消费者)

使用切片加锁可以实现

大文件排序

归并排序,分而治之,拆分为小文件,在排序

基本排序,哪些是稳定的

读写锁

http

1 http get跟head

HEAD和GET本质是一样的,区别在于HEAD不含有呈现数据,
而仅仅是HTTP头信息。有的人可能觉得这个方法没什么用,
其实不是这样的。想象一个业务情景:欲判断某个资源是否存在,
我们通常使用GET,但这里用HEAD则意义更加明确。

2 http 401,403

400 bad request,请求报文存在语法错误
401 unauthorized,表示发送的请求需要有通过 HTTP 认证的认证信息
403 forbidden,表示对请求资源的访问被服务器拒绝
404 not found,表示在服务器上没有找到请求的资源  

3 http keep-alive

client发出的HTTP请求头需要增加Connection:keep-alive字段
Web-Server端要能识别Connection:keep-alive字段,
并且在http的response里指定Connection:keep-alive字段,
告诉client,我能提供keep-alive服务,
并且"应允"client我暂时不会关闭socket连接

4 http能不能一次连接多次请求,不等后端返回

http本质上市使用socket连接,因此发送请求,接写入tcp缓冲,
是可以多次进行的,这也是http是无状态的原因   

5 tcp与udp区别,udp优点,适用场景

tcp传输的是数据流,而udp是数据包,tcp会进过三次握手,udp不需要

6 time-wait的作用 服务产生大量的time_wait如何解决

https://www.jianshu.com/p/41f7e468f312

如果服务器最后发送的ACK因为某种原因丢失了,那么客户一定会重新发送FIN,
这样因为有TIME_WAIT的存在,服务器会重新发送ACK给客户,
如果没有TIME_WAIT,那么无论客户有没有收到ACK,服务器都已经关掉连接了,
此时客户重新发送FIN,服务器将不会发送ACK,而是RST,从而使客户端报错

如果没有TIME_WAIT,我们可以在最后一个ACK还未到达客户的时候,
就建立一个新的连接。那么此时,如果客户收到了这个ACK的话,就乱套了,
必须保证这个ACK完全死掉之后,才能建立新的连接。


在应用中通过设置合理的连接池参数可以避免TIME_WAIT状态过多的问题
比如 http  redis  grpc  mysql...

数据库

1 索引

2 锁

3 事务

幻读,一致性,CAP

4 持久化

redis

1 持久化

2 分布式锁

3 sorted set

mq

1 重复消费

2 保证不丢失消息

孤儿进程,僵尸进程

死锁条件,如何避免

linux命令,查看端口占用,cpu负载,内存占用,如何发送信号给一个进程

git文件版本,使用顺序,merge跟rebase

go数据类型小结

https://www.cnblogs.com/itbsl/p/9854681.html

基本数据类型

整型

无符号整型:uint8uint16uint32uint64

带符号整型:int8 int16 int32 int64

uintint具体是32位还是64位看操作系统

浮点型

float32和float64

Go语言中浮点数默认是float64

复数

complex128和complex64

布尔值

boolean

##字符串
string

byte和rune类型

go语言中字符串都是UTF-8编码,UTF-8编码中一个常用汉字一般占3个字符

由于rune可表示的范围更大,所以能处理一切字符,当然也包括中文字符。在平时计算中文字符,可用rune。

1
2
3
4
5
6
7
8
9
10
11
func main() {
var chinese = "我是中国人, I am Chinese"
fmt.Println("chinese length", len(chinese))
fmt.Println("chinese word length", len([]rune(chinese)))
fmt.Println("chinese word length", utf8.RuneCountInString(chinese))
}

//输出,注意在golang中一个汉字占3个byte
chinese length 31
chinese word length 19
chinese word length 19

go跨平台编译小结

#1、跨平台编译
https://studygolang.com/articles/20471

windows平台下编译linux可执行文件:

1
2
3
SET CGO_ENABLED=0 //禁用CGO
SET GOOS=linux //目标平台是linux
SET GOARCH=amd64 // 目标处理器架构是amd64

再执行 ‘go bulid’ 命令,就可以得到在linux平台运行的可执行文件了

Mac 下编译 Linux 和windows平台64位可执行文件

1
2
3
4
CGO_ENABLED=0 
GOOS=darwin
GOARCH=amd64
go bulid
1
2
3
4
CGO_ENABLED=0 
GOOS=windows
GOARCH=amd64
go bulid

windows下编译Mac平台64位可执行文件

1
2
3
4
CGO_ENABLED=0 
GOOS=darwin
GOARCH=amd64
go bulid

gin框架搭建小结

##1 go gin

##2 安装

gin-gonic

gin

go get -u github.com/gin-gonic/gin

##3 导入
package main

import "github.com/gin-gonic/gin"

func main() {
    r := gin.Default()
    r.GET("/ping", func(c *gin.Context) {
        c.JSON(200, gin.H{
            "message": "pong",
        })
    })
    r.Run() // listen and serve on 0.0.0.0:8080 (for windows "localhost:8080")
}

##4 API Examples

Using GET, POST, PUT, PATCH, DELETE and OPTIONS

func main() {
    // Creates a gin router with default middleware:
    // logger and recovery (crash-free) middleware
    router := gin.Default()

    router.GET("/someGet", getting)
    router.POST("/somePost", posting)
    router.PUT("/somePut", putting)
    router.DELETE("/someDelete", deleting)
    router.PATCH("/somePatch", patching)
    router.HEAD("/someHead", head)
    router.OPTIONS("/someOptions", options)

    // By default it serves on :8080 unless a
    // PORT environment variable was defined.
    router.Run()
    // router.Run(":3000") for a hard coded port
}

Parameters in path

func main() {
    router := gin.Default()

    // This handler will match /user/john but will not match /user/ or /user
    router.GET("/user/:name", func(c *gin.Context) {
        name := c.Param("name")
        c.String(http.StatusOK, "Hello %s", name)
    })

    // However, this one will match /user/john/ and also /user/john/send
    // If no other routers match /user/john, it will redirect to /user/john/
    router.GET("/user/:name/*action", func(c *gin.Context) {
        name := c.Param("name")
        action := c.Param("action")
        message := name + " is " + action
        c.String(http.StatusOK, message)
    })

    // For each matched request Context will hold the route definition
    router.POST("/user/:name/*action", func(c *gin.Context) {
        c.FullPath() == "/user/:name/*action" // true
    })

    router.Run(":8080")
}

Querystring parameters

func main() {
    router := gin.Default()

    // Query string parameters are parsed using the existing underlying request object.
    // The request responds to a url matching:  /welcome?firstname=Jane&lastname=Doe
    router.GET("/welcome", func(c *gin.Context) {
        firstname := c.DefaultQuery("firstname", "Guest")
        lastname := c.Query("lastname") // shortcut for c.Request.URL.Query().Get("lastname")

        c.String(http.StatusOK, "Hello %s %s", firstname, lastname)
    })
    router.Run(":8080")
}

mysql事务

1、原子性实现原理:Undo log

- Undo log是为了实现事务的原子性,在mysql数据库InnoDB存储引擎中,
还用Undo log来实现多版本并发控制(MVCC)
- 在操作任何数据之前,首先将数据备份到一个地方(这个存储数据备份的地方称为Undo log).
然后进行数据修改。如果出现了错误或者用户执行了ROLLBACK语句,
系统可以利用undo log中的备份将数据恢复到事务之前的状态
- 注意:undo log是逻辑日志,可以理解为:
    - 当delete一条记录时,undo log中会记录一条对应的insert记录
    - 当insert一条记录时,undo log中会记录一条对应的delete记录
    - 当update一条记录时,undo log中会记录一条相反的update记录


(逻辑日志的意思是记录某一行数据的修改,物理日志是记录某一页的数据修改)

2、持久性原理: Redo log

- 和undo log相反,redo log记录的是新数据的备份。(异步写)
在事务提交前,只要将redo log持久化即可,不需要将数据持久化。
当系统崩溃时,虽然数据没有持久化,但是redo log已经持久化。
系统可以根据 redo log 的内容,将所有数据恢复到最新的状态
(innodb_flush_log_at_trx_commit)
WAL(write ahead log):预写日志

当我们每次执行update,insert,delete等语句后,commit操作后,redo log执行持久化操作

innodb_flush_log_at_trx_commit = 0/1/2

set global innodb_flush_log_at_trx_commit=2;
show variables like 'innodb_flush_log_at_trx_commit';

默认值为:1

由于实时将数据刷到磁盘中,在并发条件下,性能较低,

3、mysql的隔离级别

  • 读未提交(read_uncommitted):对事务处理的读取没有任何限制;
  • 读已提交(read_committed):
  • 可重复读(repeatable_read):默认级别
  • 串行化(seriauzable)
事务的隔离级别 脏读 不可重复读 幻读
读未提交(read_uncommitted)
读已提交(read_committed)
可重复读(repeatable_read)
串行化(seriauzable)

一致性

事务的并发执行,事务故障或系统故障 会对事务的一致性造成破坏

数据库系统通过并发控制技术和日志恢复技术来避免这种情况的发生:
- 并发控制技术保证了事务的隔离性(加锁),使数据库的一致性状态不会
因为并发执行的操作被破坏。
- 日志恢复技术保证了事务的原子性,是一致性状态下不会因事务或系统故障被破坏。
同时使已提交的对数据库的修改不会因为系统崩溃而丢失,保证了事务的持久性。

mysql优化

#1、选择优化的数据类型

##1 更小的通常更好
一般情况下,应该尽量使用可以正确存储数据的最小的数据类型

例如只需要存储 `0-200`, `tinyint unsigned`更好一些

更小的数据类型通常更快,因为它们占用更少的磁盘、内存和CPU缓存,并且处理时需要的CPU周期也更少

##2 简单就好
简单数据类型的操作通常需要更少的CPU周期。

例如,整型比字符型操作代价更低,因为字符集和校对规则(排序规则)是字符比较比整型比较更复杂。
ex: 一个是应该使用Mysql内建的类型(date,time,datetime)而不是字符串来存储日期和时间,另外一个是应该用整型存储IP地。

##3 尽量避免NULL
很多表都包含可为NULL的列,即使应用程序并不需要保存NULL也是如此,这是因为NULL是列的默认属性。
通常情况下最好指定列为NOT NULL,除非真的需要存储NULL值。

如果查询中包含可为NULL的列,对Mysql来说更难优化,因为可为NULL的列使得索引、索引统计和值比较都更复杂。
可为NULL的列会使用更多的存储空间,在Mysql中也需要特殊处理。当可为NULL的列被索引时,每个索引记录需要一个额外的字节,
在MyISAM里甚至还可能导致固定大小的索引(例如只有一个整数列的索引)变成可变大小的索引。
通常此项改动对于InnoDB的性能提升比较小。InnoDB使用单独的位(bit)存储NULL值,所以对于稀疏数据有很好的空间效率。

优化工具

explain

explain-output

show-profile

show-profile

* The SHOW PROFILE and SHOW PROFILES statements are deprecated and will be removed in a future MySQL release.
Use the Performance Schema instead; see Section 25.19.1, “Query Profiling Using Performance Schema”. *

set profiling=1;
select * from student;
show profile for query 1;
show profile all for query 1;
show profile all for query 1\G               (后面没有分号!!!)

---------------------------------------

mysql> set profiling=1;
Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql> select * from student;
+----+-----------+------+------+
| id | name      | age  | sex  |
+----+-----------+------+------+
|  1 | xiaoming  |   19 |    1 |
|  2 | xiaohong  |   18 |    0 |
|  3 | xiaolan   |   20 |    0 |
|  4 | xiaolv    |   20 |    0 |
|  5 | xiaohuang |   20 |    0 |
|  6 | 666       |   17 |    0 |
+----+-----------+------+------+
6 rows in set (0.00 sec)

mysql> show profile for query 1;
+----------------------+----------+
| Status               | Duration |
+----------------------+----------+
| starting             | 0.000081 |
| checking permissions | 0.000011 |
| Opening tables       | 0.000019 |
| init                 | 0.000018 |
| System lock          | 0.000009 |
| optimizing           | 0.000006 |
| statistics           | 0.000016 |
| preparing            | 0.000013 |
| executing            | 0.000005 |
| Sending data         | 0.000056 |
| end                  | 0.000006 |
| query end            | 0.000009 |
| closing tables       | 0.000008 |
| freeing items        | 0.000013 |
| cleaning up          | 0.000016 |
+----------------------+----------+
15 rows in set, 1 warning (0.00 sec)

mysql> show profile all for query 1;
+----------------------+----------+----------+------------+-------------------+---------------------+--------------+---------------+---------------+-------------------+-------------------+-------------------+-------+-----------------------+----------------------+-------------+
| Status               | Duration | CPU_user | CPU_system | Context_voluntary | Context_involuntary | Block_ops_in | Block_ops_out | Messages_sent | Messages_received | Page_faults_major | Page_faults_minor | Swaps | Source_function       | Source_file          | Source_line |
+----------------------+----------+----------+------------+-------------------+---------------------+--------------+---------------+---------------+-------------------+-------------------+-------------------+-------+-----------------------+----------------------+-------------+
| starting             | 0.000081 | 0.000032 |   0.000045 |                 0 |                   0 |            0 |             0 |             0 |                 0 |                 0 |                 0 |     0 | NULL                  | NULL                 |        NULL |
| checking permissions | 0.000011 | 0.000005 |   0.000006 |                 0 |                   0 |            0 |             0 |             0 |                 0 |                 0 |                 0 |     0 | check_access          | sql_authorization.cc |         809 |
| Opening tables       | 0.000019 | 0.000007 |   0.000010 |                 0 |                   0 |            0 |             0 |             0 |                 0 |                 0 |                 0 |     0 | open_tables           | sql_base.cc          |        5753 |
| init                 | 0.000018 | 0.000007 |   0.000011 |                 0 |                   0 |            0 |             0 |             0 |                 0 |                 0 |                 0 |     0 | handle_query          | sql_select.cc        |         128 |
| System lock          | 0.000009 | 0.000005 |   0.000006 |                 0 |                   0 |            0 |             0 |             0 |                 0 |                 0 |                 0 |     0 | mysql_lock_tables     | lock.cc              |         330 |
| optimizing           | 0.000006 | 0.000002 |   0.000004 |                 0 |                   0 |            0 |             0 |             0 |                 0 |                 0 |                 0 |     0 | optimize              | sql_optimizer.cc     |         158 |
| statistics           | 0.000016 | 0.000007 |   0.000009 |                 0 |                   0 |            0 |             0 |             0 |                 0 |                 0 |                 0 |     0 | optimize              | sql_optimizer.cc     |         374 |
| preparing            | 0.000013 | 0.000005 |   0.000008 |                 0 |                   0 |            0 |             0 |             0 |                 0 |                 0 |                 0 |     0 | optimize              | sql_optimizer.cc     |         482 |
| executing            | 0.000005 | 0.000002 |   0.000002 |                 0 |                   0 |            0 |             0 |             0 |                 0 |                 0 |                 0 |     0 | exec                  | sql_executor.cc      |         126 |
| Sending data         | 0.000056 | 0.000023 |   0.000033 |                 0 |                   0 |            0 |             0 |             0 |                 0 |                 0 |                 0 |     0 | exec                  | sql_executor.cc      |         202 |
| end                  | 0.000006 | 0.000002 |   0.000003 |                 0 |                   0 |            0 |             0 |             0 |                 0 |                 0 |                 0 |     0 | handle_query          | sql_select.cc        |         206 |
| query end            | 0.000009 | 0.000004 |   0.000006 |                 0 |                   0 |            0 |             0 |             0 |                 0 |                 0 |                 0 |     0 | mysql_execute_command | sql_parse.cc         |        4956 |
| closing tables       | 0.000008 | 0.000003 |   0.000004 |                 0 |                   0 |            0 |             0 |             0 |                 0 |                 0 |                 0 |     0 | mysql_execute_command | sql_parse.cc         |        5009 |
| freeing items        | 0.000013 | 0.000005 |   0.000008 |                 0 |                   0 |            0 |             0 |             0 |                 0 |                 0 |                 0 |     0 | mysql_parse           | sql_parse.cc         |        5622 |
| cleaning up          | 0.000016 | 0.000007 |   0.000008 |                 0 |                   0 |            0 |             0 |             0 |                 0 |                 0 |                 0 |     0 | dispatch_command      | sql_parse.cc         |        1931 |
+----------------------+----------+----------+------------+-------------------+---------------------+--------------+---------------+---------------+-------------------+-------------------+-------------------+-------+-----------------------+----------------------+-------------+
15 rows in set, 1 warning (0.00 sec)

Performance

performance-schema-quick-start

https://dev.mysql.com/doc/refman/8.0/en/optimization.html

分库分表

分库分表

mysql中间件分享(Mysql-prxoy,Atlas,DBProxy,Amoeba,cobar,TDDL)

主从复制

MTS: 并行复制技术

读写分离

使用存储过程脚本批量插入数据

使用存储过程脚本批量插入数据

创建数据库表:

1
2
3
4
5
6
CREATE TABLE bigtables (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`number` int(20) DEFAULT NULL,
`name` varchar(100) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

创建函数:

1
2
3
4
5
6
7
8
9
10
11
12
delimiter $$
create function rand_string(n int) returns varchar(255)
begin
declare chars_str varchar(100) default 'qwertyuiopasdfghjklzxcvbnm';
declare return_str varchar(255) default '';
declare i int default 0;
while i<n do
set return_str=concat(return_str,substring(chars_str,floor(1+rand()*52),1));
set i=i+1;
end while;
return return_str;
end $$

创建产生随机的数字的函数

删除函数: DROP FUNCTION rand_num;

1
2
3
4
5
6
delimiter $$
create function rand_num() returns int(5)
begin
declare i int default 0;
set i=floor(100+rand()*10);
return i; end $$

创建存储过程

删除存储过程: drop procedure insert_bigtables;

1
2
3
4
5
6
7
8
9
10
11
12
delimiter $$ 
create procedure insert_bigtables(in start int(10),in max_num int(10))
begin
declare i int default 0;
set autocommit = 0;
repeat
set i = i +1;
insert into bigtables(id,number,name) values((start+i),rand_num(),rand_string(6));
until i=max_num
end repeat;
commit;
end $$

调用存储过程

1
2
call insert_bigtables(100,10); 
/*number大于100,插入10条数据*/

查看存储过程

select name from mysql.proc where db = 'insert_bigtables' and type = 'PROCEDURE';

SELECT * FROM information_schema.Routines WHERE ROUTINE_NAME = 'insert_bigtables' ;

SHOW CREATE PROCEDURE insert_bigtables;

SHOW CREATE FUNCTION rand_num;