[JAVA] Verstehen Sie den Fehler, indem Sie ihn implementieren und analysieren. (2) Deadlock (SQL)

Überblick

Was passiert, wenn auf dem RDBMS, auf das eine Webanwendung zugreift, ein Deadlock auftritt?

* In diesem Artikel wird [Webanwendung voller Fehler](http://qiita.com/tamura__246/items/7275c7406706fb0057e8) mit verschiedenen Fehlern verwendet. Dies ist der zweite Artikel, der zeigt, wie man es analysiert.

Im vorherigen Artikel (http://qiita.com/tamura__246/items/603a3368994498a2cd2d) habe ich den Java-Deadlock neu erstellt und bestätigt, dass der Thread gestoppt wurde und keine Antwort zurückgegeben wurde. Ist Deadlock in RDBMS der gleiche?

Probieren wir es aus.

Reproduzieren Sie das tote Schloss

Lassen Sie uns zunächst das tote Schloss reproduzieren. Laden Sie die Webanwendung herunter und starten Sie sie (https://github.com/k-tamura/easybuggy/releases/latest). Informationen zum Starten finden Sie unter hier.

* In diesem Artikel wird zur Überprüfung Version 1.2.22 verwendet. Das Verhalten kann sich in zukünftigen Versionen ändern. Greifen Sie nach dem Start auf die folgende URL zu.

http://localhost:8080

Wenn es normal startet, wird der folgende Bildschirm angezeigt.

Screenshot from 2017-04-23 20-34-28.png

Klicken Sie auf den Link "Dead Lock (SQL)", um einen Bildschirm anzuzeigen, auf dem Dead Lock (SQL) reproduziert werden kann.

Screenshot from 2017-04-23 20-29-57.png

Öffnen Sie diesen Bildschirm in einem anderen Fenster (oder einer anderen Registerkarte), wie am unteren Bildschirmrand angegeben. Klicken Sie einmal in einem Fenster auf den Link Benutzer-ID, um die Benutzerliste nach ID in absteigender Reihenfolge zu sortieren. Klicken Sie dann unmittelbar nach dem Klicken auf die Schaltfläche "Aktualisieren" in aufsteigender Reihenfolge in einem anderen Fenster auf die Schaltfläche "Aktualisieren".

Nach einer Weile wird in einem Fenster die Meldung "10 aktualisiert" und im anderen Fenster die Meldung "Die Sperre konnte aufgrund eines Deadlocks nicht erworben werden" angezeigt. Zu diesem Zeitpunkt ist in RDBMS eine Dead Lock aufgetreten.

Screenshot from 2017-04-23 20-30-54.png

Lassen Sie uns das Protokoll überprüfen. Wenn Sie sich logs / easybuggy.log ansehen, aktualisieren zwei Threads (qtp1806431167-21, qtp1806431167-23) abwechselnd Benutzerinformationen, wobei der erste USER04 und der zweite USER05 aktualisiert und anschließend 20 Sekunden verarbeitet werden Ein Stopp ist aufgetreten. Danach können Sie sehen, dass der letztere die Verarbeitung fortsetzt und der erstere eine SQLTransactionRollbackException hat.

2017-04-24 13:21:26  INFO qtp1806431167-23 DeadlockServlet2 user09 is updated.
2017-04-24 13:21:26  INFO qtp1806431167-21 DeadlockServlet2 user00 is updated.
2017-04-24 13:21:26  INFO qtp1806431167-23 DeadlockServlet2 user08 is updated.
2017-04-24 13:21:26  INFO qtp1806431167-21 DeadlockServlet2 user01 is updated.
2017-04-24 13:21:27  INFO qtp1806431167-23 DeadlockServlet2 user07 is updated.
2017-04-24 13:21:27  INFO qtp1806431167-21 DeadlockServlet2 user02 is updated.
2017-04-24 13:21:27  INFO qtp1806431167-23 DeadlockServlet2 user06 is updated.
2017-04-24 13:21:27  INFO qtp1806431167-21 DeadlockServlet2 user03 is updated.
2017-04-24 13:21:28  INFO qtp1806431167-23 DeadlockServlet2 user05 is updated.
2017-04-24 13:21:28  INFO qtp1806431167-21 DeadlockServlet2 user04 is updated.
2017-04-24 13:21:48  INFO qtp1806431167-23 DeadlockServlet2 user04 is updated.
2017-04-24 13:21:48 ERROR qtp1806431167-21 DeadlockServlet2 SQLTransactionRollbackException occurs: 
java.sql.SQLTransactionRollbackException: A lock could not be obtained due to a deadlock, cycle of locks and waiters is:
Lock : ROW, USERS, (1,16)
  Waiting XID : {198, X} , APP, Update users set name = ?, phone = ?, mail = ? where id = ?
  Granted XID : {194, X} 
Lock : ROW, USERS, (1,15)
  Waiting XID : {194, X} , APP, Update users set name = ?, phone = ?, mail = ? where id = ?
  Granted XID : {198, X} 
. The selected victim is XID : 198.
	at org.apache.derby.impl.jdbc.SQLExceptionFactory40.getSQLException(Unknown Source)
	at org.apache.derby.impl.jdbc.Util.generateCsSQLException(Unknown Source)
	at org.apache.derby.impl.jdbc.TransactionResourceImpl.wrapInSQLException(Unknown Source)
	at org.apache.derby.impl.jdbc.TransactionResourceImpl.handleException(Unknown Source)
	at org.apache.derby.impl.jdbc.EmbedConnection.handleException(Unknown Source)
	at org.apache.derby.impl.jdbc.ConnectionChild.handleException(Unknown Source)
	at org.apache.derby.impl.jdbc.EmbedStatement.executeStatement(Unknown Source)
	at org.apache.derby.impl.jdbc.EmbedPreparedStatement.executeStatement(Unknown Source)
	at org.apache.derby.impl.jdbc.EmbedPreparedStatement.executeUpdate(Unknown Source)
	at org.t246osslab.easybuggy.troubles.DeadlockServlet2.updateUsers(DeadlockServlet2.java:170)
	at org.t246osslab.easybuggy.troubles.DeadlockServlet2.service(DeadlockServlet2.java:55)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:770)
	at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:684)
	at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1507)
	at org.t246osslab.easybuggy.core.filters.SecurityFilter.doFilter(SecurityFilter.java:51)
	at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1495)
	at org.t246osslab.easybuggy.core.filters.EncodingFilter.doFilter(EncodingFilter.java:42)
	at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1495)
	at org.t246osslab.easybuggy.core.filters.AuthenticationFilter.doFilter(AuthenticationFilter.java:72)
	at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1487)
	at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:499)
	at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:137)
	at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:557)
	at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:231)
	at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1086)
	at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:427)
	at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:193)
	at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1020)
	at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:135)
	at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:116)
	at org.eclipse.jetty.server.Server.handle(Server.java:370)
	at org.eclipse.jetty.server.AbstractHttpConnection.handleRequest(AbstractHttpConnection.java:494)
	at org.eclipse.jetty.server.AbstractHttpConnection.content(AbstractHttpConnection.java:984)
	at org.eclipse.jetty.server.AbstractHttpConnection$RequestHandler.content(AbstractHttpConnection.java:1045)
	at org.eclipse.jetty.http.HttpParser.parseNext(HttpParser.java:861)
	at org.eclipse.jetty.http.HttpParser.parseAvailable(HttpParser.java:236)
	at org.eclipse.jetty.server.AsyncHttpConnection.handle(AsyncHttpConnection.java:82)
	at org.eclipse.jetty.io.nio.SelectChannelEndPoint.handle(SelectChannelEndPoint.java:696)
	at org.eclipse.jetty.io.nio.SelectChannelEndPoint$1.run(SelectChannelEndPoint.java:53)
	at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:608)
	at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:543)
	at java.lang.Thread.run(Thread.java:745)
Caused by: java.sql.SQLException: A lock could not be obtained due to a deadlock, cycle of locks and waiters is:
Lock : ROW, USERS, (1,16)
  Waiting XID : {198, X} , APP, Update users set name = ?, phone = ?, mail = ? where id = ?
  Granted XID : {194, X} 
Lock : ROW, USERS, (1,15)
  Waiting XID : {194, X} , APP, Update users set name = ?, phone = ?, mail = ? where id = ?
  Granted XID : {198, X} 
. The selected victim is XID : 198.
	at org.apache.derby.impl.jdbc.SQLExceptionFactory.getSQLException(Unknown Source)
	at org.apache.derby.impl.jdbc.SQLExceptionFactory40.wrapArgsForTransportAcrossDRDA(Unknown Source)
	... 42 more
Caused by: ERROR 40001: A lock could not be obtained due to a deadlock, cycle of locks and waiters is:
Lock : ROW, USERS, (1,16)
  Waiting XID : {198, X} , APP, Update users set name = ?, phone = ?, mail = ? where id = ?
  Granted XID : {194, X} 
Lock : ROW, USERS, (1,15)
  Waiting XID : {194, X} , APP, Update users set name = ?, phone = ?, mail = ? where id = ?
  Granted XID : {198, X} 
. The selected victim is XID : 198.
	at org.apache.derby.iapi.error.StandardException.newException(Unknown Source)
	at org.apache.derby.impl.services.locks.Deadlock.buildException(Unknown Source)
	at org.apache.derby.impl.services.locks.ConcurrentLockSet.lockObject(Unknown Source)
	at org.apache.derby.impl.services.locks.AbstractPool.lockObject(Unknown Source)
	at org.apache.derby.impl.services.locks.ConcurrentPool.lockObject(Unknown Source)
	at org.apache.derby.impl.store.raw.xact.RowLocking3.lockRecordForWrite(Unknown Source)
	at org.apache.derby.impl.store.access.heap.HeapController.lockRow(Unknown Source)
	at org.apache.derby.impl.store.access.heap.HeapController.lockRow(Unknown Source)
	at org.apache.derby.impl.store.access.btree.index.B2IRowLocking3.lockRowOnPage(Unknown Source)
	at org.apache.derby.impl.store.access.btree.index.B2IRowLocking3._lockScanRow(Unknown Source)
	at org.apache.derby.impl.store.access.btree.index.B2IRowLockingRR.lockScanRow(Unknown Source)
	at org.apache.derby.impl.store.access.btree.BTreeForwardScan.fetchRows(Unknown Source)
	at org.apache.derby.impl.store.access.btree.BTreeScan.fetchNext(Unknown Source)
	at org.apache.derby.impl.sql.execute.TableScanResultSet.getNextRowCore(Unknown Source)
	at org.apache.derby.impl.sql.execute.IndexRowToBaseRowResultSet.getNextRowCore(Unknown Source)
	at org.apache.derby.impl.sql.execute.ProjectRestrictResultSet.getNextRowCore(Unknown Source)
	at org.apache.derby.impl.sql.execute.NormalizeResultSet.getNextRowCore(Unknown Source)
	at org.apache.derby.impl.sql.execute.DMLWriteResultSet.getNextRowCore(Unknown Source)
	at org.apache.derby.impl.sql.execute.UpdateResultSet.collectAffectedRows(Unknown Source)
	at org.apache.derby.impl.sql.execute.UpdateResultSet.open(Unknown Source)
	at org.apache.derby.impl.sql.GenericPreparedStatement.executeStmt(Unknown Source)
	at org.apache.derby.impl.sql.GenericPreparedStatement.execute(Unknown Source)
	... 36 more
2017-04-24 13:21:49  INFO qtp1806431167-23 DeadlockServlet2 user03 is updated.
2017-04-24 13:21:49  INFO qtp1806431167-23 DeadlockServlet2 user02 is updated.
2017-04-24 13:21:50  INFO qtp1806431167-23 DeadlockServlet2 user01 is updated.
2017-04-24 13:21:50  INFO qtp1806431167-23 DeadlockServlet2 user00 is updated.

Um welche Art von Implementierung handelt es sich?

Was war die Implementierung des Quellcodes? Sehen Sie sich DeadlockServlet2.java an, das im Protokoll ausgegeben wurde. Lasst uns. Die wichtigen Teile sind:

    private String updateUsers(ArrayList<User> users, Locale locale) {

・ ・ ・(Abkürzung)・ ・ ・

        try {

            conn = DBClient.getConnection();
            conn.setAutoCommit(false);

            stmt = conn.prepareStatement("Update users set name = ?, phone = ?, mail = ? where id = ?");
            for (User user : users) {
                stmt.setString(1, user.getName());
                stmt.setString(2, user.getPhone());
                stmt.setString(3, user.getMail());
                stmt.setString(4, user.getUserId());
                executeUpdate = executeUpdate + stmt.executeUpdate();
                Thread.sleep(500);
            }
            conn.commit();
            resultMessage = MessageUtils.getMsg("msg.update.records", new Object[] { executeUpdate }, locale) + "<br><br>";

        } catch (SQLTransactionRollbackException e) {
            resultMessage = MessageUtils.getErrMsg("msg.deadlock.occurs", locale);
            log.error("SQLTransactionRollbackException occurs: ", e);
            rollbak(conn);
・ ・ ・(Abkürzung)・ ・ ・

    }

In diesem Servlet werden die Benutzerlistendaten auf dem Bildschirm in der Reihenfolge von oben erfasst und der RDBMS-Benutzerdatensatz mit der UPDATE-Anweisung aktualisiert. Und ich bin fest entschlossen, wenn alle Updates abgeschlossen sind.

deadlock.png

Wenn der erste Thread USER05 aktualisiert und dann versucht, USER04 zu aktualisieren, aktualisiert der zweite Thread USER04, versucht dann, USER05 zu aktualisieren, und wartet darauf, dass die anderen abgeschlossen werden. .. DB (Derby) erkennt, dass eine Dead Lock aufgetreten ist, und gibt nach 20 Sekunden einen Fehler an die Transaktion des zweiten Threads zurück. Andererseits fängt der zweite Thread die SQLTransactionRollbackException ab und führt die Ausnahmebehandlung aus.

Was ist mit anderen Einstellungen und Datenbanken?

Das Verhalten während des Deadlocks hängt auch vom verwendeten RDBMS und den Einstellungen ab. Das diesmal verwendete RDBMS ist ein integriertes Derby im Modus "In-Memory-Datenbank". Die Standardeinstellung ist die Sperre auf Zeilenebene (* Um genau zu sein, handelt es sich im Grunde genommen um eine Sperre auf Zeilenebene, und die Granularität der Sperren wird unter Berücksichtigung der Leistung angepasst. Erweitert sich auf mehrzeilige Sperren und Tabellensperren.

Bedienung mit Tischsperre

Eine Option mit dem Namen derby.storage.rowLocking finden Sie im Derby Developer Guide (https://builds.apache.org/job/Derby-docs/lastSuccessfulBuild/artifact/trunk/out/devguide/index.html). Sie können eine Sperre auf Zeilenebene zu einer Sperre auf Tabellenebene machen, indem Sie sie auf false setzen.

Lassen Sie uns also die Funktion der Sperre auf Tabellenebene überprüfen. Ändern Sie die folgende Zeile in pom.xml.

<!-- <argument>-Dderby.storage.rowLocking=true</argument> -->
<!--Ändern Sie den Wert in der obersten Zeile von true in false-->
<argument>-Dderby.storage.rowLocking=false</argument>

Starten Sie EasyBuggy neu und probieren Sie es aus. Befehl mvn (mvn clean install exec: exec Wenn es mit gestartet wird, stoppen Sie es mit Strg + C und starten Sie es erneut mit demselben Befehl. Aktualisieren Sie dann die beiden Listen mit der umgekehrten Sortierreihenfolge. Diesmal sollte es keinen Deadlock geben. Wenn Sie das Protokoll überprüfen, wird der nächste Thread aktualisiert und wartet darauf, dass die Aktualisierung des ersten aktualisierten Threads wie unten gezeigt abgeschlossen wird.

2017-04-24 13:51:50  INFO qtp1806431167-24 DeadlockServlet2 user09 is updated.
2017-04-24 13:51:50  INFO qtp1806431167-24 DeadlockServlet2 user08 is updated.
2017-04-24 13:51:51  INFO qtp1806431167-24 DeadlockServlet2 user07 is updated.
2017-04-24 13:51:51  INFO qtp1806431167-24 DeadlockServlet2 user06 is updated.
2017-04-24 13:51:52  INFO qtp1806431167-24 DeadlockServlet2 user05 is updated.
2017-04-24 13:51:52  INFO qtp1806431167-24 DeadlockServlet2 user04 is updated.
2017-04-24 13:51:53  INFO qtp1806431167-24 DeadlockServlet2 user03 is updated.
2017-04-24 13:51:53  INFO qtp1806431167-24 DeadlockServlet2 user02 is updated.
2017-04-24 13:51:54  INFO qtp1806431167-24 DeadlockServlet2 user01 is updated.
2017-04-24 13:51:54  INFO qtp1806431167-24 DeadlockServlet2 user00 is updated.
2017-04-24 13:51:55  INFO qtp1806431167-20 DeadlockServlet2 user00 is updated.
2017-04-24 13:51:56  INFO qtp1806431167-20 DeadlockServlet2 user01 is updated.
2017-04-24 13:51:56  INFO qtp1806431167-20 DeadlockServlet2 user02 is updated.
2017-04-24 13:51:57  INFO qtp1806431167-20 DeadlockServlet2 user03 is updated.
2017-04-24 13:51:57  INFO qtp1806431167-20 DeadlockServlet2 user04 is updated.
2017-04-24 13:51:58  INFO qtp1806431167-20 DeadlockServlet2 user05 is updated.
2017-04-24 13:51:58  INFO qtp1806431167-20 DeadlockServlet2 user06 is updated.
2017-04-24 13:51:59  INFO qtp1806431167-20 DeadlockServlet2 user07 is updated.
2017-04-24 13:51:59  INFO qtp1806431167-20 DeadlockServlet2 user08 is updated.
2017-04-24 13:52:00  INFO qtp1806431167-20 DeadlockServlet2 user09 is updated.

Es handelt sich um eine Sperre auf Tabellenebene. Wenn Sie also bereits eine Transaktion haben, die die Sperre erworben hat, müssen Sie warten, bis sie abgeschlossen ist. Da es nach Abschluss aktualisiert wird, wird der Aktualisierungsinhalt des ersten aktualisierten Threads überschrieben.

Verhalten in MySQL

Ich werde es auch mit MySQL überprüfen. Kommentieren Sie die Derby-Einstellung in easybuggy / src / main / resources / application.properties aus und fügen Sie die MySQL-Einstellung hinzu. Die diesmal verwendete Version von MySQL ist 5.1.73.

### RDBMS
#Kommentieren Sie die Derby-Einstellung im speicherinternen DB-Modus aus und
#database.url=jdbc:derby:memory:demo;create=true
#database.driver=org.apache.derby.jdbc.EmbeddedDriver
#Fügen Sie MySQL-Einstellungen hinzu
database.url=jdbc:mysql://localhost:3306/easybuggy?user=easybuggy&password=password
database.driver=com.mysql.jdbc.Driver

Die obige Einstellung dient zum Herstellen einer Verbindung zur lokal installierten MySQL easybuggy-Datenbank als Benutzer mit dem Namen easybuggy. Das Kennwort für diesen Benutzer lautet Kennwort.

Starten Sie jetzt EasyBuggy neu und probieren Sie es aus. Ist ein Dead Lock aufgetreten? In meiner Umgebung ist das nicht passiert. Der Grund liegt in der Standardspeicher-Engine von MySQL. Wenn die Version von MySQL älter als 5.5 ist, lautet die Standardspeicher-Engine "MyISAM".

$ mysql -u root
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 31
Server version: 5.1.73-log Source distribution

Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> use information_schema;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> select table_name, engine from tables where table_schema = 'easybuggy';
+------------+--------+
| table_name | engine |
+------------+--------+
| users      | MyISAM |
+------------+--------+
1 row in set (0.00 sec)

MyISAM unterstützt nur das Sperren auf Tabellenebene und das Sperren auf Zeilenebene nicht. Bearbeiten Sie also /etc/my.cnf und ändern Sie es in InnoDB.

[mysqld]
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
user=mysql
symbolic-links=0
#Fügen Sie Folgendes hinzu
default-table-type=InnoDB

[mysqld_safe]
  …

Starten Sie MySQL und EasyBuggy nach Änderungen neu und versuchen Sie es erneut. Ich denke, diesmal wird es zu einem Deadlock kommen.

2017-04-24 14:29:14  INFO qtp1806431167-22 DeadlockServlet2 user09 is updated.
2017-04-24 14:29:15  INFO qtp1806431167-22 DeadlockServlet2 user08 is updated.
2017-04-24 14:29:15  INFO qtp1806431167-25 DeadlockServlet2 user00 is updated.
2017-04-24 14:29:15  INFO qtp1806431167-22 DeadlockServlet2 user07 is updated.
2017-04-24 14:29:15  INFO qtp1806431167-25 DeadlockServlet2 user01 is updated.
2017-04-24 14:29:16  INFO qtp1806431167-22 DeadlockServlet2 user06 is updated.
2017-04-24 14:29:16  INFO qtp1806431167-25 DeadlockServlet2 user02 is updated.
2017-04-24 14:29:16  INFO qtp1806431167-22 DeadlockServlet2 user05 is updated.
2017-04-24 14:29:16  INFO qtp1806431167-25 DeadlockServlet2 user03 is updated.
2017-04-24 14:29:17  INFO qtp1806431167-22 DeadlockServlet2 user04 is updated.
2017-04-24 14:29:17  INFO qtp1806431167-22 DeadlockServlet2 user03 is updated.
2017-04-24 14:29:17 ERROR qtp1806431167-25 DeadlockServlet2 SQLTransactionRollbackException occurs:
com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException: Deadlock found when trying to get lock; try restarting transaction
        at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
        at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
        at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
        at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
        at com.mysql.jdbc.Util.handleNewInstance(Util.java:411)
        at com.mysql.jdbc.Util.getInstance(Util.java:386)
        at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1066)
        at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4187)
        at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4119)
        at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2570)
        at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2731)
        at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2815)
        at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:2155)
        at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2458)
        at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2375)
        at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2359)
        at org.t246osslab.easybuggy.troubles.DeadlockServlet2.updateUsers(DeadlockServlet2.java:169)
        at org.t246osslab.easybuggy.troubles.DeadlockServlet2.service(DeadlockServlet2.java:57)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:770)
        at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:684)
        at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1507)
        at org.t246osslab.easybuggy.core.filters.SecurityFilter.doFilter(SecurityFilter.java:51)
        at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1495)
        at org.t246osslab.easybuggy.core.filters.EncodingFilter.doFilter(EncodingFilter.java:42)
        at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1495)
        at org.t246osslab.easybuggy.core.filters.AuthenticationFilter.doFilter(AuthenticationFilter.java:72)
        at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1487)
        at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:499)
        at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:137)
        at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:557)
        at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:231)
        at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1086)
        at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:427)
        at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:193)
        at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1020)
        at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:135)
        at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:116)
        at org.eclipse.jetty.server.Server.handle(Server.java:370)
        at org.eclipse.jetty.server.AbstractHttpConnection.handleRequest(AbstractHttpConnection.java:494)
        at org.eclipse.jetty.server.AbstractHttpConnection.content(AbstractHttpConnection.java:984)
        at org.eclipse.jetty.server.AbstractHttpConnection$RequestHandler.content(AbstractHttpConnection.java:1045)
        at org.eclipse.jetty.http.HttpParser.parseNext(HttpParser.java:861)
        at org.eclipse.jetty.http.HttpParser.parseAvailable(HttpParser.java:236)
        at org.eclipse.jetty.server.AsyncHttpConnection.handle(AsyncHttpConnection.java:82)
        at org.eclipse.jetty.io.nio.SelectChannelEndPoint.handle(SelectChannelEndPoint.java:696)
        at org.eclipse.jetty.io.nio.SelectChannelEndPoint$1.run(SelectChannelEndPoint.java:53)
        at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:608)
        at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:543)
        at java.lang.Thread.run(Thread.java:745)
2017-04-24 14:29:18  INFO qtp1806431167-22 DeadlockServlet2 user02 is updated.
2017-04-24 14:29:18  INFO qtp1806431167-22 DeadlockServlet2 user01 is updated.
2017-04-24 14:29:19  INFO qtp1806431167-22 DeadlockServlet2 user00 is updated.

Als ich das Protokoll überprüfte, löste ich eine com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException aus, die java.sql.TransactionRollbackException geerbt hat.

Außerdem brauchte Derby 20 Sekunden, um den Deadlock zu erkennen, aber MySQL schien ihn sofort zu erkennen. Es wird angenommen, dass dies auf Unterschiede in den Erkennungsmethoden und -algorithmen zurückzuführen ist. Ich habe es nicht im Detail untersucht, aber ich denke, es kann in den Einstellungen geändert werden.

Diese Zusammenfassung

--Deadlock tritt auf, wenn es mehrere Threads (Transaktionen) gibt, in denen die Reihenfolge der Sperrenerfassung auch in RDBMS umgekehrt ist, z. B. Java-Deadlock.

  • Wartet nicht ewig wie Java-Deadlocks (verarbeite einen weiter und erhalte einen Fehler auf dem anderen)
  • Wenn ein Deadlock auftritt, löst der JDBC-Treiber eine java.sql.SQLTransactionRollbackException aus (* Dies hängt von der Implementierung des JDBC-Treibers ab. Verschiedene Versionen können eine andere Ausnahme auslösen.)
  • Der Betrieb zum Zeitpunkt der Dead Lock hängt vom verwendeten RDBMS und der Einstellung des Sperrmodus ab.
  • Um Deadlocks zu vermeiden, muss die Datenzugriffsreihenfolge festgelegt und das Programm implementiert werden.