mysql消除自动断开8小时未曾用过的链接

by admin on 2019年9月2日

最近在做一个个人项目,数据库尝试使用了mongodb、sqlite和mysql。分享一下关于mysql的连接池用法。项目部署于appfog,项目中我使用连接池链接数据库,本地测试一切正常。上线以后,经过几次请求两个数据接口总是报503。一直不明就里,今天经过一番排查终于顺利解决了。

异常:

在使用mysql进行开发的时候,经常会遇到如何控制mysql连接数的问题。比较好的解决方案就是使用一个连接池,控制连接数。org.apache.commons.pool2中提供了对象池管理的框架,可以很方便的解决这个问题。

mysql解决自动断开8小时未曾用过的链接

通过修改/etc/ssh/sshd_config中的配置解决自动断开的问题。下面是要修改的两个配置项的含义:

 

javax.servlet.ServletException:
org.springframework.transaction.CannotCreateTransactionException: Could
not open Hibernate Session for transaction; nested exception is
org.hibernate.TransactionException: JDBC begin failed:

具体实现

import java.sql.{Connection, DriverManager}

import org.apache.commons.pool2.impl.{DefaultPooledObject, GenericObjectPool}
import org.apache.commons.pool2.{BasePooledObjectFactory, PooledObject}

object MysqlConnectionPool {
  def apply(url: String, userName: String, password: String, className: String): GenericObjectPool[Connection] = {
    new GenericObjectPool[Connection](new MysqlConnectionFactory(url, userName, password, className))
  }
}

class MysqlConnectionFactory(url: String, userName: String, password: String, className: String) extends BasePooledObjectFactory[Connection]{
  override def create(): Connection = {
    Class.forName(className)
    DriverManager.getConnection(url, userName, password)
  }

  override def wrap(conn: Connection): PooledObject[Connection] = new DefaultPooledObject[Connection](conn)

  override def validateObject(pObj: PooledObject[Connection]) = !pObj.getObject.isClosed

  override def destroyObject(pObj: PooledObject[Connection]) = pObj.getObject.close()
}

 

“ClientAliveInterval指定了服务器端向客户端请求消息的时间间隔, 默认是0,
不发送.而ClientAliveInterval 60表示每分钟发送一次, 然后客户端响应,
这样就保持长连接了.这里比较怪的地方是:不是客户端主动发起保持连接的请求(如FTerm,
CTerm等),而是需要服务器先主动。

 

 

测试

import java.sql.{Connection, ResultSet, Statement}

import org.apache.commons.pool2.impl.{GenericObjectPool, GenericObjectPoolConfig}
object RunApp {

  def getData(pool: GenericObjectPool[Connection]): Unit ={
    var stmt: Statement = null
    var rs: ResultSet = null

    try {
      val conn = pool.borrowObject()
      stmt = conn.createStatement
      rs = stmt.executeQuery("SELECT * FROM user")
      for (index <- 1 to rs.getMetaData.getColumnCount){
        println(rs.getMetaData.getColumnName(index))
      }

      Thread.sleep(10000)

      pool.returnObject(conn)
    } catch {
      case ex: Exception =>
        // handle any errors
        System.out.println("SQLException: " + ex.getMessage)
    }
  }

  def main(args: Array[String]): Unit = {
    val conf = new GenericObjectPoolConfig
    conf.setMaxTotal(2)
    conf.setMaxIdle(1)
    conf.setMaxWaitMillis(20000)
    val pool = MysqlConnectionPool("jdbc:mysql://localhost:3306/tutorials", "root", "root", "com.mysql.jdbc.Driver")
    pool.setConfig(conf)

    for (_ <- 1 to 3){
      new Thread(new Runnable {
        override def run(): Unit = {
          getData(pool)
        }
      }).start()
    }
  }
}

测试代码中通过conf.setMaxTotal(2)设置最大使用的连接数为2,也就是说只能同时有两个对象连接mysql,其他对象等待,并且等待的超时时间为conf.setMaxWaitMillis(20000)。那么在main函数中启动了3个线程同时对数据库进行查询操作,并且每次查询都会sleeep
10秒。程序运行的时候可以通过show full processlist;查看mysql的连接数,会发现只有2个对象会同时连接mysql,只有等其中一个运行结束后pool.returnObject(conn)将连接返还给连接池,第三个线程才会得到资源连接mysql。
conf.setMaxIdle(1)的作用是最多处于idle状态的对象的个数,如果超过这个数量,会自动调用MysqlConnectionFactory中的destroyObject方法销毁对象。

近一段时间,很多部门同事反映在使用mysql的过程出现数据库连接自动断开的问题,我对该问题做了一些实验。
 www.2cto.com  

另外,至于ClientAliveCountMax,
使用默认值3即可.ClientAliveCountMax表示服务器发出请求后客户端没有响应的次数达到一定值,
就自动断开。正常情况下, 客户端不会不响应。“

 

root cause

总结

通过本文介绍的方式可以有效的控制mysql的连接数。

关于mysql自动断开的问题研究结果如下,在mysql中有相关参数设定,当数据库连接空闲一定时间后,服务器就

1 查看当前配置

1.mysql 链接普通模式

org.springframework.transaction.CannotCreateTransactionException: Could
not open Hibernate Session for transaction; nested exception is
org.hibernate.TransactionException: JDBC begin failed:

会断开等待超时的连接:

grep”ClientAlive” sshd_config

 

 

奥门威尼斯网址 1

#ClientAliveInterval0

 

 

 

#ClientAliveCountMax3

 

解决方案:

同一时间,这两个参数只有一个起作用。到底是哪个参数起作用,和用户连接时指定的连接参数相关,缺省情况下是使用

2 备份原文件

mysql的普通用法如下所示:

1.

wait_timeout。我建议是将这两个参数都修改,以免引起不必要的麻烦。

cp sshd_configsshd_config.bak

 

给jdbc url 增加 autoReconnect=true 一定能解决你的问题,可以定期观察一下
show processlist
改进方法如下:
<property name=”url”
value=”jdbc:mysql://localhost/数据库实例名称?&useUnicode=true&characterEncoding=utf-8&autoReconnect=true”/>

奥门威尼斯网址 , 

3 修改配置文件

复制代码

 

2、修改参数

sed-i “s/#ClientAliveInterval 0/ClientAliveInterval 60/g” sshd_config

  var mysql = require(‘mysql’),

2.

这两个参数的默认值是8小时。我测试过将这两个参数改为0,结果出人意料,系统自动将这个值设置为1。换句话说,不能将该值设置为永久。我建议为参数值加三个0,这样肯定可以满足我们的应用要求。
 www.2cto.com  

sed -i “s/#ClientAliveCountMax3/ClientAliveCountMax 3/g” sshd_config

      env = {

寻找支持重连的连接池。
           注意:c3p0连接池支持重连;重连参数是:
               idleConnectionTestPeriod   设置空闲连接测试周期
               preferredTestQuery : 设置一查询语句,用于重连测试
              testConnectionOnCheckin设置为true
              testConnectionOnCheckout设置为true

 

4 验证修改结果

        host : ‘localhost’,

 

修改操作:打开/etc/my.cnf,在属性组mysqld下面添加参数如下:

grep”ClientAlive” sshd_config

        user : ‘root’,

在sessionFactory里配置:

[mysqld]

diff sshd_configsshd_config.bak

        password : ‘2212’,

<property name=”hibernateProperties”>
   <props>

interactive_timeout=28800000

奥门威尼斯网址 2

        database : ‘image_marker’

        <prop key=”hibernate.autoReconnect”>true</prop>

wait_timeout=28800000

5 重启服务

      };

  </props>
</property>

 

service sshdrestart

 

windows下在my.ini文中增加:

现在无论空闲多久,SSH客户端都不会自动断开了。

    db = mysql.createConnection(env);

 

参考资料

    db.connect();

interactive_timeout=28800000

如何避免SSH Secure Shell Client连接Linux超时,自动断开?
http://www.linuxidc.com/Linux/2013-02/79940.htm

 

wait_timeout=28800000

SSH 连接超时(ssh timeout) 解决办法
http://www.linuxidc.com/Linux/2013-02/79941.htm

    exports.do = function (sql, callback) {

 

奥门威尼斯网址 3

 

近一段时间,很多部门同事反映在使用mysql的过程出现数据库连接自动断开的问题,我对该问题做了…

      db.query(sql, callback);

 

    }

 

复制代码

MySQL中有一个名叫wait_timeout的变量,表示操作超时时间,当连接超过一定时间没有活动后,会自动关闭该连接,这个值默认为28800(即8小时)。关于普通用法链接丢失后重新链接,请看这里
传送门

 

 

 

2.使用连接池

 

之前我的错误代码,官网上只给出了连接池用法,但是没有给出和请求结合的实例。由于欠缺经验,我认为多个请求使用一个connection比较节省资源。后面发现,connetion经过一段时间后会自动断开,这样问题就出现了。

 

复制代码

pool.getConnection(function (err, connection){

    exports.do = function (sql, callback){

        

        connection.query(sql, function (){

            callback.apply(connection, arguments);

            connection.release();

        });

    }

})

复制代码

google/baidu后发现了一个使用pool的实例

 

 

 

发现他的代码每一次请求都用pool创建一个connection,改进我的代码终于解决了一段时间后connection自动断开的问题。

 

 

 

正确代码为

 

复制代码

pool  = mysql.createPool(env);

 

    exports.do = function (sql, callback){

        this.getConnection(function (err, connection){

            connection.query(sql, function (){

                callback.apply(connection, arguments);

                connection.release();

            });

        })

    }.bind(pool)

复制代码

为每一个请求都建立一个connection使用完后调用connection.release();
直接释放资源。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图