引言:昨天晚上做了个激活服务,然后测试没问题,今天早上重新测了下,发现报异常,链接不上数据库.
先说一下发生这个Exception的大致原因:
MySQL的配置中,有一个叫做“wait_timeout"的参数,这个参数大致的意思是这样:当一个客户端连接到MySQL数据库后,如果客户端不自己断开,也不做任何操作,MySQL数据库会将这个连接保留"wait_timeout"这么长时间(单位是s,默认是28800s,也就是8小时),超过这个时间之后,MySQL数据库为了节省资源,就会在数据库端断开这个连接;当然,在此过程中,如果客户端在这个连接上有任意的操作,MySQL数据库都会重新开始计算这个时间。
这么看来,发生上面Exception的原因就是因为我的服务器和MySQL数据库的连接超过了”wait_timeout"时间,MySQL服务器端将其断开了,但是我的程序再次使用这个连接时没有做任何判断,所以就挂了。
那这个问题怎么解决呢?
查了下网上的资料,其中详细点的如下:
第一个问题:我们的服务器曾经在设计的过程中考虑过这个事情,所以服务器的主线程有一个定时的check机制,每隔半小时会发送一个"select 1"到数据库来保证连接是活动的,为什么这个check机制不起作用了呢?
第二个问题:从上面的Exception中可以得到这么一个信息:
[java] view plaincopy
The last packet sent successfully to the server was 43200 milliseconds ago, which is longer than the server configured value of 'wait_timeout'. 这个信息说的很明白,最后一个成功发到Server的包是43200毫秒之前。但是43200毫秒才43.2秒,也就是说我们的服务器43.2秒之前才和MySQL服务器通过信,怎么会发生超过”wait_timeout“的问题呢?而且MySQL数据库的配置也确实是28800秒(8小时),这又是神马情况呢?[html] view plaincopy
程序中更新的过程大致是这样: [java] view plaincopy
session = org.hibernate.SessionFactory.openSession();
transaction = session.beginTransaction();
session.update(something);
transaction.commit();
session.close(); 在这里,所有关于数据库Connection的连接和关闭都在Hibernate中,因此,不去挖掘Hibernate的源码是不可能了。[html] view plaincopy
上面配置中最重要的就是hibernate.c3p0.testConnectionOnCheckout这个属性,它保证了我们前面说的每次取出连接时会检查该连接是否被关闭了。不过这个属性会对性能有一些损耗,引用我参考的博客上得话:程序能用是第一,之后才是它的性能(又不是不能容忍)。
当然,c3p0自带类似于select 1这样的check机制,但是就像我说的,除非你将check机制的间隔时间把握的非常好,否则,问题是没有解决的。
好了,至此,困扰我的问题解决完了。希望上面的这些整理可以为我以后碰到类似的问题留个思路,也可以为正在被此问题困扰的人提供一丝帮助。
最后补充点东西:
1,一些c3p0的属性方法总结:
datasource.c3p0.acquireIncrement=10当连接池中的连接用完时,C3P0一次性创建新连接的数目;
datasource.c3p0.minPoolSize=50连接池中保留的最小连接数。默认为15
datasource.c3p0.maxPoolSize=400连接池中保留的最大连接数。默认为15;
datasource.c3p0.initialPoolSize=50初始化时创建的连接数,应在minPoolSize与maxPoolSize之间取值。默认为3;
datasource.c3p0.maxIdleTime=1800最大空闲时间,超过空闲时间的连接将被丢弃。为0或负数则永不丢弃。默认为0;
datasource.c3p0.acquireRetryAttempts=100定义在从数据库获取新连接失败后重复尝试获取的次数,默认为30;
datasource.c3p0.acquireRetryDelay=20两次连接中间隔时间,单位毫秒,默认为1000;
datasource.c3p0.debugUnreturnedConnectionStackTraces=true
datasource.c3p0.maxStatements=0JDBC的标准参数,用以控制数据源内加载的PreparedStatement数量。但由于预缓存的Statement属 于单个Connection而不是整个连接池。所以设置这个参数需要考虑到多方面的因素,如果maxStatements与 maxStatementsPerConnection均为0,则缓存被关闭。默认为0;
datasource.c3p0.idleConnectionTestPeriod=1800隔多少秒检查所有连接池中的空闲连接,默认为0表示不检查;
datasource.c3p0.breakAfterAcquireFailure=true获取连接失败将会引起所有等待获取连接的线程抛出异常。但是数据源仍有效保留,并在下次调 用getConnection()的时候继续尝试获取连接。如果设为true,那么在尝试获取连接失败后该数据源将申明已断开并永久关闭。默认为 false;
datasource.c3p0.testConnectionOnCheckout=false因性能消耗大请只在需要的时候使用它。如果设为true那么在每个connection提交的时候都 将校验其有效性。建议使用idleConnectionTestPeriod或automaticTestTable
datasource.c3p0.autoCommitOnClose=true连接关闭时默认将所有未提交的操作回滚。默认为false;
datasource.c3p0.maxStatementsPerConnection=100连接池内单个连接所拥有的最大缓存Statement数。默认为0;
2,本问题中,再多加入
3,记得添加两个jar包:我添加的版本是c3p0-0.9.2.1.jar和mchange-commons-java-0.2.3.4.jar
若后面有新的问题 随时补充.