首页 > 解决方案 > Spring Boot jpa 防止自动更新

问题描述

我有一个关于 Jpa 和并发访问的问题。这里有一个示例代码

用户

@Entity
public class User {

    @Id
    @GeneratedValue
    private Long id;

    private String firstName;

    private String lastName;

    ...

用户服务

public class UserService {

    private final UserRepository userRepository;

    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    @Transactional
    public String getFirstName(Long userId) throws InterruptedException {
        User user = userRepository.findById(userId).get();
        Thread.sleep(5000L); // 5s
        // ...
        return user.getFirstname();
    }

    @Transactional
    public void updateUser(Long userId, String firstName, String lastName) {
        User user = userRepository.findById(userId).get();
        user.setFirstname(firstName);
        user.setLastname(lastName);
        userRepository.save(user);
    }
}

如果我同时调用两个端点(POST 之前的 GET),getFirstName 方法将覆盖更新,因为在事务结束时,即使没有更新,JPA 也会进行隐式保存。我的更新将被覆盖,因为在我的 getFirstName 方法开始时,我用旧的名字加载用户

如果我们不调用存储库的保存方法,有没有办法禁用同步?我不想每次都分离实体。此外,我不想将事务置于只读状态(也许我需要在 getFirstName 方法中更新另一个实体)。

如果我没有进行任何更改,我不希望 JPA 自动保存我的实体。由于并发访问,这可能是一个问题。

谢谢


编辑(解决)

我为属性用户使用了转换器

@Entity
public class User {

    @Id
    @GeneratedValue
    private Long id;

    private String firstName;

    private String lastName;

    @Convert(converter = SimpleConverter.class)
    private customObject object;
    ...

@Component
@Converter
public class SimpleConverter implements AttributeConverter<CustomObject, String> {

    private static ObjectMapper objectMapper;

    @SneakyThrows
    @Override
    public String convertToDatabaseColumn(CustomObject object) {

        if (Objects.isNull(object)) {
            return null;
        }

        return objectMapper.writeValueAsString(object);
    }

    @SneakyThrows
    @Override
    public CustomObject convertToEntityAttribute(String data) {

        if (StringUtils.isBlank(data)) {
            return null;
        }
        return objectMapper.readValue(data, CustomObject.class);
    }

    @Autowired
    public void setObjectMapper(ObjectMapper objectMapper) {
        TutorialConverter.objectMapper = objectMapper;
    }
}

我无法解释为什么,但是使用此转换器,即使我没有进行任何更改,我的实体也会在每次事务结束时在数据库中更新。

我删除了这个属性,现在当两个方法同时执行时,getFirstName 方法不会覆盖数据


编辑 2

CustomObject 类没有 equals 方法……大错误。这解释了这种行为。谢谢 !

标签: springspring-bootjpa

解决方案


通过删除@Transactional,persistanceContext 将不会被刷新。或者你可以有@Transactional(readOnly=true)。您可以在此处阅读更多信息:https ://vladmihalcea.com/spring-read-only-transaction-hibernate-optimization/


推荐阅读