You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@seata.apache.org by "lhozy (via GitHub)" <gi...@apache.org> on 2026/06/17 11:06:53 UTC
[I] Global lock batch acquire always fails on Dameng(DM): LockStoreDataBaseDAO.doAcquireLocks relies on executeBatch().length [incubator-seata]
lhozy opened a new issue, #8144:
URL: https://github.com/apache/incubator-seata/issues/8144
# [Bug] Global lock batch acquire always fails on Dameng (DM) — `LockStoreDataBaseDAO.doAcquireLocks` relies on `executeBatch().length`
## Ⅰ. Describe the bug
When the Seata Server uses **DB store mode** with a **Dameng (DM)** database, any branch transaction that needs to acquire **two or more row locks** in a single `BranchRegister` **always fails** to acquire the global lock, even though the `lock_table` is empty and there is no real conflict.
The client side gets:
```
io.seata.rm.datasource.exec.LockConflictException: get global lock fail, xid:..., lockKeys:XXX:1;YYY:2
```
The server side logs:
```
LockStoreDataBaseDAO : Global lock batch acquire failed, xid ... branchId ... pks [1, 2]
AbstractExceptionHandler : this request cannot acquire global lock ...
```
A branch that locks only **one** row works fine. So in practice **any business transaction that modifies 2+ rows (master/detail, entity + i18n text, etc.) can never commit**, which makes AT mode effectively unusable on DM for real workloads.
## Ⅱ. Root cause
`org.apache.seata.server.storage.db.lock.LockStoreDataBaseDAO#doAcquireLocks`:
```java
protected boolean doAcquireLocks(Connection conn, List<LockDO> lockDOs) throws SQLException {
...
for (LockDO lockDO : lockDOs) {
... ps.addBatch();
}
return ps.executeBatch().length == lockDOs.size(); // <-- here
}
```
It judges batch success by `executeBatch().length == lockDOs.size()`.
The DM JDBC driver (`DmdbPreparedStatement`) implements batch execution via `executeBatchByRow()` and **aggregates** the per-statement results through `ExecuteRetInfo.union(...)`, so `executeBatch()` returns an `int[]` whose **length does not equal the number of batched statements**.
As a result:
- The lock rows **are actually inserted** into `lock_table`.
- But `executeBatch().length == lockDOs.size()` evaluates to **false**.
- `doAcquireLocks` returns `false`, the caller does `conn.rollback()` (the inserted lock rows are discarded), and the branch register is reported as a lock conflict.
Single-row branches take the `doAcquireLock` (non-batch) path, which does not have this check, so they succeed — which is why the failure only appears for multi-row branches.
> Per the JDBC spec, the return value of `Statement.executeBatch()` is an array of update counts where each element may be a count, `SUCCESS_NO_INFO (-2)`, or `EXECUTE_FAILED (-3)`. Assuming `length == number of statements` is not guaranteed across drivers; relying on it is the bug.
## Ⅲ. How to reproduce
1. Seata Server `store.mode=db`, store DB = Dameng (DM8).
2. Any AT-mode business transaction whose single branch updates/inserts **≥ 2 rows** (so the branch reports `lockKey` with 2+ pks).
3. Branch register fails with `Global lock batch acquire failed` against an empty `lock_table`.
## Ⅳ. Expected behavior
The batch lock acquire should succeed when the lock rows are inserted without conflict, regardless of the driver-specific length of the `executeBatch()` return array. Real conflicts (duplicate `row_key`) still surface as `SQLIntegrityConstraintViolationException` and are already handled.
## Ⅴ. Environment
- Seata version: **2.6.0** (the same code is present on the current `2.x` branch).
- DB store: Dameng (DM8), DM JDBC driver `DmJdbcDriver18`.
- The fix is proposed in the accompanying PR.
## Ⅵ. Suggested fix
Stop relying on `executeBatch().length`. Detect failure via `Statement.EXECUTE_FAILED` instead:
```java
int[] result = ps.executeBatch();
for (int updated : result) {
if (updated == java.sql.Statement.EXECUTE_FAILED) {
return false;
}
}
return true;
```
This is correct for drivers that return one element per statement and for drivers (like DM) that aggregate the result array, while preserving the existing conflict handling (the `catch (SQLIntegrityConstraintViolationException ...)` branch).
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: notifications-unsubscribe@seata.apache.org.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@seata.apache.org
For additional commands, e-mail: notifications-help@seata.apache.org
Re: [I] Global lock batch acquire always fails on Dameng(DM): LockStoreDataBaseDAO.doAcquireLocks relies on executeBatch().length [incubator-seata]
Posted by "funky-eyes (via GitHub)" <gi...@apache.org>.
funky-eyes closed issue #8144: Global lock batch acquire always fails on Dameng(DM): LockStoreDataBaseDAO.doAcquireLocks relies on executeBatch().length
URL: https://github.com/apache/incubator-seata/issues/8144
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: notifications-unsubscribe@seata.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@seata.apache.org
For additional commands, e-mail: notifications-help@seata.apache.org