如何设置数据库的连接数和连接超时时间

如何设置数据库的连接数和连接超时时间,第1张

以spring+mybatis为例

1.配置datasource时指定如下信息

2.读取properties下的所有配置文件

3.jdbc.properties文件内容如下:

1.首先将标志位设为Non-blocking模式,准备在非阻塞模式下调用connect函数

2.调用connect,正常情况下,因为TCP三次握手需要一些时间;而非阻塞调用只要不能立即完成就会返回错误,所以这里会返回EINPROGRESS,表示在建立连接但还没有完成。

3.在读套接口描述符集(fd_set rset)和写套接口描述符集(fd_set

wset)中将当前套接口置位(用FD_ZERO()、FD_SET()宏),并设置好超时时间(struct

timeval *timeout)

4.调用select( socket, &rset, &wset, NULL, timeout )

返回0表示connect超时

如果你设置的超时时间大于75秒就没有必要这样做了,因为内核中对connect有超时限制就是75秒。

网络编程中socket的分量我想大家都很清楚了,socket也就是套接口,在套接口编程中,提到超时的概念,我们一下子就能想到3个:发送超时,接收超时,以及select超时(注:

select

函数并不是只用于套接口的,但是套接口编程中用的比较多),在connect到目标主机的时候,这个超时是不由我们来设置的。不过正常情况下这个超时都很

长,并且connect又是一个阻塞方法,一个主机不能连接,等着connect返回还能忍受,你的程序要是要试图连接多个主机,恐怕遇到多个不能连接的

主机的时候,会塞得你受不了的。我也废话少说,先说说我的方法,如果你觉得你已掌握这种方法,你就不用再看下去了,如果你还不了解,我愿意与你分享。本文

是已在Linux下的程序为例子,不过拿到Windows中方法也是一样,无非是换几个函数名字罢了。

Linux中要给connect设置超时,应该是有两种方法的。一种是该系统的一些参数,这个方法我不讲,因为我讲不清楚:P,它也不是编程实现的。另外一种方法就是变相的实现connect的超时,我要讲的就是这个方法,原理上是这样的:

1.建立socket

2.将该socket设置为非阻塞模式

3.调用connect()

4.使用select()检查该socket描述符是否可写(注意,是可写)

5.根据select()返回的结果判断connect()结果

6.将socket设置为阻塞模式(如果你的程序不需要用阻塞模式的,这步就省了,不过一般情况下都是用阻塞模式的,这样也容易管理)

如果你对网络编程很熟悉的话,其实我一说出这个过程你就知道怎么写你的程序了,下面给出我写的一段程序,仅供参考。

/******************************

* Time out for connect()

* Write by Kerl W

******************************/

#include

#include

#define TIME_OUT_TIME 20 //connect超时时间20秒

int main(int argc , char **argv)

{

………………

int sockfd = socket(AF_INET, SOCK_STREAM, 0)

if(sockfd <0) exit(1)

struct sockaddr_in serv_addr

………//以服务器地址填充结构serv_addr

int error=-1, len

len = sizeof(int)

timeval tm

fd_set set

unsigned long ul = 1

ioctl(sockfd, FIONBIO, &ul)//设置为非阻塞模式

bool ret = false

if( connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) ==

-1)

{

tm.tv_set = TIME_OUT_TIME

tm.tv_uset = 0

FD_ZERO(&set)

FD_SET(sockfd, &set)

if( select(sockfd+1, NULL, &set, NULL, &tm) >0)

{

getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, (socklen_t *)&len)

if(error == 0) ret = true

else ret = false

} else ret = false

}

else ret = true

ul = 0

ioctl(sockfd, FIONBIO, &ul)//设置为阻塞模式

if(!ret)

{

close( sockfd )

fprintf(stderr , "Cannot Connect the server!n")

return

}

fprintf( stderr , "Connected!n")

//下面还可以进行发包收包 *** 作

……………

}

以上代码片段,仅供参考,也是为初学者提供一些提示,主要用到的几个函数,select,

ioctl,

getsockopt都可以找到相关资料,具体用法我这里就不赘述了,你只需要在linux中轻轻的敲一个man

<函数名>就能够看到它的用法。

此外我需要说明的几点是,虽然我们用ioctl把套接口设置为非阻塞模式,不过select本身是阻塞的,阻塞的时间就是其超时的时间由调用select

时候的最后一个参数timeval类型的变量指针指向的timeval结构变量来决定的,timeval结构由一个表示秒数的和一个表示微秒数(long

类型)的成员组成,一般我们设置了秒数就行了,把微妙数设为0(注:1秒等于100万微秒)。而select函数另一个值得一提的参数就是上面我们用到的

fd_set类型的变量指针。调用之前,这个变量里面存了要用select来检查的描述符,调用之后,针对上面的程序这里面是可写的描述符,我们可以用宏

FD_ISSET来检查某个描述符是否在其中。由于我这里只有一个套接口描述符,我就没有使用FD_ISSET宏来检查调用select之后这个

sockfd是否在set里面,其实是需要加上这个判断的。不过我用了getsockopt来检查,这样才可以判断出这个套接口是否是真的连接上了,因为

我们只是变相的用select来检查它是否连接上了,实际上select检查的是它是否可写,而对于可写,是针对以下三种条件任一条件满足时都表示可写

的:

1)套接口发送缓冲区中的可用控件字节数大于等于套接口发送缓冲区低潮限度的当前值,且或者i)套接口已连接,或者ii)套接口不要求连接(UDP方式的)

2)连接的写这一半关闭。

3)有一个套接口错误待处理。

这样,我们就需要用getsockopt函数来获取套接口目前的一些信息来判断是否真的是连接上了,没有连接上的时候还能给出发生了什么错误,当然我程序中并没有标出那么多状态,只是简单的表示可连接/不可连接。

下面我来谈谈对这个程序测试的结果。我针对3种情形做了测试:

1. 目标机器网络正常的情况

可以连接到目标主机,并能成功以阻塞方式进行发包收包作业。

2. 目标机器网络断开的情况

在等待设置的超时时间(上面的程序中为20秒)后,显示目标主机不能连接。

3. 程序运行前断开目标机器网络,超时时间内,恢复目标机器的网络

在恢复目标主机网络连接之前,程序一只等待,恢复目标主机后,程序显示连接目标主机成功,并能成功以阻塞方式进行发包收包作业。

上各种情况的测试结果表明,这种设置connect超时的方法是完全可行的。我自己是把这种设置了超时的connect封装到了自己的类库,用在一套监控

系统中,到目前为止,运行还算正常。这种编程实现的connect超时比起修改系统参数的那种方法的有点就在于它只用于你的程序之中而不影响系统。

connect非阻塞套接口时候,一般使用在以下几种情况:

1.三路握手需要时间,这个要视具体的网络情况而定。当然也有可能失败。在三路握手的时候我们并不需要在原地等待三路握手的完成,可以用这些时间来

完成其它事情,然后当这些事情完成后,再去检测连接是否建立(也就是三路握手是否完成)。

2.可以用这种技术来同时建立多个连接。(WEB浏览器中很常用)。

3.connect超时需要很长时间才会通知,如果我们认为超过0.1秒以后就算超时(不管它是不是真的超时),这是就可以使用非阻塞式I/O结合

select来完成。

当采用非阻塞式I/O来使用connect时候,要判断一个连接是否建立则比较复杂,需要按照以下几个步骤来完成

1.即使是使用非阻塞式的connect *** 作,connect依然可能正确返回,也就是说非阻塞的connect

也有可能三路连接完成后返回,这种情况一般发生在服务器和主机在同一个机器上,所以第一步要判断connect是否正确返回,如果正确返回则请做正确返回

的处理,否则进入步骤2

2.设置fd_set,(如果没看明白,请先看select函数介绍),让select函数同时监听套接字的读写2个属性,如果既可读也可写则进入

步骤3,如果可写但不可读进入步骤4.

3.如果到达这步,我们需要调用getsockopt进一步判断。这里涉及到一个移植问题,getsockopt如果发生错误,

源自Berkeley的实现会返回0,如果是solaris,则会返回-1。建议是2个都处理(如果看不明白请先看getsockopt函数,套接口选

项)。根据getsockopt通过参数返回的erron的值,如果值为0则表示链接建立完成,如果不为0, 则说明链接建立没有完成。

4.如果能到达这里,则说明连接建立完成。

最后,即使最后你得出链接没有建立完成,也只是说:可能三路握手的过程还是没有完成。

MySQL查询超时的设置方法

为了优化OceanBase的query timeout设置方式,特调研MySQL关于timeout的处理,记录如下。

[plain]

mysql>show variables like '%time%'

+----------------------------+-------------------+

| Variable_name | Value |

+----------------------------+-------------------+

| connect_timeout| 10|

| datetime_format| %Y-%m-%d %H:%i:%s |

| delayed_insert_timeout | 300 |

| flush_time | 1800 |

| innodb_lock_wait_timeout | 50|

| innodb_old_blocks_time | 0 |

| innodb_rollback_on_timeout | OFF |

| interactive_timeout| 28800 |

| lc_time_names | en_US |

| lock_wait_timeout | 31536000 |

| long_query_time| 10.000000 |

| net_read_timeout | 30|

| net_write_timeout | 60|

| slave_net_timeout | 3600 |

| slow_launch_time | 2 |

| system_time_zone | |

| time_format| %H:%i:%s |

| time_zone | SYSTEM|

| timed_mutexes | OFF |

| timestamp | 1366027807|

| wait_timeout | 28800 |

+----------------------------+-------------------+

21 rows in set, 1 warning (0.00 sec)

重点解释其中几个参数:

connect_timeout:

The number of seconds that the mysqld server waits for a connect packet before respondingwith Bad handshake. The default value is 10 seconds as of MySQL 5.1.23 and 5 seconds before that. Increasing the connect_timeout value might help if clients frequently encounter errors of the form Lost connection to MySQL server at ‘XXX’, system error: errno.

解释:在获取链接时,等待握手的超时时间,只在登录时有效,登录成功这个参数就不管事了。主要是为了防止网络不佳时应用重连导致连接数涨太快,一般默认即可。

interactive_timeout:

The number of seconds the server waits for activity on an interactive connection before closing it. An interactive client is defined as a client that uses the CLIENT_INTERACTIVE option to mysql_real_connect(). See alsowait_timeout.

解释:一个持续SLEEP状态的线程多久被关闭。线程每次被使用都会被唤醒为acrivity状态,执行完Query后成为interactive状态,重新开始计时。wait_timeout不同在于只作用于TCP/IP和Socket链接的线程,意义是一样的。

MySQL可以配置连接的超时时间,这个时间如果做得太长,甚至到了10min,那么很可能发生这种情况,3000个链接都被占满而且sleep在哪,新链接进不来,导致无法正常服务。因此这个配置尽量配置一个符合逻辑的值,60s或者120s等等。

说人话:

命令行下面敲一个命令后,直至下一个命令到来之前的时间间隔为interactive_time,如果这个时间间隔超过了interactive_timeout,则连接会被自动断开,下一个命令失败。不过一般的mysql客户端都有自动重连机制,下一个命令会在重连后执行。

[sql]

mysql>set interactive_timeout = 1

Query OK, 0 rows affected (0.00 sec)

mysql>show session variables like '%timeout%'

+----------------------------+----------+

| Variable_name | Value|

+----------------------------+----------+

| connect_timeout| 10 |

| interactive_timeout| 1|

| wait_timeout | 28800|

+----------------------------+----------+

10 rows in set (0.00 sec)

=====

[sql]

mysql>set wait_timeout = 1

Query OK, 0 rows affected (0.00 sec)

【去泡杯茶,等会儿】

mysql>show session variables like '%timeout%'

ERROR 2006 (HY000): MySQL server has gone away

No connection. Trying to reconnect...

Connection id:7

Current database: *** NONE ***

+----------------------------+----------+

| Variable_name | Value|

+----------------------------+----------+

| connect_timeout| 10 |

| interactive_timeout| 28800|

| wait_timeout | 28800|

+----------------------------+----------+

10 rows in set (0.01 sec)

wait_timeout:

The number of seconds the server waits for activity on a noninteractive connection (连接上没有活动命令,可能是客户端喝咖啡去了。)before closing it. Before MySQL 5.1.41, this timeout applies only to TCP/IP connections, not to connections made through Unix socket files, named pipes, or shared memory.

On thread startup, the session wait_timeout value is initialized from the global wait_timeout value or from the global interactive_timeout value, depending on the type of client

这里顺带解释一下什么是non-interactive connection

>Non-Interactive Commands

Just do a quick look up on a table without logging into the client, running the query then logging back out again.

You can instead just type one line using the ' -e ' flag.

[sql]

c:\mysql\bin\mysql -u admin -p myDatabase -e 'SELECT * FROM employee'

net_read_timeout / net_write_timeout

The number of seconds to wait for more data from a connection before aborting the read. Before MySQL 5.1.41, this timeout applies only to TCP/IP connections, not to connections made through Unix socket files, named pipes, or shared memory. When the server is reading from the client, net_read_timeout is the timeout value controlling when to abort. When the server is writing to the client, net_write_timeout is the timeout value controlling when to abort. See also slave_net_timeout.

On Linux, the NO_ALARM build flag affects timeout behavior as indicated in the description of the net_retry_count system variable.

解释:这个参数只对TCP/IP链接有效,分别是数据库等待接收客户端发送网络包和发送网络包给客户端的超时时间,这是在Activity状态下的线程才有效的参数

JDBC setQueryTimeout函数:

为了避免查询出现死循环,或时间过长等现象,而导致线程阻塞,在获得Statement的实例后,stmt.setQueryTimeout(10)避免因为查询导致程序出现线程阻塞。

但昨天发现程序出现了,“ORA-01013: 用户请求取消当前的 *** 作”的异常。手工执行出错SQL语句发现,这个语句耗时20多秒。因为setQueryTimeout(10),所以还没有执行完查询语句就抛出异常了。使用setQueryTimeout(10)时一定要把时间设置的长一些,如60秒以上。只要不导致线程长期阻塞,就可以。太短了容易抛出,“ORA-01013: 用户请求取消当前的 *** 作”的异常

JDBC实现setQueryTimeout的原理:

[java]

class IfxCancelQueryImpl extends TimerTask

implements IfmxCancelQuery

{

IfxStatement stmt

Timer t = null

public void startCancel(IfxStatement paramIfxStatement, int paramInt)

throws Exception

{

this.stmt = paramIfxStatement

this.t = new Timer(true)

this.t.schedule(this, paramInt * 1000)

}

public void run()

{

try

{

this.stmt.cancel()

this.t.cancel()

}

catch (SQLException localSQLException)

{

this.t.cancel()

throw new Error(localSQLException.getErrorCode() + ":" + localSQLException.getMessage())

}

}

}


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/sjk/9962625.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-03
下一篇 2023-05-03

发表评论

登录后才能评论

评论列表(0条)

保存