簡體   English   中英

即使明確設置,PreparedStatement也不會超時

[英]PreparedStatement won't ever timeout even if explicitly set

我試圖模擬一個場景,我的服務失去了與數據庫的連接,並且不能通過阻止與iptables的連接來執行INSERT ,但我無法使executeQuery()方法超時。

我所做的是為PreparedStatement設置超時,就像這個statement.setQueryTimeout(5) 這是代碼。

HikariConfig config = new HikariConfig();

config.setJdbcUrl("jdbc:mysql://db-url/db");
config.setUsername("user");
config.setPassword("passwd");

config.setMaximumPoolSize(10);
config.setAutoCommit(false);
config.setConnectionTimeout(5000);
config.setDriverClassName("com.mysql.jdbc.Driver");
config.addDataSourceProperty("cachePrepStmts", "true");
config.addDataSourceProperty("prepStmtCacheSize", "250");
config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");
config.addDataSourceProperty("autoReconnect", "true");

final HikariDataSource pool = new HikariDataSource(config);

final String query = "INSERT INTO xtable VALUES (?, ?, ?, ?, ?)";

try ( Connection connection = pool.getConnection() )
{
    try ( PreparedStatement statement = connection.prepareStatement(query) )
    {
        // this is what I expect to work
        statement.setQueryTimeout(5);

        for ( Info info : infos )
        {
            statement.setString(1, info.getValue1());
            statement.setString(2, info.getValue2());
            statement.setString(3, info.getValue3());
            statement.setString(4, info.getValue4());
            statement.setString(5, info.getValue5());

            try
            {
                System.out.println("Waiting");
                Thread.sleep(5000);
                // I use this sleep to ban the database url with iptables
                // to simulate a disconnection
                System.out.println("Waited");
            }
            catch ( InterruptedException e )
            {
                e.printStackTrace();
            }

            System.out.println("Before executeQuery");
            statement.executeQuery();
            // I assumed that this would timeout after 5 seconds
            // But it never reaches the next System.out.print
            System.out.println("After executeQuery");
        }
    }

    System.out.println("Before commit");
    connection.commit();
    System.out.println("After commit");
}
catch ( SQLException e )
{
    log.error("Couldn't execute query", e);
}

輸出將是:

Waiting
Waited
Before executeQuery

然后它永遠掛起......我該怎么辦才能讓它拋出異常?

在try-finally中調用Connection.setNetworkTimeout()

private final static Executor immediateExecutor = Runnable::run;

try ( Connection connection = pool.getConnection() ) {
   int timeout = connection.getNetworkTimeout();
   connection.setNetworkTimeout(immediateExecutor, TimeUnit.SECONDS.toMillis(5));
   ...
   try (PreparedStatement...) {
      ...
   }
   finally {
      connection.setNetworkTimeout(timeout);
   }
}
finally {
   ...
}

您遇到了未確認的TCP流量,如果未設置網絡超時,則可能會掛起連接。

你總能:

try{
     preparedstatement = connection.prepareStatement(query);
     preparedstatement.setQueryTimeout(seconds);
}

而不是你做了什么。 也許這會更好。 同樣的事情是:

Connection connection = pool.getConnection() 

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM