【问题标题】:Semi-Multi threaded JDBC connection半多线程 JDBC 连接
【发布时间】:2014-12-10 21:06:19
【问题描述】:

我有以下 Callable 实例,这里抛出了 SQLException:

public long[] call() throws Exception {
    long[] stats = new long[6];
    try {
        executer.acquire();
        PreparedStatement statement =
            connection
                .prepareStatement("SELECT `War`.`EndTime` FROM `WarSim`.`War` WHERE `War`.`WarName` = ?");
        statement.setString(1, warName);
        ResultSet res = statement.executeQuery(); //<--------------SQLEXCEPTION HERE
        if (res.first()) {
        Timestamp ts = res.getTimestamp("EndTime");
        if (ts != null)
            stats[0] = 1;
        statement =
            connection
                .prepareStatement("SELECT COUNT(`ID`) FROM `Missile` WHERE `WarName` = ?");
        statement.setString(1, warName);
        res = statement.executeQuery();
        stats[1] = res.getInt(1);
        statement =
            connection
                .prepareStatement("SELECT COUNT(`ID`) FROM `Missile` WHERE `WarName` =  ?  AND `Intercepted` = '1'");
        statement.setString(1, warName);
        res = statement.executeQuery();
        stats[2] = res.getInt(1);
        stats[3] = stats[1] - stats[2];
        statement =
            connection
                .prepareStatement("SELECT COUNT(`ID`) FROM `EnemyLauncher` WHERE `WarName` = ? AND `Intercepted` = '1'");
        statement.setString(1, warName);
        res = statement.executeQuery();
        stats[4] = res.getInt(1);
        statement =
            connection
                .prepareStatement("SELECT SUM(`Damage`) FROM `Missile` WHERE `WarName` =  ? AND `Intercepted` = '0'");
        statement.setString(1, warName);
        res = statement.executeQuery();
        stats[5] = res.getInt(1);
        }
    } catch (SQLException e) {
        System.out.println(warName + " is problematic");
        while (e != null) {
        System.out.println("\tmsg: " + e.getMessage()+
                       "\n\tstate: " + e.getSQLState());
        e = e.getNextException();
        }
    } catch (InterruptedException e) {
        e.printStackTrace();
    } finally {
        executer.release();
    }
    return stats;
    }

executer 是我使用的单一许可、公平信号量。

当我调试代码时,一切正常(没有例外),但是当我“正常”运行程序时,我得到了“结果集开始”SQLException 以及 SQLState S1000。

即使我使用信号量获取要查询的互斥体,我怎么会出现异常?

请帮忙:)

编辑:这是堆栈跟踪。

java.sql.SQLException: Before start of result set

    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1075)
    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:989)
    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:984)
    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:929)
    at com.mysql.jdbc.ResultSetImpl.checkRowPos(ResultSetImpl.java:841)
    at com.mysql.jdbc.ResultSetImpl.getInt(ResultSetImpl.java:2672)
    at db.jdbc.GetWarStatsTask.call(GetWarStatsTask.java:37)
    at db.jdbc.GetWarStatsTask.call(GetWarStatsTask.java:1)
    at java.util.concurrent.FutureTask.run(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at java.lang.Thread.run(Unknown Source)

处理数据库连接的类:

public class JDBCConnection implements DBConnection {

    private Connection connection;
    private String dbUrl;
    private Semaphore executer;
    private ExecutorService es;
    private static JDBCConnection instance;

    public static JDBCConnection getInstance() {
    if (instance == null) {
        instance = new JDBCConnection();
    }
    return instance;
    }

    private JDBCConnection() {
    dbUrl = "jdbc:mysql://---------/WarSim";
    try {
        Class.forName("com.mysql.jdbc.Driver").newInstance();
        connection =
            DriverManager.getConnection(dbUrl, "------", "-------");
    } catch (InstantiationException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    } catch (SQLException e) {
        while (e != null) {
        System.out.println(e.getMessage());
        e = e.getNextException();
        }
    }
    es = Executors.newCachedThreadPool();
    executer = new Semaphore(1, true);
    }

    public Future<long[]> getWarStats(String warName) {
    return es.submit(new GetWarStatsTask(executer, connection, warName));
    }

    public void closeDB() {
    try {
     if (connection != null) {
        connection.close();
     }
    } catch (Exception e) {
        System.out.println("Could not close the current connection.");
        e.printStackTrace();
    }
}

【问题讨论】:

  • 你能发布堆栈跟踪的前几行吗?
  • 添加到问题正文谢谢。
  • 您的结果集何时关闭,连接何时关闭?也许这是内存泄漏的症状。
  • 在你的问题中你说:"When I debug the code, everything works perfectly (no exceptions), yet when I run the program "normally" I get the "start of result set" SQLException thrown along with SQLState S1000." 当你“正常”运行它时你有什么不同。你如何产生线程并清理它们?
  • 线程是通过 Executor 产生的。我会添加信息

标签: java mysql multithreading jdbc


【解决方案1】:

基本上,您将光标定位在第一行之前,然后请求数据。您需要将光标移动到第一行。

所以先打电话result.next();

【讨论】:

  • 张贴者指出,调试时一切正常,但负载不高。调试的时候肯定会出问题。
  • 正如 Andreas 所说,这不是问题所在。我还在 if 语句中使用了 res.first()。
  • 试试 if(result.next()){do stuff}
  • 如我所述,statement.executeQuery(); 之后会引发异常。使用 System.out 对其进行跟踪。
  • 在我意识到你的意思之后,这正是我的问题。需要在每个语句之后调用 result.next()。谢谢!
【解决方案2】:

通过使用信号量,您了解了 JDBC 规则,即一次只能由单个线程使用连接。但是,您需要注意其他线程,即垃圾收集器线程。

在这种情况下,您需要在释放信号量之前关闭所有创建的语句对象。如果您不关闭语句对象,它们将被垃圾收集器线程在不确定的时间关闭,从而导致连接出现异常行为。

所以,在你准备一个新的语句对象之前,你需要关闭旧的。


statement.close()

声明 = 联系 .prepareStatement("SELECT COUNT(ID) FROM Missile WHERE WarName = ?");


最后你需要关闭语句。


stats[5] = res.getInt(1);

statement.close()


您可能想练习在您的代码上运行“findbugs”。我认为这可能已经发现了没有关闭 Statement 对象的问题。

【讨论】:

  • 感谢您的帮助,我了解到只要您在本地而不是在静态上下文中使用该语句,这并不重要。在调用 getInt() 之前,我已经使用 result.next() 解决了这个问题
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-06-13
  • 1970-01-01
  • 1970-01-01
  • 2015-12-31
  • 1970-01-01
  • 2010-11-15
  • 2012-11-18
相关资源
最近更新 更多