grom (二)关于gorm 线程安全性的考证

线程安全

线程安全是指在拥有共享数据的多条线程并行执行的程序中,线程安全的代码会通过同步机制保证各个线程都可以正常且正确的执行,不会出现数据污染等意外情况。

设计实验与验证

使用 go 关键词 创建100个goroutine 来对数据库进行更新字段,让一个字段的值自增1,观察最后结果。

现有数据库test ,里面有student表,尝试修改第一条数据的age属性
在这里插入图片描述

实验代码如下

package main

import (
	"fmt"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
	"sync"
)

type Student struct {
	ID uint
	Name string
	Age uint8
}
// 设置 `Student` 的表名为 `student`
func (Student) TableName() string {
	return "student"
}

func main() {
	/* 1. 创建一个数据库连接对象db */
	dsn := "root:123456@tcp(127.0.0.1:3306)/test?charset=utf8mb4&parseTime=True&loc=Local"
	db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
	if err != nil{
		panic(err)
	}
	// 协程控制
	var waitgroup sync.WaitGroup
	waitgroup.Add(100)
	for i := 0; i < 100; i++ {
		go func(n int) {
			fmt.Println(n)
			db.Model(&Student{}).Where("id = ?", 1).Update("age", gorm.Expr("age + 1"))
			waitgroup.Done()
		}(i)
	}
	waitgroup.Wait()
}

实验结果
在这里插入图片描述
可见 gorm 对于数据库的操作是线程安全的

线程不安全的例子

这里我们以pymysql 常见的错误使用为例。设数据表结构相同,测试逻辑相同,测试代码如下

# pymysql线程安全性考量
import pymysql
import _thread
import threading

# 打开数据库连接
db = pymysql.connect(host="localhost", user="root", password="123456", db="test")

# 使用 cursor() 方法创建一个游标对象 cursor
cursor = db.cursor()

threadLock = threading.Lock()


def increase(num):
    # 使用 execute()  方法执行 SQL 查询
    print(num)
    # threadLock.acquire()  ** 线程锁 ** 
    cursor.execute("UPDATE `test`.`student` SET `age` = `age`+1 WHERE `id` = 1")
    db.commit()
    print(num, "done")
    # threadLock.release()

# 创建100 个线程
for i in range(1, 101):
    _thread.start_new_thread(increase, (i,))

# 使用input 让主程序处于停滞状态
input()

执行代码会出现如下错误
pymysql.err.InternalError: Packet sequence number wrong - got 97 expected 2
在这里插入图片描述

多个线程同时共享了一个连接,发生了错误,要使上述代码和gorm的代码有一样的效果,需要我们手动上锁,即把threadLock.acquire()threadLock.release() 取消注释

def increase(num):
    # 使用 execute()  方法执行 SQL 查询
    print(num)
    threadLock.acquire() #  ** 线程锁 ** 
    cursor.execute("UPDATE `test`.`student` SET `age` = `age`+1 WHERE `id` = 1")
    db.commit()
    print(num, "done")
    threadLock.release()
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值