[JAVA] Comprendre le bogue en l'implémentant et en l'analysant (2) Deadlock (SQL)

Aperçu

Que se passe-t-il si un blocage se produit sur le SGBDR auquel une application Web accède?

* Cet article utilise [application Web pleine de bogues](http://qiita.com/tamura__246/items/7275c7406706fb0057e8) avec divers bogues. C'est le deuxième article qui montre comment l'analyser.

Dans l'article précédent (http://qiita.com/tamura__246/items/603a3368994498a2cd2d), j'ai recréé le blocage Java et confirmé que le thread s'est arrêté et qu'aucune réponse n'a été renvoyée. Le blocage dans le SGBDR est-il le même?

Essayons-le.

Reproduire le dead lock

Tout d'abord, reproduisons le verrou mort. Téléchargez et lancez l'application Web (https://github.com/k-tamura/easybuggy/releases/latest). Veuillez consulter ici pour savoir comment démarrer.

* Cet article utilise la version 1.2.22 pour la vérification. Le comportement peut changer dans les versions futures. Après le démarrage, accédez à l'URL suivante.

http://localhost:8080

S'il démarre normalement, l'écran suivant s'affiche.

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

Si vous cliquez sur le lien qui dit «Dead Lock (SQL)», vous verrez un écran où Dead Lock (SQL) peut être reproduit.

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

Ouvrez cet écran dans une autre fenêtre (ou onglet) comme indiqué en bas de l'écran. Cliquez sur le lien de l'ID utilisateur une fois dans une fenêtre pour trier la liste des utilisateurs par ID dans l'ordre décroissant. Ensuite, immédiatement après avoir cliqué sur le bouton "Mettre à jour", cliquez sur le bouton "Mettre à jour" dans l'ordre croissant dans une autre fenêtre.

Après un certain temps, une fenêtre affichera le message "10 mis à jour" et l'autre affichera le message "Le verrou n'a pas pu être acquis en raison d'un blocage." À ce moment, un verrou mort s'est produit dans le SGBDR.

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

Vérifions le journal. En regardant logs / easybuggy.log, deux threads (qtp1806431167-21, qtp1806431167-23) mettent à jour en alternance les informations utilisateur, le premier met à jour USER04 et le second met à jour USER05 pendant 20 secondes. Un arrêt s'est produit. Après cela, vous pouvez voir que ce dernier continue le traitement et que le premier a une exception SQLTransactionRollbackException.

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.

De quel type de mise en œuvre s'agit-il

Quelle a été l'implémentation du code source? Regardez DeadlockServlet2.java qui a été affiché dans le journal. Allons. Les parties importantes sont:

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

・ ・ ・(Abréviation)・ ・ ・

        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);
・ ・ ・(Abréviation)・ ・ ・

    }

Dans ce servlet, les données de la liste des utilisateurs à l'écran sont acquises dans l'ordre à partir du haut, et l'enregistrement utilisateur du SGBDR est mis à jour avec l'instruction UPDATE. Et je m'engage lorsque toutes les mises à jour sont effectuées.

deadlock.png

Lorsque le premier thread met à jour USER05, puis essaie de mettre à jour USER04, le deuxième thread met à jour USER04, puis essaie de mettre à jour USER05 et attend que l'autre se termine. .. DB (Derby) détecte qu'un verrou mort s'est produit et renvoie une erreur à la transaction du deuxième thread après 20 secondes. D'autre part, le deuxième thread intercepte SQLTransactionRollbackException et effectue la gestion des exceptions.

Qu'en est-il des autres paramètres et bases de données?

Le comportement lors d'un blocage dépend également du SGBDR utilisé et des paramètres. Le SGBDR utilisé cette fois est un Derby intégré en mode «base de données en mémoire», et la valeur par défaut est le verrouillage au niveau des lignes (* Pour être précis, il s'agit essentiellement d'un verrouillage au niveau des lignes, et la granularité du verrou est ajustée en tenant compte des performances. S'étend aux verrous à plusieurs lignes et aux verrous de table).

Fonctionnement avec verrouillage au niveau de la table

Consultez le Guide du développeur Derby (https://builds.apache.org/job/Derby-docs/lastSuccessfulBuild/artifact/trunk/out/devguide/index.html) pour une option appelée derby.storage.rowLocking. Vous pouvez faire d'un verrou au niveau de la ligne un verrou au niveau de la table en le définissant sur false.

Alors, vérifions le fonctionnement du verrouillage au niveau de la table. Modifiez la ligne suivante dans pom.xml.

<!-- <argument>-Dderby.storage.rowLocking=true</argument> -->
<!--Changer la valeur de la ligne supérieure de vrai à faux-->
<argument>-Dderby.storage.rowLocking=false</argument>

Redémarrez EasyBuggy et essayez-le. commande mvn (mvn clean install exec: exec S'il est démarré avec), arrêtez-le avec Ctrl + C et redémarrez-le avec la même commande. Ensuite, mettez à jour les deux listes avec l'ordre de tri inversé à nouveau. Cette fois, il ne devrait y avoir aucune impasse. En vérifiant le journal, le thread suivant commence à se mettre à jour, en attendant que la mise à jour du premier thread mis à jour soit terminée comme indiqué ci-dessous.

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.

C'est un verrou au niveau de la table, donc si vous avez déjà une transaction qui a acquis le verrou, vous devrez attendre qu'elle se termine. Puisqu'il sera mis à jour une fois terminé, le contenu de la mise à jour du premier thread mis à jour sera écrasé.

Comportement dans MySQL

Je vais également le vérifier avec MySQL. Mettez en commentaire le paramètre Derby dans easybuggy / src / main / resources / application.properties et ajoutez le paramètre MySQL. La version de MySQL utilisée cette fois est la 5.1.73.

### RDBMS
#Commentez le paramètre Derby en mode DB en mémoire,
#database.url=jdbc:derby:memory:demo;create=true
#database.driver=org.apache.derby.jdbc.EmbeddedDriver
#Ajouter des paramètres MySQL
database.url=jdbc:mysql://localhost:3306/easybuggy?user=easybuggy&password=password
database.driver=com.mysql.jdbc.Driver

Le paramètre ci-dessus permet de se connecter à la base de données MySQL easybuggy installée localement en tant qu'utilisateur nommé easybuggy, et le mot de passe de cet utilisateur est password.

Maintenant, redémarrez EasyBuggy et essayez-le. Un verrou mort s'est produit? Cela ne s'est pas produit dans mon environnement. La raison est dans le moteur de stockage par défaut de MySQL. Si la version de MySQL est antérieure à 5.5, le moteur de stockage par défaut est "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 prend uniquement en charge le verrouillage au niveau de la table et ne prend pas en charge le verrouillage au niveau des lignes. Alors éditez /etc/my.cnf et changez-le en InnoDB.

[mysqld]
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
user=mysql
symbolic-links=0
#Ajoutez ce qui suit
default-table-type=InnoDB

[mysqld_safe]
  …

Après avoir apporté des modifications, redémarrez MySQL et EasyBuggy et réessayez. Je pense qu'une impasse se produira cette fois.

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.

Lorsque j'ai vérifié le journal, je lançais une exception com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException qui héritait de java.sql.TransactionRollbackException.

De plus, Derby a mis 20 secondes pour détecter le blocage, mais MySQL a semblé le détecter immédiatement. On pense que cela est dû aux différences dans les méthodes de détection et les algorithmes. Je ne l'ai pas étudié en détail, mais je pense que cela peut être modifié dans les paramètres.

Ce résumé

--Le blocage se produit lorsqu'il y a plusieurs threads (transactions) dans lesquels l'ordre d'acquisition du verrou est inversé même dans un SGBDR comme le blocage Java.

  • N'attend pas éternellement comme les blocages Java (continuez à traiter l'un et obtenez une erreur sur l'autre)
  • En cas de blocage, le pilote JDBC lève une exception java.sql.SQLTransactionRollbackException (* Cela dépend de l'implémentation du pilote JDBC. Différentes versions peuvent lever une exception différente)
  • Le fonctionnement au moment du verrouillage mort dépend du SGBDR utilisé et du réglage du mode verrouillage.
  • Afin d'éviter un blocage, il est nécessaire de décider de l'ordre d'accès aux données et de mettre en œuvre le programme.