Browse Source

Detach RuleChainDetailsEntity after findById to prevent stale version conflict

RuleChainEntity and RuleChainDetailsEntity map to the same DB table.
When RuleChainDetailsEntity is loaded into the persistence context
(e.g. during isUpdateNeeded metadata comparison) and then the same row
is updated via RuleChainEntity (during saveRuleChain), the cached
RuleChainDetailsEntity becomes stale. Subsequent save via
RuleChainDetailsEntity fails with OptimisticLockException.

Fix: detach the entity immediately after loading in findById so it
does not linger in the persistence context.
pull/15361/head
Viacheslav Klimov 6 months ago
parent
commit
def602902a
Failed to extract signature
  1. 12
      dao/src/main/java/org/thingsboard/server/dao/sql/rule/JpaRuleChainDetailsDao.java

12
dao/src/main/java/org/thingsboard/server/dao/sql/rule/JpaRuleChainDetailsDao.java

@ -23,12 +23,14 @@ import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.StringUtils;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.rule.RuleChainDetails;
import org.thingsboard.server.dao.DaoUtil;
import org.thingsboard.server.dao.model.sql.RuleChainDetailsEntity;
import org.thingsboard.server.dao.rule.RuleChainDetailsDao;
import org.thingsboard.server.dao.sql.JpaAbstractDao;
import org.thingsboard.server.dao.util.SqlDao;
import org.thingsboard.server.exception.DataValidationException;
import java.util.Optional;
import java.util.UUID;
@Slf4j
@ -39,6 +41,16 @@ public class JpaRuleChainDetailsDao extends JpaAbstractDao<RuleChainDetailsEntit
private final RuleChainDetailsRepository ruleChainDetailsRepository;
@Override
public RuleChainDetails findById(TenantId tenantId, UUID key) {
Optional<RuleChainDetailsEntity> entity = getRepository().findById(key);
// Detaching to avoid stale version conflict with RuleChainEntity which maps to the same table.
// Without detach, a loaded RuleChainDetailsEntity stays in the persistence context and becomes stale
// when the same row is updated via RuleChainEntity (e.g. during rule chain import with circular references).
entity.ifPresent(e -> getEntityManager().detach(e));
return DaoUtil.getData(entity);
}
@Override
public RuleChainDetails save(TenantId tenantId, RuleChainDetails ruleChainDetails) {
try {

Loading…
Cancel
Save