From a829bf1996622b4a3a13f69e3c789375edc1d58f Mon Sep 17 00:00:00 2001 From: waterWang Date: Thu, 20 Aug 2026 05:30:00 +0000 Subject: [PATCH] fix: release START_TXN nesting level on persist() SQLException path (#13905) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GenericDaoBase.persist() calls txn.start() which pushes a START_TXN nesting level onto the caller's transaction stack. The SQLException catch block throws without reaching txn.commit(), so the nesting level is leaked. The caller's subsequent commit() finds the transaction unbalanced and silently no-ops — all caller work in that batch is lost with no error. Fix: track commit success and roll back the START_TXN level in a finally block when commit() was not reached, ensuring the caller's transaction is restored to a balanced state instead of silently abandoning its work. Closes #13905 Signed-off-by: waterWang --- .../db/src/main/java/com/cloud/utils/db/GenericDaoBase.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/framework/db/src/main/java/com/cloud/utils/db/GenericDaoBase.java b/framework/db/src/main/java/com/cloud/utils/db/GenericDaoBase.java index dcd863465d1b..10f035528992 100644 --- a/framework/db/src/main/java/com/cloud/utils/db/GenericDaoBase.java +++ b/framework/db/src/main/java/com/cloud/utils/db/GenericDaoBase.java @@ -1625,6 +1625,7 @@ public T persist(final T entity) { final TransactionLegacy txn = TransactionLegacy.currentTxn(); PreparedStatement pstmt = null; String sql = null; + boolean committed = false; try { txn.start(); for (final Pair pair : _insertSqls) { @@ -1673,6 +1674,7 @@ public T persist(final T entity) { insertElementCollection(entity, _idAttributes.get(_table)[0], id, ecAttributes); } txn.commit(); + committed = true; } catch (final SQLException e) { logger.error("DB Exception on: " + pstmt, e); handleEntityExistsException(e); @@ -1681,6 +1683,10 @@ public T persist(final T entity) { throw new CloudRuntimeException("Problem with getting the ec attribute ", e); } catch (IllegalAccessException e) { throw new CloudRuntimeException("Problem with getting the ec attribute ", e); + } finally { + if (!committed) { + txn.rollback(); + } } return _idField != null ? findByIdIncludingRemoved(id) : null;