简体   繁体   English

间歇性的java慢查询到MySQL

[英]intermitten java slow query to MySQL

In my application server, which is written in JAVA, I have the following symptom: 在我的应用程序服务器,用JAVA编写,我有以下症状:

Once or twice per hour, the query to MySQL is extremely slow (8-10s/query). 每小时一次或两次,对MySQL的查询非常慢(8-10秒/查询)。

My server queries to 2 different database servers, and both of them have this symptom, but not at the same time. 我的服务器查询2个不同的数据库服务器,它们都有这种症状,但不是同时出现。

To eliminate the cause of network, I run a network monitor, and it reports that the network between application server and database servers is good. 为了消除网络的原因,我运行一个网络监视器,它报告应用服务器和数据库服务器之间的网络是好的。 Moreover, my app server has 4 threads, only 1 thread have slow query, the other 3 still query well. 而且,我的app服务器有4个线程,只有1个线程有慢查询,另外3个仍然查询好。

On both DB servers, I set connection timeout to 10s, there are some queries which timeout (>10s), some queries not timeout but slow (query time longer than 1s, usually 8s-9s). 在两个数据库服务器上,我将连接超时设置为10秒,有些查询超时(> 10秒),有些查询不超时但速度慢(查询时间超过1秒,通常为8秒-9秒)。

1 strange thing is, despite there are slow query on client side, there is no slow query log on database server side (I config slow query time is 1s). 1奇怪的是,尽管客户端的查询速度很慢,但数据库服务器端没有慢查询日志(我配置慢查询时间为1秒)。

Here is a piece of my code that I'm using to connect to DB: 这是我用来连接数据库的一段代码:

    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;
}

You did not use a connection pool, so the java server will keep connecting and disconnecting mysql. 您没有使用连接池,因此java服务器将继续连接和断开mysql。 Are there many lines in the table? 表中有很多行吗? Is there some other thread will keep inserting? 还有其他一些线程会继续插入吗?

I would strongly suggest to use a proper JDBC Connection Pool instead of the DriverManager , the drawback of the latter is that it creates a new connection each time one is needed, there is no pooling. 我强烈建议使用正确的JDBC连接池而不是DriverManager ,后者的缺点是每次需要时都会创建一个新连接,没有池。 Creating a connection with the database is, generally, a lengthy operation. 通常,与数据库建立连接是一项冗长的操作。

Next to that your code is flawed, imho, your connection remains open in case of an exception and you should close the ResultSet and PreparedStatement as well as the connection. 除此之外,您的代码存在缺陷,imho,如果出现异常,您的连接仍会保持打开状态,您应该关闭ResultSetPreparedStatement以及连接。 Preferably in a finally block. 优选地,在finally块中。

I suggest rewriting the code as follows. 我建议重写代码如下。

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);
}

Instead of setting the dbConfigString you should set the DataSource ideally and use that for obtaining connections. 您应该理想地设置DataSource并使用它来获取连接,而不是设置dbConfigString

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

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

That way you can inject a proper connection pool like Commons DBCP or HikariCP . 这样你就可以注入一个像Commons DBCPHikariCP这样的连接池。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM