diff -r --new-file -u a/h2/src/main/org/h2/command/ddl/DropIndex.java b/h2/src/main/org/h2/command/ddl/DropIndex.java
--- a/h2/src/main/org/h2/command/ddl/DropIndex.java	2019-10-14 09:47:23.000000000 +0300
+++ b/h2/src/main/org/h2/command/ddl/DropIndex.java	2020-07-10 16:26:40.178099681 +0300
@@ -41,7 +41,9 @@
 
     @Override
     public int update() {
-        session.commit(true);
+        if (!transactional) {
+            session.commit(true);
+        }
         Database db = session.getDatabase();
         Index index = getSchema().findIndex(session, indexName);
         if (index == null) {
diff -r --new-file -u a/h2/src/main/org/h2/command/ddl/DropTable.java b/h2/src/main/org/h2/command/ddl/DropTable.java
--- a/h2/src/main/org/h2/command/ddl/DropTable.java	2019-10-14 09:47:23.000000000 +0300
+++ b/h2/src/main/org/h2/command/ddl/DropTable.java	2020-07-10 16:26:34.942033641 +0300
@@ -120,7 +120,9 @@
 
     @Override
     public int update() {
-        session.commit(true);
+        if (!transactional) {
+            session.commit(true);
+        }
         if (prepareDrop()) {
             executeDrop();
         }
diff -r --new-file -u a/h2/src/main/org/h2/command/Parser.java b/h2/src/main/org/h2/command/Parser.java
--- a/h2/src/main/org/h2/command/Parser.java	2019-10-14 09:47:23.000000000 +0300
+++ b/h2/src/main/org/h2/command/Parser.java	2020-07-10 16:26:30.409976485 +0300
@@ -2247,6 +2247,9 @@
                 // TODO SET_DEFAULT works in the same way as CASCADE
                 command.setDropAction(ConstraintActionType.SET_DEFAULT);
             }
+            if (readIf("TRANSACTIONAL")) {
+                command.setTransactional(true);
+            }
             return command;
         } else if (readIf("INDEX")) {
             boolean ifExists = readIfExists(false);
@@ -2259,6 +2262,9 @@
             if (readIf(ON)) {
                 readIdentifierWithSchema();
             }
+            if (readIf("TRANSACTIONAL")) {
+                command.setTransactional(true);
+            }
             return command;
         } else if (readIf("USER")) {
             boolean ifExists = readIfExists(false);
@@ -6344,6 +6350,9 @@
                 }
 
             }
+            if (readIf("TRANSACTIONAL")) {
+                command.setTransactional(true);
+            }
             command.setHash(hash);
             command.setSpatial(spatial);
             return command;
@@ -8268,6 +8277,9 @@
             }
             read("REFERENCES");
             parseReferences(command, schema, tableName);
+            if (readIf("TRANSACTIONAL")) {
+               command.setTransactional(true);
+           }
         } else {
             if (constraintName != null) {
                 throw getSyntaxError();
diff -r --new-file -u a/h2/src/main/org/h2/engine/LocalTempTablesManager.java b/h2/src/main/org/h2/engine/LocalTempTablesManager.java
--- a/h2/src/main/org/h2/engine/LocalTempTablesManager.java	1970-01-01 02:00:00.000000000 +0200
+++ b/h2/src/main/org/h2/engine/LocalTempTablesManager.java	2020-07-10 16:20:21.437325177 +0300
@@ -0,0 +1,97 @@
+package org.h2.engine;
+
+import java.util.*;
+
+import org.h2.table.Table;
+import org.h2.util.Utils;
+
+/**
+ * Manager responsible for handling operations with local temp tables. There are scenarios
+ * in which tables marked with onCommitDrop or onCommitTruncate flags should be accessed faster 
+ * and not sequentially searched. All the work on local temp tables should pass through this 
+ * manager in order to keep the maps consistent.
+ */
+public class LocalTempTablesManager {
+   
+   private HashMap<String, Table> localTempTables;
+   private HashMap<String, Table> onCommitDropTables;
+   private HashMap<String, Table> onCommitTruncateTables;
+   private Database database;
+
+   public LocalTempTablesManager(Database database) {
+       this.database = database;
+   }
+
+   public void register(Table table) {
+       if (localTempTables == null) {
+           localTempTables = database.newStringMap();
+       }
+       
+       localTempTables.put(table.getName(), table);
+       if (table.getOnCommitDrop()) {
+           if (onCommitDropTables == null) {
+               onCommitDropTables = database.newStringMap();
+           }
+           onCommitDropTables.put(table.getName(), table);
+       }
+       if (table.getOnCommitTruncate()) {
+           if (onCommitTruncateTables == null) {
+               onCommitTruncateTables = database.newStringMap();
+           }
+           onCommitTruncateTables.put(table.getName(), table);
+       }
+   }
+
+   public boolean has(String name) {
+       if (localTempTables == null) {
+           return false;
+       }
+       return localTempTables.containsKey(name);
+   }
+
+   public Table get(String name)
+   {
+       if (localTempTables == null) {
+           return null;
+       }
+       return localTempTables.get(name);
+   }
+
+   public ArrayList<Table> getAll() {
+       if (localTempTables == null) {
+           return Utils.newSmallArrayList();
+       }
+       return new ArrayList<>(localTempTables.values());
+   }
+
+   public void remove(String name) {
+       if (localTempTables != null) {
+           localTempTables.remove(name);
+       }
+       if (onCommitDropTables != null) {
+           onCommitDropTables.remove(name);
+       }
+       if (onCommitTruncateTables != null) {
+           onCommitTruncateTables.remove(name);
+       }
+   }
+
+   public boolean canClean(boolean closeSession) {
+       return closeSession || 
+              onCommitDropTables != null && !onCommitDropTables.isEmpty() || 
+              onCommitTruncateTables != null && !onCommitTruncateTables.isEmpty();
+   }
+
+   public HashMap<String, Table> getOnCommitDropTables() {
+      return onCommitDropTables;
+   }
+
+   public HashMap<String, Table> getLocalTempTables() {
+      return localTempTables;
+   }
+
+   public HashMap<String, Table> getOnCommitTruncateTables() {
+      return onCommitTruncateTables;
+   }
+
+}
diff -r --new-file -u a/h2/src/main/org/h2/engine/Session.java b/h2/src/main/org/h2/engine/Session.java
--- a/h2/src/main/org/h2/engine/Session.java	2019-10-14 09:47:23.000000000 +0300
+++ b/h2/src/main/org/h2/engine/Session.java	2020-07-10 16:26:13.397761925 +0300
@@ -108,7 +108,7 @@
     private int firstUncommittedLog = Session.LOG_WRITTEN;
     private int firstUncommittedPos = Session.LOG_WRITTEN;
     private HashMap<String, Savepoint> savepoints;
-    private HashMap<String, Table> localTempTables;
+    private LocalTempTablesManager localTempTablesManager;
     private HashMap<String, Index> localTempTableIndexes;
     private HashMap<String, Constraint> localTempTableConstraints;
     private long throttleNs;
@@ -398,17 +398,17 @@
      * @return the table, or null
      */
     public Table findLocalTempTable(String name) {
-        if (localTempTables == null) {
+        if (localTempTablesManager == null) {
             return null;
         }
-        return localTempTables.get(name);
+        return localTempTablesManager.get(name);
     }
 
     public ArrayList<Table> getLocalTempTables() {
-        if (localTempTables == null) {
+        if (localTempTablesManager == null) {
             return Utils.newSmallArrayList();
         }
-        return new ArrayList<>(localTempTables.values());
+        return localTempTablesManager.getAll();
     }
 
     /**
@@ -418,17 +418,17 @@
      * @throws DbException if a table with this name already exists
      */
     public void addLocalTempTable(Table table) {
-        if (localTempTables == null) {
-            localTempTables = database.newStringMap();
+        if (localTempTablesManager == null) {
+            localTempTablesManager = new LocalTempTablesManager(database);
         }
-        if (localTempTables.get(table.getName()) != null) {
+        if (localTempTablesManager.has(table.getName())) {
             StringBuilder builder = new StringBuilder();
             table.getSQL(builder, false).append(" AS ");
             Parser.quoteIdentifier(table.getName(), false);
             throw DbException.get(ErrorCode.TABLE_OR_VIEW_ALREADY_EXISTS_1, builder.toString());
         }
         modificationId++;
-        localTempTables.put(table.getName(), table);
+        localTempTablesManager.register(table);
     }
 
     /**
@@ -442,8 +442,8 @@
         boolean wasLocked = database.lockMeta(this);
         try {
             modificationId++;
-            if (localTempTables != null) {
-                localTempTables.remove(table.getName());
+            if (localTempTablesManager != null) {
+                localTempTablesManager.remove(table.getName());
             }
             synchronized (database) {
                 table.removeChildrenAndResources(this);
@@ -1055,7 +1055,7 @@
     }
 
     private void cleanTempTables(boolean closeSession) {
-        if (localTempTables != null && localTempTables.size() > 0) {
+        if (localTempTablesManager != null && localTempTablesManager.canClean(closeSession)) {
             if (database.isMVStore()) {
                 _cleanTempTables(closeSession);
             } else {
@@ -1067,23 +1067,47 @@
     }
 
     private void _cleanTempTables(boolean closeSession) {
-        Iterator<Table> it = localTempTables.values().iterator();
-        while (it.hasNext()) {
-            Table table = it.next();
-            if (closeSession || table.getOnCommitDrop()) {
+        HashMap<String, Table> localTempTables = localTempTablesManager.getLocalTempTables();     
+        if (closeSession && localTempTables != null) {
+            Iterator<Table> it = localTempTables.values().iterator();
+            while (it.hasNext()) {
+                Table table = it.next();
                 modificationId++;
                 table.setModified();
                 it.remove();
+                localTempTablesManager.remove(table.getName());
                 // Exception thrown in org.h2.engine.Database.removeMeta
                 // if line below is missing with TestDeadlock
                 database.lockMeta(this);
                 table.removeChildrenAndResources(this);
-                if (closeSession) {
-                    // need to commit, otherwise recovery might
-                    // ignore the table removal
-                    database.commit(this);
-                }
-            } else if (table.getOnCommitTruncate()) {
+                // need to commit, otherwise recovery might
+                // ignore the table removal
+                database.commit(this);
+            }
+            return;
+        }
+        
+        HashMap<String, Table> onCommitDropTables = localTempTablesManager.getOnCommitDropTables();
+        if (onCommitDropTables != null) {
+            Iterator<Table> it = onCommitDropTables.values().iterator();
+            while (it.hasNext()) {
+                Table table = it.next();
+                modificationId++;
+                table.setModified();
+                it.remove();
+                localTempTablesManager.remove(table.getName());
+                // Exception thrown in org.h2.engine.Database.removeMeta
+                // if line below is missing with TestDeadlock
+                database.lockMeta(this);
+                table.removeChildrenAndResources(this);
+            }
+        }
+        
+        HashMap<String, Table> onCommitTruncateTables = localTempTablesManager.getOnCommitTruncateTables();
+        if (onCommitTruncateTables != null) {
+            Iterator<Table> it = onCommitTruncateTables.values().iterator();
+            while (it.hasNext()) {
+                Table table = it.next();
                 table.truncate(this);
             }
         }
diff -r --new-file -u a/h2/src/main/org/h2/pagestore/db/PageStoreTable.java b/h2/src/main/org/h2/pagestore/db/PageStoreTable.java
--- a/h2/src/main/org/h2/pagestore/db/PageStoreTable.java	2019-10-14 09:47:23.000000000 +0300
+++ b/h2/src/main/org/h2/pagestore/db/PageStoreTable.java	2020-07-10 16:24:35.364525681 +0300
@@ -400,32 +400,34 @@
     }
 
     private boolean doLock2(Session session, int lockMode, boolean exclusive) {
-        if (exclusive) {
-            if (lockExclusiveSession == null) {
-                if (lockSharedSessions.isEmpty()) {
-                    traceLock(session, exclusive, "added for");
-                    session.registerTableAsLocked(this);
-                    lockExclusiveSession = session;
-                    return true;
-                } else if (lockSharedSessions.size() == 1 &&
+       synchronized (this) { 
+           if (exclusive) {
+               if (lockExclusiveSession == null) {
+                    if (lockSharedSessions.isEmpty()) {
+                        traceLock(session, exclusive, "added for");
+                        session.registerTableAsLocked(this);
+                        lockExclusiveSession = session;
+                        return true;
+                    } else if (lockSharedSessions.size() == 1 &&
                         lockSharedSessions.containsKey(session)) {
-                    traceLock(session, exclusive, "add (upgraded) for ");
-                    lockExclusiveSession = session;
-                    return true;
-                }
-            }
-        } else {
-            if (lockExclusiveSession == null) {
-                if (lockMode == Constants.LOCK_MODE_READ_COMMITTED) {
-                    // PageStore is single-threaded, no lock is required
+                        traceLock(session, exclusive, "add (upgraded) for ");
+                        lockExclusiveSession = session;
+                        return true;
+                    }
+                }
+            } else {
+                if (lockExclusiveSession == null) {
+                    if (lockMode == Constants.LOCK_MODE_READ_COMMITTED) {
+                        // PageStore is single-threaded, no lock is required
+                        return true;
+                    }
+                    if (!lockSharedSessions.containsKey(session)) {
+                        traceLock(session, exclusive, "ok");
+                        session.registerTableAsLocked(this);
+                        lockSharedSessions.put(session, session);
+                    }
                     return true;
                 }
-                if (!lockSharedSessions.containsKey(session)) {
-                    traceLock(session, exclusive, "ok");
-                    session.registerTableAsLocked(this);
-                    lockSharedSessions.put(session, session);
-                }
-                return true;
             }
         }
         return false;
@@ -441,15 +443,17 @@
     @Override
     public void unlock(Session s) {
         if (database != null) {
-            traceLock(s, lockExclusiveSession == s, "unlock");
-            if (lockExclusiveSession == s) {
-                lockSharedSessions.remove(s);
-                lockExclusiveSession = null;
-            }
-            synchronized (database) {
+            synchronized (this) {
+                traceLock(s, lockExclusiveSession == s, "unlock");
+                if (lockExclusiveSession == s) {
+                    lockSharedSessions.remove(s);
+                    lockExclusiveSession = null;
+                }
                 if (!lockSharedSessions.isEmpty()) {
                     lockSharedSessions.remove(s);
                 }
+            }
+            synchronized (database) {
                 if (!waitingSessions.isEmpty()) {
                     database.notifyAll();
                 }
@@ -495,7 +499,10 @@
         scanIndex.remove(session);
         database.removeMeta(session, getId());
         scanIndex = null;
-        lockExclusiveSession = null;
+        synchronized (this)
+        {
+            lockExclusiveSession = null;
+        }
         lockSharedSessions.clear();
         invalidate();
     }
diff -r --new-file -u a/h2/src/main/org/h2/table/RegularTable.java b/h2/src/main/org/h2/table/RegularTable.java
--- a/h2/src/main/org/h2/table/RegularTable.java	2019-10-14 09:47:23.000000000 +0300
+++ b/h2/src/main/org/h2/table/RegularTable.java	2020-07-10 16:24:07.732177274 +0300
@@ -200,12 +200,15 @@
             // take a local copy so we don't see inconsistent data, since we are
             // not locked while checking the lockExclusiveSession value
             Session copyOfLockExclusiveSession = lockExclusiveSession;
-            if (error == null && copyOfLockExclusiveSession != null) {
-                Table t = copyOfLockExclusiveSession.getWaitForLock();
-                if (t != null) {
-                    error = t.checkDeadlock(copyOfLockExclusiveSession, clash, visited);
-                    if (error != null) {
-                        error.add(session);
+            synchronized (this)
+            {
+                if (error == null && copyOfLockExclusiveSession != null) {
+                    Table t = copyOfLockExclusiveSession.getWaitForLock();
+                    if (t != null) {
+                        error = t.checkDeadlock(copyOfLockExclusiveSession, clash, visited);
+                        if (error != null) {
+                            error.add(session);
+                        }
                     }
                 }
             }
