【发布时间】:2015-06-09 08:02:51
【问题描述】:
我的应用同时使用Mysql和Postgres,web服务器是tomcat 7.0。应用程序运行一段时间后,如 15、16 小时,它丢失了 mysql 连接池,并且我在日志中收到“无法获取连接,池错误超时等待空闲对象”错误消息。所以我需要启动tomcat来重新启动应用程序以再次重新连接到Mysql连接池。我在完成查询后关闭每个连接。这在 Postgres 上从来没有发生过,只是在 Mysql 上,所以……很奇怪。
我使用 Singleton 连接到 Mysql 和 Postgres 的连接池。下面是Mysql的代码。
public class DB {
private static DB database = new DB();
private DataSource ds;
private DB() {
try {
InitialContext ic = new InitialContext();
ds = (DataSource)ic.lookup("java:comp/env/jdbc/mobile_recharge");
} catch(Exception e) {
e.printStackTrace();
}
}
public static DB getInstance() {
return database;
}
public DataSource getDS() throws SQLException {
return ds;
}
}
其中一个查询:
public boolean preSaveData(HashMap<String, String> mapXML, String date, String serialNum) {
try {
con = open();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
log.writeLog(mapXML.get("terminalId"), mapXML.get("date_time"), "fails to insert order info into mysql: " + e.getMessage());
return false;
}
String table = new JudgeTidField().table(mapXML.get("tidField"));
String query = "insert into " + table + " (Terminal_id, Yewu, Phone_number, Company, " +
"Order_money, Balance, Actual_money, Order_record_date, Recharge_record_date, Province, Serial_number) values " +
"(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);";
try {
presta = (PreparedStatement) con.prepareStatement(query);
presta.setString(1, mapXML.get("terminalId"));
presta.setString(2, "recharge");
presta.setString(3, mapXML.get("phoneNum"));
presta.setString(4, mapXML.get("type"));
presta.setFloat(5, Float.parseFloat(mapXML.get("price")));
presta.setFloat(6, (float) 0.000);
presta.setFloat(7, Float.parseFloat(mapXML.get("actualMoney")));
presta.setString(8, date);
presta.setString(9, date);
presta.setString(10, mapXML.get("province"));
presta.setString(11, serialNum);
presta.executeUpdate();
log.writeLog(mapXML.get("terminalId"), mapXML.get("date_time"), "success to insert order info into mysql");
return true;
} catch (SQLException e) {
e.getMessage();
log.writeLog(mapXML.get("terminalId"), mapXML.get("date_time"), "fail to insert order info into mysql: " + e.getMessage());
return false;
} finally {
try {
presta.close();
} catch (SQLException e1) {
e1.printStackTrace();
}
try {
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
在 context.xml 中:
<Context docBase="Mobile" path="/Mobile" reloadable="true">
<Resource
name="jdbc/mobile_recharge"
auth="Container"
type="javax.sql.DataSource"
maxActive="500"
maxIdle="5"
maxWait="5000"
driverClassName="com.mysql.jdbc.Driver"
username="root"
password="xxxxxxxx"
url="jdbc:mysql://xxx.xxx.x.xxx:3306/mobile_recharge?characterEncoding=utf8" />
<Resource
name="jdbc/pgsql"
type="javax.sql.DataSource"
maxActive="500"
maxIdle="2"
username="postgres"
maxWait="5000"
driverClassName="org.postgresql.Driver"
password="xxxxxxxx"
url="jdbc:postgresql://xxx.xxx.x.xxx:5555/runningacounts"/>
</Context>
在 web.xml 中:
<resource-ref>
<description>MysqlDB Connection</description>
<res-ref-name>jdbc/mobile_recharge</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
<resource-ref>
<description>PGDB Connection</description>
<res-ref-name>jdbc/pgsql</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
【问题讨论】:
-
您的应用服务器和数据库服务器之间有防火墙吗?
-
假设你连接到MySQL服务器做得很好,你确定你在使用连接对象后释放了对象引用吗?否则池继续创建并达到maxActive,然后无法再创建一个。此外,maxActive=500?您已经调整 MySQL 以允许 500 个活动连接?默认值为 151。
-
肯回答表明您已达到 maxActive 限制:根据您的代码,Connection 对象“con”和 PreparedStatement“presta”是成员字段。尽量使用局部变量,如果JDK1.7的可用try-with语句对每个Closeable类进行说明。
-
(我问防火墙的原因是因为如果一段时间不使用连接可能会失去状态)
-
@Alastair McCormack 应用服务器和数据库服务器之间没有防火墙