半多线程 JDBC 连接

问题描述 投票:0回答:3

我有以下 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();
    }
}
java mysql multithreading jdbc
3个回答
2
投票

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

所以先打电话

result.next();


2
投票

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

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

因此,在准备新的语句对象之前,您需要关闭旧的语句对象。


statement.close()

声明= 联系 .prepareStatement("从

ID
中选择 COUNT(
Missile
) ,其中
WarName
= ?");


最后您需要关闭该语句。


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

statement.close()


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


0
投票

我经历的是,在MSSQLSERVER上,我创建了多个共享同一个Connection对象的java线程,其中一个线程创建了一个带有标识列的临时表,然后线程读取表的不同部分(通过过滤标识列)并它是并行工作的。同样的方法不能在 Oracle 上并行工作,只是按照服务器排列的连续顺序,尽管在这种情况下,具有不同 Connection 对象实例的线程能够在同一个表(不是临时表)上并行运行选择查询。所以答案是这取决于数据库类型。

© www.soinside.com 2019 - 2024. All rights reserved.