游戏电视苹果数码历史美丽
投稿投诉
美丽时装
彩妆资讯
历史明星
乐活安卓
数码常识
驾车健康
苹果问答
网络发型
电视车载
室内电影
游戏科学
音乐整形

Golangdatabasesql源码分析

  简介
  Gorm是Go语言开发用的比较多的一个ORM。它的功能比较全:增删改查关联(包含一个,包含多个,属于,多对多,多种包含)CallBacks(创建、保存、更新、删除、查询找)之前之后都可以有callback函数预加载事务复合主键日志databasesql包
  但是这篇文章中并不会直接看Gorm的源码,我们会先从databasesql分析。原因是Gorm也是基于这个包来封装的一些功能。所以只有先了解了databasesql包才能更加好的理解Gorm源码。
  databasesql其实也是一个对于mysql驱动的上层封装。github。comgosqldrivermysql就是一个对于mysql的驱动,databasesql就是在这个基础上做的基本封装包含连接池的使用使用例子
  下面这个是最基本的增删改查操作
  操作分下面几个步骤:引入github。comgosqldrivermysql包(包中的init方法会初始化mysql驱动的注册)使用sql。Open初始化一个sql。DB结构调用PrepareExec执行sql语句
  使用Exec函数无需释放调用完毕之后会自动释放,把连接放入连接池中packagemainimport(databasesqlfmtgithub。comgosqldrivermysqlstrconv)funcmain(){打开连接db,err:sql。Open(mysql,root:feg125800tcp(47。100。245。167:3306)artifact?charsetutf8locAsia2FShanghaiparseTimeTrue)iferr!nil{fmt。Println(err:,err)}设置最大空闲连接数db。SetMaxIdleConns(1)设置最大链接数db。SetMaxOpenConns(1)query(db,3)}修改funcupdate(dbsql。DB,idint,userstring){stmt,err:db。Prepare(updateusersetUserName?whereId?)iferr!nil{fmt。Println(err)}res,err:stmt。Exec(user,id)updateId,err:res。LastInsertId()fmt。Println(updateId)}删除funcdelete(dbsql。DB,idint){stmt,err:db。Prepare(deletefromuserwhereid?)iferr!nil{fmt。Println(err)}res,err:stmt。Exec(1)updateId,err:res。LastInsertId()fmt。Println(updateId)}查询funcquery(dbsql。DB,idint){rows,err:db。Query(selectfromuserwhereidstrconv。Itoa(id))iferr!nil{fmt。Println(err)return}forrows。Next(){varidintvaruserstringvarpwdstringrows。Scan(id,user,pwd)fmt。Println(id:,id,user:,user,pwd:,pwd)}rows。Close()}插入funcinsert(dbsql。DB,user,pwdstring){stmt,err:db。Prepare(insertintousersetUserName?,Password?)iferr!nil{fmt。Println(err)}res,err:stmt。Exec(peter,panlei)id,err:res。LastInsertId()fmt。Println(id)}连接池
  因为Gorm的连接池就是使用databasesql包中的连接池,所以这里我们需要学习一下包里的连接池的源码实现。其实所有连接池最重要的就是连接池对象、获取函数、释放函数下面来看一下databasesql中的连接池。
  DB对象typeDBstruct{数据库实现驱动driverdriver。DriverdsnstringnumCloseduint64锁musync。Mutexprotectsfollowingfields空闲连接freeConn〔〕driverConn阻塞请求队列,等连接数达到最大限制时,后续请求将插入此队列等待可用连接connRequestsmap〔uint64〕chanconnRequest记录下一个key用于connRequestsmap的keynextRequestuint64NextkeytouseinconnRequests。numOpenintnumberofopenedandpendingopenconnectionsopenerChchanstruct{}closedbooldepmap〔finalCloser〕depSetlastPutmap〔driverConn〕string最大空闲连接数maxIdleint最大打开连接数maxOpenint连接最大存活时间maxLifetimetime。DurationcleanerChchanstruct{}}
  获取方法func(dbDB)conn(ctxcontext。Context,strategyconnReuseStrategy)(driverConn,error){db。mu。Lock()ifdb。closed{db。mu。Unlock()returnnil,errDBClosed}Checkifthecontextisexpired。select{default:casectx。Done():db。mu。Unlock()returnnil,ctx。Err()}lifetime:db。maxLifetime查看是否有空闲的连接如果有则直接使用空闲连接numFree:len(db。freeConn)ifstrategycachedOrNewConnnumFree0{取出数据第一个conn:db。freeConn〔0〕复制数组,去除第一个连接copy(db。freeConn,db。freeConn〔1:〕)db。freeConndb。freeConn〔:numFree1〕conn。inUsetruedb。mu。Unlock()ifconn。expired(lifetime){conn。Close()returnnil,driver。ErrBadConn}returnconn,nil}判断是否超出最大连接数ifdb。maxOpen0db。numOpendb。maxOpen{创建一个chanreq:make(chanconnRequest,1)获取下一个request作为map中的keyreqKey:db。nextRequestKeyLocked()db。connRequests〔reqKey〕reqdb。mu。Unlock()Timeouttheconnectionrequestwiththecontext。select{casectx。Done():Removetheconnectionrequestandensurenovaluehasbeensentonitafterremoving。db。mu。Lock()delete(db。connRequests,reqKey)db。mu。Unlock()select{default:caseret,ok:req:ifok{db。putConn(ret。conn,ret。err)}}returnnil,ctx。Err()如果没有取消则从reqchan中获取数据阻塞主一直等待有conn数据传入caseret,ok:req:if!ok{returnnil,errDBClosed}判断超时ifret。errnilret。conn。expired(lifetime){ret。conn。Close()returnnil,driver。ErrBadConn}returnret。conn,ret。err}}db。numOpenoptimisticallydb。mu。Unlock()调用driver的Open方法建立连接ci,err:db。driver。Open(db。dsn)iferr!nil{db。mu。Lock()db。numOpencorrectforearlieroptimismdb。maybeOpenNewConnections()db。mu。Unlock()returnnil,err}db。mu。Lock()dc:driverConn{db:db,createdAt:nowFunc(),ci:ci,inUse:true,}db。addDepLocked(dc,dc)db。mu。Unlock()returndc,nil}
  释放连接方法释放连接func(dbDB)putConn(dcdriverConn,errerror){db。mu。Lock()if!dc。inUse{ifdebugGetPut{fmt。Printf(putConn(v)DUPLICATEwas:sPREVIOUSwas:s,dc,stack(),db。lastPut〔dc〕)}panic(sql:connectionreturnedthatwasneverout)}ifdebugGetPut{db。lastPut〔dc〕stack()}设置已经在使用中dc。inUsefalsefor,fn:rangedc。onPut{fn()}dc。onPutnil判断连接是否有错误iferrdriver。ErrBadConn{db。maybeOpenNewConnections()db。mu。Unlock()dc。Close()return}ifputConnHook!nil{putConnHook(db,dc)}调用方法释放连接added:db。putConnDBLocked(dc,nil)db。mu。Unlock()判断如果没有加到了空闲列表中dc关闭if!added{dc。Close()}}func(dbDB)putConnDBLocked(dcdriverConn,errerror)bool{ifdb。closed{returnfalse}ifdb。maxOpen0db。numOpendb。maxOpen{returnfalse}如果等待chan列表大于0ifc:len(db。connRequests);c0{varreqchanconnRequestvarreqKeyuint64获取map中chan和keyforreqKey,reqrangedb。connRequests{break}从列表中删除chandelete(db。connRequests,reqKey)Removefrompendingrequests。iferrnil{dc。inUsetrue}把连接传入chan中让之前获取连接被阻塞的获取函数继续reqconnRequest{conn:dc,err:err,}returntrue}elseiferrnil!db。closeddb。maxIdleConnsLocked()len(db。freeConn){如果没有等待列表,则把连接放到空闲列表中db。freeConnappend(db。freeConn,dc)db。startCleanerLocked()returntrue}returnfalse}
  连接池的实现有很多方法,在databasesql包中使用的是chan阻塞使用map记录等待列表,等到有连接释放的时候再把连接传入等待列表中的chan不在阻塞返回连接。
  之前我们看到的Redigo是使用一个chan来阻塞,然后释放的时候放入空闲列表,在往这一个chan中传入struct{}{},让程序继续获取的时候再从空闲列表中获取。并且使用的是链表的结构来存储空闲列表。总结
  databasesql是对于mysql驱动的封装,然而Gorm则是对于databasesql的再次封装。让我们可以更加简单的实现对于mysql数据库的操作。

卧室这样巧妙去装扮,二人世界才够浪漫卧室是提供人们休息的场所,在装修风格上要体现出温馨舒适的效果,尤其是夫妻共同的卧室,更得要用心去装扮,这样才能凸显出浪漫的格调。那么这样的卧室该如何去布置才会有此效果呢?接下来……升级还是噱头?小米AX6000实测前言去年小米推出明星路由产品AX3600,主打WIFI6,MUMIMO以及智能家居连接。打破了之前只能做低端路由的瓶颈,同时又凭借599元的超值售价,横扫一众通路大厂。……这就是雷总的格局吗?8月真可谓是一个群雄争锋的好日子,八月十号小米mix4首发骁龙888。小米从10至尊版开始、就仿佛在告诉世人小米的产品走上了高端之路的开端,确实米10至尊版也凭借着业界先……智能计算党员突击队七六所在智能计算领域的重要布子今年3月份以来,航天科工二院七六所在智能计算领域屡创佳绩,为七六所计算机产业智能化发展奠定了强有力的技术基础。令人想不到的是,这一切成果都来源于一个叫智能计算党员突击队的……海信5G新一代阅读手机正式上架,售价2399元2020年12月22,海信正式发布了新一代海信5G阅读手机A7,目前海信阅读手机A7CC版现已上架,搭载了6。7英寸彩墨屏,在此基础上,还加入了5G芯片,成了全球首款支持5G的……华为发布最新一代nova系列,它懂年轻人华为正式发布最新一代nova系列产品nova9系列,全新nova9系列延续并强化了nova的设计和成像特点,带来了由独家9号色彩、前双3200万Vlog镜头和后置5000万超感……这道菜最适合孩子吃,不仅养心补脑,还能健胃消食,清理肠道!茼蒿是是经常被人们忽视的一道菜,很多人仅仅是在吃火锅的时候才能吃到茼蒿。但事实上茼蒿的做法很多样,可以炒可以蒸也可以煮。茼蒿是非常适合孩子吃的一道菜,因为茼蒿本身含有多种……空气开关漏电断路器过压欠压保护器是什么?空气开关、漏电断路器、过压欠压保护器是什么?它们之间存在哪些区别呢?一、空气开关空气开关,又叫空气断路器,是断路器的一种,是一种当电路中电流超过额定电流会自动断开的……英雄联盟手游与王者荣耀谁在鄙视谁目录鄙视链手游,门槛得低低门槛高竞技游戏移植持续进行1。鄙视链《LOL手游》终于在10月开启了不删档测试。在AppStore的评分一度被冲到3点几……面对竞争白热化,勘察设计企业如何发挥工程设计本质优势?勘察设计是典型的技术和人才密集型企业,作为建筑业产业链上的前端环节,承担着工程建设项目的咨询服务职责,在经过事业制转型企业化、推行全过程工程咨询服务(PMC)、工程总承包服务(……ATENVE801HDMI信号延长器产品功能概览ATENVE801为一款HDMIHDBaseTLite的信号延长器,通过一条Cat5e66a线缆能延伸HDMI信号远达70米,并支持HDMI(3D、深色、4K……李佳琦推荐也踩雷?是什么让极米NEWZ6X用户直呼一生黑?就在20日的双十一预售日开启时,极米NEWZ6X在带货一哥李佳琦的强大推动力下,销量一路飙升。京东金榜截图要说今年最值得期待的家用投影仪,极米NEWZ6X肯定是榜上……
Linux之sshid命令把本地的ssh公钥文件安装到远程主机对应的账户下,sshcopyid命令可以把本地主机的公钥复制到远程主机的authorizedkeys文件上,sshcopyid命令也会给远程……多元化的购车意愿让奇瑞小蚂蚁成为了用户的宠儿当今社会,很多的90后逐渐成为了汽车市场中的主要消费者力,他们对市场的需求明显和老一辈有着很大变化,这批年轻的消费者在购车的时候,不再一味地追求大气、有面子的车型,而是是曾经冷……南北方冷库的区别与要求南北冷库的概述就拿小编所在地福州来说吧,做为东南部沿海地区,虽然地处东南方,但与南方的气候十分接近,有南方的炎热和雨林季节,比起东部沿海,那气温算是非常的暖和了。为……双雄对决iPhone12和华为Mate40Pro拍照谁更强iPhone12和华为的Mate40Pro都已经上市两个月了,两台2020在手机行业最具影响力的机型经过多次系统升级,目前整体系统已经都已稳定。在拍照方面,两款机型都在上一代产……科比事故飞行员家属发声科比事故飞行员家属发声科比坠机事故中飞行员AraZobayan的哥哥BergeZobayan近日在一份法庭申辩文件中表示,事故发生当天科比就知道在有大雾的早上飞行中存在危险,所……不断蝉变的城投公司原创:周援智纲智库如果说1992年上海市政府率先成立的城市投资公司开启了政府型土地经营模式,那么,2002年智纲智库提出的城市运营引发了市场型的土地运营模式,最有代表性的……比亚迪汽车APP车与手机的新操作比亚迪汽车App全新升级上线,整体视觉风格耳目一新。同时,其在原有基础上融合了原迪粉汇小程序的功能,并增加了诸多新功能。通过官方展示图我们能够看到,比亚迪汽车App视觉设……呼伦贝尔南屯汽车成比亚迪宋Pro尽享优惠活动本周宋Pro最新报价:比亚迪益丰祥泰店10。25日限时促销,降价10。78,如此优惠的降幅,大家可千万不要错过,店铺地址:内蒙古自治区呼伦贝尔市鄂温克族自治旗巴彦托海镇南工业园……逃出地牢评测还未挺进就要脱出,七进七出反复折磨提起Switch上的精品独立游戏,相信很多小伙伴都会想到大名鼎鼎的《挺进地牢》,作为一款只有362MB容量的上帝视角弹幕Roguelike游戏,其丰富的内容玩法,狂野的游戏设计……砂石行业如何通过网络货运平台破解税负及管理问题砂石行业如何通过网络货运平台破解税负及管理问题近年来产业互联网带动的数字化转型在各行各业加速渗透。建筑行业一直是带动经济发展的主导行业,砂石作为建筑原材料中重要的结构材料……实际体验比宣传更重要,智能扫地机器人选购与安利为了能释放双手,我很早就接触过扫地机器人了,对于我这种懒癌晚期患者来说,简直就是解放双手的一大利器。不过,在我看来选扫地机器人不能光看宣传,实际体验比宣传更重要。而怎么选……微服务实战文档分享,阿里内部的Springcloud微服务精前几天,看到一条消息。在互联网职场论坛有个阿里巴巴员工说自己毕业了两年,结果发现工资居然比不上应届毕业研究生的起薪,感觉受到了公司的侮辱!其实,资历浅的新员工工资比……
友情链接:易事利快生活快传网聚热点七猫云快好知快百科中准网快好找文好找中准网快软网