有有時像這樣使用SQL Server時的錯誤:立即創建SQL Server死鎖的最小Java JDBC程序?
Transaction (Process ID 54) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction.
欲瞭解更多的背景,查了一下傑夫·阿特伍德有blogged這個問題。
我想通過使用普通JDBC的小型測試以編程方式創建SQL Server死鎖。測試應該立即創建一個死鎖,以便我可以測試一些重試邏輯。
我從傑夫的分析中得出的理解是,我只需要一些數據並閱讀很多內容,然後寫一點。
我目前有一個簡短的Java程序(如下),它創建一個表並將一些測試數據寫入表中。他們的程序啓動了幾百個線程。每個線程要麼進行更新,要麼讀取測試數據。我已經改變了更新與讀取操作的比率,但不管比率如何,我似乎無法以編程方式創建死鎖。這個版本的測試程序沒有我的重試邏輯,我會補充說,一旦我可以可靠地發生SQL Server死鎖。我想知道在單個進程中運行的所有線程是否可能以某種方式在JDBC驅動程序級別上序列化操作,因此我試着同時運行多個進程(在同一臺機器上),但仍然沒有死鎖。
import java.sql.*;
import java.util.*;
import java.util.concurrent.*;
import static java.util.concurrent.TimeUnit.*;
public class Deadlock {
static final int QUERY_THREAD_COUNT = 300, MAX_OPERATIONS_ITERATION = 5000;
static String server, db, user, pw;
static CountDownLatch latch = new CountDownLatch(QUERY_THREAD_COUNT);
public static void main(String... args) throws Exception {
server = args[0];
db = args[1];
user = args[2];
pw = args[3];
Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
Connection connection = getConnection();
Statement statement = connection.createStatement();
statement.execute("CREATE TABLE TESTTABLE (BAR INTEGER, BAZ VARCHAR(32))");
statement.execute("DELETE FROM TESTTABLE");
statement.execute("INSERT INTO TESTTABLE VALUES (1, 'FOOBARBAZ')");
connection.setAutoCommit(false);
connection.commit();
connection.close();
ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
for (int i = 0; i < QUERY_THREAD_COUNT; ++i) {
scheduledExecutorService.scheduleWithFixedDelay(new Operation(), 0, 1, MILLISECONDS);
}
latch.await();
System.exit(0);
}
static class Operation implements Runnable {
Connection connection = getConnection();
Statement statement = getStatement(connection);
int iteration;
@Override
public void run() {
if (++iteration > MAX_OPERATIONS_ITERATION) {
latch.countDown();
return;
}
try {
double random = Math.random();
boolean update = (random < 0.01);
if (update) {
statement.executeUpdate("UPDATE TESTTABLE SET BAR=" + ((int) (random * 100)) + " WHERE BAZ='FOOBARBAZ'");
} else {
ResultSet rs = statement.executeQuery("SELECT BAR, BAZ FROM TESTTABLE");
if (! rs.next()) {
return;
}
int bar = rs.getInt(1);
String baz = rs.getString(2);
if (bar > 100) {
System.err.println("int is greater than 100");
}
if (! baz.equals("FOOBARBAZ")) {
System.err.println("string is not FOOBARBAZ");
}
}
connection.commit();
} catch (SQLException sqle) { // <-- looking for a deadlock exception here!
System.err.println(sqle);
}
}
}
static Connection getConnection() {
try {
return DriverManager.getConnection("jdbc:sqlserver://" + server + ";databaseName=" + db + ";", user, pw);
} catch (Exception e) {
System.err.println(e);
throw new RuntimeException(e);
}
}
static Statement getStatement(Connection connection) {
try {
return connection.createStatement();
} catch (Exception e) {
System.err.println(e);
throw new RuntimeException(e);
}
}
}
http://dba.stackexchange.com/questions/309 –