У меня есть вопрос о 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 не имеет равных метод ... большая ошибка. Это объясняет это поведение. Спасибо!