0%

MySQL中的锁

数据库锁设计的初衷是处理并发问题。作为多用户共享的资源,当出现并发访问的时候,数据库需要合理地控制资源的访问规则。而锁就是用来实现这些访问规则的重要数据结构。

更新语句执行流程

下面是这个表的创建语句,这个表有一个主键 ID 和一个整型字段 c:

create table T(ID int primary key, c int);

如果要将 ID=2 这一行的值加 1,SQL 语句就会这么写:

update T set c=c+1 where ID=2;

前面我有跟你介绍过 SQL 语句基本的执行链路,这里我再把那张图拿过来,你也可以先简单看看这个图回顾下。首先,可以确定的说,查询语句的那一套流程,更新语句也是同样会走一遍。

数值类型

MySQL支持所有标准SQL数值数据类型。

这些类型包括严格数值数据类型(INTEGER、SMALLINT、DECIMAL和NUMERIC),以及近似数值数据类型(FLOAT、REAL和DOUBLE PRECISION)。

主键约束

主键可以是表中的某一列,也可以是表中的多个列所构成的一个组合;其中,由多个列组合而成的主键也称为复合主键。在MySQL中,主键列必须遵守以下规则。

Go的web工作原理

在Go中使用及其简单的代码即可开启一个web服务。如下:

//开启web服务
func test(){
    http.HandleFunc("/", sayHello)
    err := http.ListenAndServe(":9090",nil)
    if err!=nil {
        log.Fatal("ListenAndServer:",err)
    }
}

func sayHello(w http.ResponseWriter, r *http.Request){
    r.ParseForm()
    fmt.Println("path",r.URL.Path)
    fmt.Println("scheme",r.URL.Scheme)

    fmt.Fprintf(w, "Hello Guest!")
}

在使用ListenAndServe这个方法时,系统就会给我们指派一个路由器,DefaultServeMux是系统默认使用的路由器,如果ListenAndServe这个方法的第2个参数传入nil,系统就会默认使用DefaultServeMux。当然,这里也可以传入自定义的路由器。

Redis是一种内存型数据库,一旦服务器进程退出,数据库的数据就会丢失,为了解决这个问题,Redis提供了两种持久化的方案,将内存中的数据保存到磁盘中,避免数据的丢失。

redis介绍

Redis 是完全开源的,遵守 BSD 协议,是一个高性能的 key-value 数据库。

Redis 与其他 key - value 缓存产品有以下三个特点:

  • Redis支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用。
  • Redis不仅仅支持简单的key-value类型的数据,同时还提供list,set,zset,hash等数据结构的存储。
  • Redis支持数据的备份,即master-slave模式的数据备份。

redis的安装

brew install redis(mac)
yum install redis(centos)
apt-get install redis(ubuntu)

redis的命令网站

Redis 命令参考 — Redis 命令参考 (redisfans.com)

nginx是什么

nginx是一个开源的,支持高性能,高并发的www服务和代理服务软件。

  • 支持高并发,能支持几万并发连接

  • 资源消耗少,在3万并发连接下开启10个nginx线程消耗的内存不到200M

在项目中我们通常可能会使用database/sql连接MySQL数据库。本文借助使用sqlx实现批量插入数据的例子,介绍了sqlx中可能被你忽视了的sqlx.InDB.NamedExec方法。

安装

下载第三方包:

go get -u github.com/go-redis/redis/v9

连接

// 定义一个rdis客户端
var redisdb *redis.Client
// 初始化
func initClient() (err error) {
	redisdb = redis.NewClient(&redis.Options{
		Addr:     "localhost:6379", // post端口
		Password: "", // 密码
		DB:       0,  // 使用redis的库
	})
	_, err = redisdb.Ping(context.Background()).Result()
	if err != nil {
		fmt.Println("连接失败")
		return
	}
	return
}

使用

set/get示例

func redisExample() {
	ctx := context.Background()
	err := redisdb.Set(ctx, "score", 100, 0).Err()
	if err != nil {
		fmt.Printf("set score failed, err:%v\n", err)
		return
	}
	val, err := redisdb.Get(ctx, "score").Result()
	if err != nil {
		fmt.Printf("get score failed, err:%v\n", err)
		return
	}
	fmt.Println("score", val)
	val2, err := redisdb.Get(ctx, "name").Result()
	if err == redis.Nil {
		fmt.Println("name does not exist")
	} else if err != nil {
		fmt.Printf("get name failed, err:%v\n", err)
		return
	} else {
		fmt.Println("name", val2)
	}
}

zset示例

func redisExample2() {
	ctx := context.Background()
	zsetKey := "language_rank"
	languages := []*redis.Z{
		&redis.Z{Score: 90.0, Member: "Golang"},
		&redis.Z{Score: 98.0, Member: "Java"},
		&redis.Z{Score: 95.0, Member: "Python"},
		&redis.Z{Score: 97.0, Member: "JavaScript"},
		&redis.Z{Score: 99.0, Member: "C/C++"},
	}
	// ZADD
	num, err := redisdb.ZAdd(ctx, zsetKey, languages...).Result()
	if err != nil {
		fmt.Printf("zadd failed, err:%v\n", err)
		return
	}
	fmt.Printf("zadd %d succ.\n", num)
	// 把Golang的分数加10
	newScore, err := redisdb.ZIncrBy(ctx, zsetKey, 10.0, "Golang").Result()
	if err != nil {
		fmt.Printf("zincrby failed, err:%v\n", err)
		return
	}
	fmt.Printf("Golang's score is %f now.\n", newScore)
	// 取分数最高的3个
	ret, err := redisdb.ZRevRangeWithScores(ctx, zsetKey, 0, 2).Result()
	if err != nil {
		fmt.Printf("zrevrange failed, err:%v\n", err)
		return
	}
	for _, z := range ret {
		fmt.Println(z.Member, z.Score)
	}
	// 取95~100分的
	op := &redis.ZRangeBy{
		Min: "95",
		Max: "100",
	}
	ret, err = redisdb.ZRangeByScoreWithScores(ctx, zsetKey, op).Result()
	if err != nil {
		fmt.Printf("zrangebyscore failed, err:%v\n", err)
		return
	}
	for _, z := range ret {
		fmt.Println(z.Member, z.Score)
	}
}

输出结果如下: