Spring boot jpa предотвращает автообновление - PullRequest
0 голосов
/ 02 марта 2020

У меня есть вопрос о Jpa и параллельном доступе. Вот пример кода

Пользователь

@Entity
public class User {

    @Id
    @GeneratedValue
    private Long id;

    private String firstName;

    private String lastName;

    ...

UserService

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);
    }
}

, если я вызываю обе конечные точки одновременно (GET перед POST), метод getFirstName будет перезаписывать обновление, потому что в конце транзакции JPA сделает неявное сохранение, даже если обновления нет. Мое обновление будет перезаписано, так как в начале моего метода getFirstName я загружаю пользователя со старым именем

Есть ли способ отключить syn c, если мы не вызываем метод save хранилище? Я не хочу отделять сущность каждый раз. Более того, я не хочу помещать транзакцию только для чтения (может быть, мне нужно обновить другую сущность в методе 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 не имеет равных метод ... большая ошибка. Это объясняет это поведение. Спасибо!

Ответы [ 2 ]

1 голос
/ 02 марта 2020

Как указал М. Дейн, вы должны что-то изменить в объекте 'User' в 'getFirstName', чтобы произошло обновление, иначе hibernate не обновит сущность в базе данных.

Это, как говорится, лучшая практика, это вернуть весь объект «Пользователь» из службы

public User getUser(Long userId) throws InterruptedException {
    return userRepository.findById(userId).orElse(null); // or throw an expection / return optional
}

Затем вы бы использовали службу:

userService.getUser().getFirstname()

Это гораздо более гибкий и неявно предотвращает подобные проблемы

1 голос
/ 02 марта 2020

При удалении @Transactional persistanceContext не будет сброшен. Или вы можете иметь @Transactional (readOnly = true). Вы можете прочитать больше здесь: https://vladmihalcea.com/spring-read-only-transaction-hibernate-optimization/

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...