【问题标题】:intermitten java slow query to MySQL对 MySQL 的间歇性 java 慢速查询
【发布时间】:2014-12-16 23:31:04
【问题描述】:

在我用 JAVA 编写的应用服务器中,出现以下症状:

每小时一次或两次,对 MySQL 的查询非常慢(8-10 秒/查询)。

我的服务器查询了2个不同的数据库服务器,它们都有这个症状,但不是同时出现。

为了排除网络原因,我运行了一个网络监视器,它报告应用程序服务器和数据库服务器之间的网络良好。而且,我的应用服务器有4个线程,只有1个线程查询慢,其他3个仍然查询良好。

在两个数据库服务器上,我将连接超时设置为 10s,有一些查询超时(>10s),一些查询没有超时但很慢(查询时间长于 1s,通常是 8s-9s)。

奇怪的是,尽管客户端有慢查询,但数据库服务器端却没有慢查询日志(我配置的慢查询时间是1s)。

这是我用来连接数据库的一段代码:

    public boolean checkSession(String sessionId) {
    Connection conn = null;
    conn = getDBConnection();
    if(conn == null)
        return false;
    try {
        PreparedStatement stm = conn.prepareStatement("SELECT uid FROM sessions WHERE sid=?");
        stm.setString(1, sessionId);
                    ResultSet rs = stm.executeQuery();

        if(rs.next()){
                        if(rs.getInt("uid") == tamtayId){
                            conn.close();
                            return true;
                        }    
        }
        conn.close();
        return false;
    } catch (SQLException e1) {
        e1.printStackTrace();
    }   
    return false;
}
public void setDbConfigString(String str){
    conStr = str;
}
public Connection getDBConnection(){
    Connection conn = null;
    try{
        conn = DriverManager.getConnection(conStr);
    }
    catch (Exception e)  {
        e.printStackTrace();
    }
    return conn;
}

【问题讨论】:

  • 您的所有代码都是正确的。必须与您的 sql 服务器有关
  • 确保SELECT uid FROM sessions WHERE sid=? 使用索引来访问表。用EXPLAIN SELECT uid FROM sessions WHERE sid=?检查它
  • 我想知道你的服务器的内存和垃圾收集设置如何。我有一种直觉,“每小时一次或两次”可能只是正在进行的大量垃圾收集清理。虽然 4 线程测试结果可能与此相矛盾。
  • PS:代码的格式很差。您应该真正关闭结果集和语句,即使连接关闭 - 应该 - 这样做。几行额外的代码,你就做对了。
  • 首先使用连接池,目前每次需要连接时都会创建一个新的连接,然后销毁。如果出现异常,您还可以保持连接打开。理想情况下,您应该在 finally 块中关闭连接和资源。我真的怀疑查询速度很慢,但获得连接需要一段时间。

标签: java mysql performance yslow


【解决方案1】:

你没有使用连接池,所以java服务器会一直连接和断开mysql。 表格中有很多行吗?是否还有其他线程会继续插入?

【讨论】:

  • 我的会话表大约有 20.000 - 30.000 行
【解决方案2】:

我强烈建议使用适当的 JDBC 连接池而不是 DriverManager,后者的缺点是每次需要时都会创建一个新连接,没有池化。通常,创建与数据库的连接是一项冗长的操作。

除了您的代码有缺陷,恕我直言,您的连接在发生异常时保持打开状态,您应该关闭ResultSetPreparedStatement 以及连接。最好在finally 块中。

我建议重写代码如下。

public boolean checkSession(String sessionId) {
    Connection conn = getDBConnection()
    PreparedStatement stm = null;
    ResultSet rs = null;
    boolean val = false;
    try {
        if (conn != null) {
            stm = conn.prepareStatement("SELECT uid FROM sessions WHERE sid=?");
            stm.setString(1, sessionId);
            rs = stm.executeQuery();

            if(rs.next()){
                val = rs.getInt("uid") == tamtayId;
            }
       }
    } catch (SQLException e1) {
        e1.printStackTrace();
    } finally {
        if (rs != null) {
            try {
                rs.close();
            } catch (SQLException e) {}
        }
        if (stm != null) {
            try {
                stm.close();
            } catch (SQLException e) {}
        }
        if (conn != null) {
            try {
                conn.close();
            } catch (SQLException e) {}
        }
    }
    return val;
}

public void setDbConfigString(String str){
    conStr = str;
}

public Connection getDBConnection() throws SQLException {
    return DriverManager.getConnection(conStr);
}

最好设置DataSource,而不是设置dbConfigString,并使用它来获取连接。

public void setDataSource(DataSource ds) {
    this.ds=ds;
}

public void getDBConnection() throws SQLException {
    return ds.getConnection();
}

这样你就可以注入一个合适的连接池,比如Commons DBCPHikariCP

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-03-30
    • 1970-01-01
    • 2016-01-10
    • 1970-01-01
    • 2011-07-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多