spring - 无法使用 spring jpa 获取更新的实体并且唯一约束不会停止更新

标签 spring hibernate spring-data-jpa transactions spring-data

我的情况:公共(public)方法一开始尝试更新实体,最后尝试查询更新的实体并通过 SNS 发送消息。我遇到了两个问题。

第一个问题是,如果我调用DeviceDao.save(),我可以获得更新的实体,但如果我调用自定义更新方法updateAsset,则无法获取更新的实体UpdateClass 中的 code>。

第二个问题是代码仍然会传递到 messagePublisher,即使 UpdateClass.doSth() 抛出 org.hibernate,我也可以在“MessagePublisher.doRealthing()”中获取更新的实体。异常.ConstraintViolationException(我对 Assets ID有唯一的约束),但最终,更新被回滚。

我的问题是,为什么我会遇到这两个问题?对于第二个问题,除了提前查询 Assets Id,如何避免?

这是我的代码。

public interface ExampleDeviceDao extends JpaRepository<Device, UUID>, JpaSpecificationExecutor<Device> {

    @Modifying
    @Query("UPDATE device a SET a.asset = ?1 WHERE a.device = ?2")
    int updateAsset(UUID asset, UUID device);

}

我的公共(public)服务和方法:


@Component
public class Service {
    @Autowired
    UpdateClass updateClass;
    @Autowired
    MiddleClass middleClass;
    @Autowired
    MessagePublisher messagePublisher;

    @org.springframework.transaction.annotation.Transactional
    public void updateAsset(UUID deviceId, UUID assetId) {
        updateClass.doSth(deviceId, assetId);
        middleClass.doSth(deviceId, assetId);
        messagePublisher.doSth(deviceId, assetId);
    }
}
public abstract class AbstractClass {

    protected abstract void doRealThing(UUID deviceId, UUID assetId);

    public void doSth(UUID deviceId, UUID assetId) {
        doRealThing(deviceId, assetId);
    }
}

@Component
public class UpdateClass extends AbstractClass{

    @Autowired
    ExampleDeviceDao deviceDao;

    protected void doRealThing(UUID deviceId, UUID assetId) {
        Optional<Device> device = deviceDao.findById(deviceId);
        if (device.isPresent()) {
            device.get().setAsset(assetId);
            /** approach 1:*/
            deviceDao.save(device.get());
            /**
             * approach 2:
             * deviceDao.updateAsset(assetId, deviceId);
             */
        }
    }
}
@Component
public class MiddleClass extends AbstractClass{


    protected void doRealThing(UUID deviceId, UUID assetId) {
        //do other things, not db update or query.
    }
}
@Component
public class MessagePublisher extends AbstractClass{

    @Autowired
    ExampleDeviceDao deviceDao;
    @Autowired
    SNSMessagePublisher snsMessagePublisher;

    protected void doRealThing(UUID deviceId, UUID assetId) {
        Optional<Device> device = deviceDao.findById(deviceId);
        if (device.isPresent()) {
            snsMessagePublisher.publishMessage(device.get());
        }
    }
}

最佳答案

问题可能是您的第一级缓存(也称为持久性上下文)包含您正在执行 DML 语句(更新设备...)所针对的实体。但 Hibernate 并不知道您的 DML 语句将更改持久性上下文中实体的状态,并且对此也无法执行任何明智的操作。因此,更改是在数据库上执行的,但持久性上下文中的实体仍然具有旧状态。您可以做的唯一明智的事情是刷新实体(如果需要),或者通过调用 EntityManager.detach() 将其从持久化上下文中删除。

据我了解您的第二个问题,即使数据库事务失败,您的发布者代码也会发布 SNS 消息。在这种情况下,您始终会遇到可能的问题,因为 SNS 客户端不是交易的一部分,也不可​​能成为交易的一部分。

您可以在交易完成后发送消息

如果事务完成后 JVM 关闭但尚未发送 SNS 消息,或者 SNS 消息由于某种原因发送失败,您可能会错过发送一些消息。

为了解决此类问题,您通常会使用某种具有重试机制的作业队列。如果您对此问题的解决方案感兴趣,可以查看 Blaze-Notify这是一个可以用来有效实现这一点的工具包。您无需立即发送 SNS 消息,而是持久保存一个表示该消息的实体,稍后将对该消息进行异步处理并通过重试机制发送。

关于spring - 无法使用 spring jpa 获取更新的实体并且唯一约束不会停止更新,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73299764/

相关文章:

java - mysql如何建立两个表之间的关系

java - Hibernate 不改变现有的列是一个缺点吗?

java - 使用实体管理器时,没有为该名称定义查询

java - 我可以在 Java 中聚合、代理或模仿 @SuppressWarnings 吗?

java - hibernate 多对一外键未设置

java - 具有规范和分页支持的 Spring 数据分组

java - 通过 HTTPS 403 禁止的 Websocket

java - 如何对@Any 注释属性进行双向映射?

java - 减少hibernate需要的查询数量

java - Spring Data JPA 乐观锁定与旧版 DB2/400