原文:https://my.oschina.net/waknow/blog/205654


摘要: 使用Go链接数据库时,由于连接释放不当会在一段时间以后产生too many connections的错误。因此需要适当的选择函数和及时的释放数据库连接。

这几天用Go写了个简陋的服务器,连接Mysql数据库,提供api给其他程序调用来实现增删改产等服务。Go的版本是1.2,使用的驱动是go-sql-driver/mysql。但是在有一定量的查询结果以后,会出先too many connection的错误。

google了一下,很多文章都建议修改MySql的配置文件:my.ini。文章是这样解释的:MySql的默认连接数是100,当查询数过多时,就会出现这个错误。所以把配置修改:

max_connections=1000

这个字段后面的数字就是MySql允许的连接数,改的大一些就会解决问题。于是在电脑上直接改成10000,重启MySql。然后电脑就卡的要崩溃了。看了相关的文档大约知道,这个参数是控制MySql建立的线程数的。改成10000就会有一万个线程,电脑自然就会卡的。但是即使是这个样子,在一定的时间后还是会出现too many connections这样的错误,只是出现的时间会晚一些罢了。所以说这个也只是治标而不治本,根本没有解决问题。

翻看Go的sql文档,其中有个func (*DB) SetMaxOpenConns的函数,看名字是可以控制最大的连接数的。很开心的在程序里设置了个可以接受的数字,然后编译运行。问题仍然没有解决,还是会报同样的错误。只能通过不断的重启服务器来解决。一时真的不知道该怎么解决了。甚至怀疑是不是使用的驱动包有问题。

无意间看到这篇文章Go's database/sql,文章里解释了Go中连接数据库的连接池:当你需要和数据库通信时,就会从连接池里面取出一个连接,和数据库交互。使用完的闲置的连接会回到连接池,等待下一次的调用。如果连接池里面没有闲置的连接,会自动创建一个新的连接出来。其中有一段:

An sql.Row returns the connection when Scan() is called, sql.Rows returns either when Close() is called or all rows have been iterated over with Next(), and sql.Tx will return when Commit or Rollback() are called. If you forget to completely iterate an sql.Rows and you forget to Close it, that connection will never go back to the pool.

从上面可以看到,sql.Row如果不遍历完或者直接调用Close()方法,执行这次查询的连接就会一直存在!当连接池里的可用连接用光后,就开始创建新的连接。这就是为什么调用SetMaxOpenConns没有用的原因,因为这个函数只是设置连接池里的连接数而已!如果因为不及时释放连接而让连接池干掉了,还是会不断的创建新的连接,直到用光MySql所有的连接,报错。明白以后,在所有调用DB.Query的函数里加上了:

defer row.Close()

这样查询连接就能在函数结束或者异常的情况下被关闭,就不会持续创建新的连接了。满以为这样就可以解决问题了,但是服务器运行了以后,过段时间仍然会出现相同的错误。在phpMyadmin里的监控页面,可以看到程序运行以后MySql的连接数猛增。问题又变得无解了,只能重新一行行检查代码。

Go中的函数可以有多个返回值,使用下划线可以忽略不需要的返回值:

_, err := m.DB.Query("sql")

程序中update和del之类的sql语句不需要返回值,就直接忽略了。猜想这样也是没法释放连接的,因为即使你不接受返回值,不代表这个变量就不存在了。也就是说返回的sql.Row还是存在的,只是你没有接收而已。没接收,就更谈不上释放连接了,所以最后产生了大量的连接继续报错。回头看看那篇文章,看到这么一段:

Ping and Exec will release the connection right before returning, but the others will pass ownership of the connection to the result, whether that's an sql.Row, sql.Rows, or sql.Tx.

也就是说Ping和Exec方法在调用完之后,会自动释放连接。把代码中所有不需要返回值的语句改成由Exce方法执行,go run 一下,ok,连接数终于正常了!

问题是解决了,总起来以后要注意一下的东西:

  • 程序连接数据库会有连接泄漏的情况,需要及时释放连接

  • Go sql包中的Query和QueryRow(@qgymje 在评论中提到,QueryRow通过调用Scan方法,会自动关闭连接的)两个方法的连接不会自动释放连接,只有在遍历完结果或者调用close方法才会关闭连接

  • Go sql中的Ping和Exec方法在调用结束以后就会自动释放连接

  • 忽略了函数的某个返回值不代表这个值就不存在了,如果该返回值需要close才会释放资源,直接忽略了就会导致资源的泄漏。

  • 有close方法的变量,在使用后要及时调用该方法,释放资源

Go连接MySql数据库Error 1040: Too many connections错误解决的更多相关文章

  1. [技术博客]django连接mysql数据库的方法及部分问题的解决方法

    配置机器介绍 操作系统:Ubuntu 18.04.2 LTS 64位 python版本:Python 3.6.7 Django版本:Django 2.2 MySql版本:5.7.26 数据库选择 我们 ...

  2. 3.django连接mysql数据库及安装mysqldb驱动报错解决办法

    1.在setting.py设置连接数据库 DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'djang ...

  3. MySQL ERROR 1040: Too many connections

    如题,本章主要讲下当服务器出现 ERROR 1040: Too many connections错误时的一些处理心得. max_connections查看 ## 查看最大连接数 SHOW VARIAB ...

  4. Navicat for mysql 远程连接 mySql数据库10061、1045错误

    原文地址:http://www.111cn.net/database/mysql/46377.htm 有朋友可能会碰到使用Navicat for mysql 远程连接 mySql数据库会提示10061 ...

  5. Qt连接mysql数据库遇到QMYSQL driver not loaded

    本文件向各位博友分享一下我在Qt开发过程中,连接mysql数据库时遇到的问题,以及解决的方法,希望对遇到同样问题的博友有所帮助. 工程运行环境:vs2015+Qt5.8 在开发过程中,编写数据库连接函 ...

  6. ruby使用DBI连接MySQL数据库发生异常:in `error': Can't connect to MySQL server on 'localhost' (10061) (DBI::DatabaseError)

    Ruby使用DBI连接MySQL数据库一般为: require "dbi" dbh = DBI.connect("dbi:Mysql:test:localhost&quo ...

  7. Error loading MySQLdb module: No module named 'MySQLdb'----------- django成功连接mysql数据库的方法

    在进行django学习过程中,尝试使用框架连接mysql数据库,启动服务器的时候经常遇到Error loading MySQLdb module: No module named 'MySQLdb' ...

  8. (转) Eclipse连接MySQL数据库(傻瓜篇)

    Eclipse连接MySQL数据库(傻瓜篇) 原帖地址: http://www.cnblogs.com/fnng/archive/2011/07/18/2110023.html Posted on 2 ...

  9. visualC/C++连接MySql数据库

    vs连接数据库其实就是将mysql数据库.h头文件接口.lib链接文件和dll执行文件加入到项目中.下面是配置如何加入. 转于http://www.cnblogs.com/justinzhang/ar ...

随机推荐

  1. 001-mac使用桌面、Dock、键盘、程序安装

    一.桌面 Finder:dock第一个正方形蓝白笑脸,类似于Windows的资源管理器,是图形化界面基础,默认启动 菜单:最上侧一行左侧,当前程序的菜单 dock:应用程序快捷图标,启动的程序下面有个 ...

  2. Oracle记录登录失败的触发器

    前言:实现的功能主要是,oracle登录成功记录登录用户ip地址,登录失败记录登录失败ip地址 1,需要建立一个触发器记录登录成功的客户端用户的ip地址 大家都知道在v$session 中记录着客户端 ...

  3. Python函数参数*args和**kwargs

    1. Python中使用*args和**kwargs #!/usr/bin/env python3 # coding: utf-8 # File: args_kwargs_demo.py # Auth ...

  4. Codeforces Round #112 (Div. 2) D. Beard Graph

    地址:http://codeforces.com/problemset/problem/165/D 题目: D. Beard Graph time limit per test 4 seconds m ...

  5. Python的socket网络编程(一)

    (注:本文部分内容摘自互联网,由于作者水平有限,不足之处,还望留言指正.) 先写首诗,抒抒情. 一. 食堂.校园 见过你那么多次 卑微的我 只敢偷偷瞄上一眼 心扑通 扑通 春天真好 不是么 二. 学子 ...

  6. 基于JWT的token身份认证方案

    一.使用JSON Web Token的好处? 1.性能问题. JWT方式将用户状态分散到了客户端中,相比于session,可以明显减轻服务端的内存压力. Session方式存储用户id的最大弊病在于S ...

  7. HttpWebRequest 返回BadRequest(400) 同时返回Response

    今天用Fiddler分析安卓APP的一个登陆功能的时候,账号和密码错误会返回相应的消息,并且状态码是400. 正常用法: /// <summary> /// 读取返回的内容 /// < ...

  8. 20145324 《Java程序设计》第8周学习总结

    20145324 <Java程序设计>第8周学习总结 教材学习内容总结 第十四章 1.NIO使用频道来衔接数据节点,可以设定缓冲区容量,在缓冲区中对感兴趣的数据区块进行标记,提供clear ...

  9. 优盘版Kali

    准备USB镜象 下载Kali linux. 如果你用的是Windows,下载Win32 Disk Imager. *nix类系统不需要额外的软件. 一块U盘(至少 2GB 容量). Kali Linu ...

  10. [CF911F]Tree Destruction

    题意翻译 给你一棵树,每次挑选这棵树的两个叶子,加上他们之间的边数(距离),然后将其中一个点去掉,问你边数(距离)之和最大可以是多少. 首先我们知道,到一个点距离最远的点是直径的端点.考虑贪心,如果我 ...