【问题标题】:JDBC optimize MySql request on MultithreadJDBC在多线程上优化MySql请求
【发布时间】:2016-04-17 01:43:05
【问题描述】:

我正在构建一个网络爬虫,我正在寻找处理我的请求以及我的线程和数据库 (MySql) 之间的连接的最佳方式。

我有两种类型的线程:

  1. Fetchers:他们抓取网站。他们生成 url 并将它们添加到 2 个表中:table_url 和 table_file。他们从 table_url 中选择 继续爬行。并更新 table_url 以设置visited=1 当他们 已阅读网址。或者在他们阅读时访问了=-1。他们能 删除行。
  2. 下载器:他们下载文件。他们从 table_file 中选择。他们更新 table_file 以更改 Downloaded 列。他们从不 插入任何东西。

现在我正在处理这个: 我有一个基于c3p0 的连接池。 每个目标(网站)都有这些变量:

private Connection connection_downloader;
private Connection connection_fetcher;

当我实例化一个网站时,我只创建一次这两个连接。然后每个线程将根据他们的目标使用这些连接。

每个线程都有这些变量:

private Statement statement;
private ResultSet resultSet;

在每次查询之前,我都会打开一个 SqlStatement:

public static Statement openSqlStatement(Connection connection){
    try {
        return connection.createStatement();
    } catch (SQLException e) {
        e.printStackTrace();
    }
    return null;
}

在每次查询之后,我都会关闭 sql 语句和 resultSet :

public static  void closeSqlStatement(ResultSet resultSet, Statement statement){
    if (resultSet != null) try { resultSet.close(); } catch (SQLException e) {e.printStackTrace();}
    if (statement != null) try { statement.close(); } catch (SQLException e) {e.printStackTrace();}
}

现在我的 Select 查询只适用于一个选择(我现在不必选择多个,但很快就会改变)并且定义如下:

public static  String sqlSelect(String Query, Connection connection, Statement statement, ResultSet resultSet){
    String result = null;
    try {
        resultSet = statement.executeQuery(Query);
        resultSet.next();
        result = resultSet.toString();
    } catch (SQLException e) {
        e.printStackTrace();
    }
    closeSqlStatement(resultSet, statement);
    return result;
}

插入、删除和更新查询使用此功能:

public static int sqlExec(String Query, Connection connection, Statement statement){
    int ResultSet = -1;
    try {
        ResultSet = statement.executeUpdate(Query);
    } catch (SQLException e) {
        e.printStackTrace();
    }
    closeSqlStatement(resultSet, statement);
    return ResultSet;
}

我的问题很简单:这可以改进得更快吗?而且我担心互斥会阻止一个线程在另一个线程更新链接时更新链接。

【问题讨论】:

    标签: java mysql multithreading jdbc


    【解决方案1】:

    我认为您的设计存在缺陷。为一个网站分配一个全职连接将严重限制您的整体工作量。

    由于您已经设置了连接池,因此可以在使用前获取(然后返回)。

    同样,try-with-catch 用于 关闭 你所有的 ResultSets 和 Statements 之后将使代码更具可读性 - 使用 PreparedStatement 而不是 Statement 不会受到伤害也是。

    一个示例(使用静态 dataSource() 调用访问您的池):

    public static String sqlSelect(String id) throws SQLException {
        try(Connection con = dataSource().getConnection();
            PreparedStatement ps = con.prepareStatement("SELECT row FROM table WHERE key = ?")) {
              ps.setString(1, id);
              try(ResultSet resultSet = ps.executeQuery()) {
                if(rs.next()) {
                  return rs.getString(1);
                } else {
                  throw new SQLException("Nothing found");
                }
              }
        } catch (SQLException e) {
            e.printStackTrace();
            throw e;
        }
    }
    

    按照相同的模式,我建议您也为您的应用程序使用的所有不同的插入/更新/选择创建方法 - 所有这些都仅在数据库逻辑内的短时间内使用连接。

    【讨论】:

    • 你的意思是总是要求一个新的连接比使用一个已经存在的连接更好吗?不是很慢吗?
    • 您使用连接池 - 所以这不是真正的“新”连接,而是“回收”连接。所以你可以在很多很多对象之间共享少量的连接
    • 我使用了一个连接池,认为它会更好,因为我正在构建一个多线程应用程序。我是对的吗?它是否安全(为了数据完整性?)
    • 是的,连接池没问题。关于数据完整性:考虑您需要在 onw 事务 中完成什么,然后使用单个连接将所有代码放入
    • 还有一件事:我永远不必关闭连接?只有 resultSet 和 Statement 吗?
    【解决方案2】:

    我看不出在您的网络爬虫线程中拥有所有数据库内容的真正优势。

    为什么不使用带有 sqlSelect 和 sqlExec 方法的静态类,但不使用 Connection 和 ResultSet 参数。两个连接对象也是静态的。使用前请确保连接对象有效。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-08-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-05-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多