Я сохраняю несколько объектов, используя CrudRepository.save(Iterable<S>)
.
Является ли это поведение операции атомарным?
Что произойдет, если я сохраню 10 объектов, а для 6-го не получится?
Да, это атомарно. SimpleJpaRepository
— это реализация по умолчанию для интерфейса CrudRepository
. Метод save
помечен Transactional
при реализации. Так что в случае какой-либо ошибки все будет откатываться.
@Transactional
public <S extends T> List<S> save(Iterable<S> entities) {
List<S> result = new ArrayList();
if (entities == null) {
return result;
} else {
Iterator var3 = entities.iterator();
while(var3.hasNext()) {
S entity = var3.next();
result.add(this.save(entity));
}
return result;
}
}
@ Юджин, я думаю, он имел в виду: Yes, it is atomic
. Что в этом плохого ?
@NiVeR ничего плохого если он это имел в виду ... и в таком случае потребуется правильное редактирование
Евгений и NiveR, Спасибо за отзыв. Я отредактировал свой ответ.
Согласно документация, вот как выглядит saveAll:
@Transactional
public <S extends T> List<S> saveAll(Iterable<S> entities)
Но чтобы быть уверенным, что это будет работать как одна атомарная транзакция, вам нужно:
1) Убедитесь, что транзакции поддерживают работу на вас
2) Убедитесь, что для autocommit установлено значение false (необязательно, если не сработает)
Spring отключает автофиксацию для методов @Transactional (когда такой метод выполняется и возвращается к предыдущей настройке после завершения), поэтому пункт 2 не нужен.
@Lesiak Раньше у меня были проблемы с autocomit=true + Spring Boot 1.5 + MariaDB. На самом деле это не работало как отдельная атомарная транзакция, прежде чем я отправил autocommit + autocommit по умолчанию на false. Добавьте необязательную метку к # 2, спасибо
За увиденным вот что происходит в случае SimpleJpaRepository
метода сохранения с помощью Iterable
@Transactional
public <S extends T> List<S> More save(Iterable<S> entities) {
List<S> result = new ArrayList<S>();
if (entities == null) {
return result;
}
for (S entity : entities) {
result.add(save(entity));
}
return result;
}
Стоит отметить, что сохранение с Iterable
изменилось на saveAll
в последних версиях.
См. изменения для более подробной информации
What will happen if I save 10 entities and it fails for 6th one?
По умолчанию CrudRespository
будет иметь @Transactional
, поэтому в случае исключения ничего не сохраняется.
В случае обработки вручную это будет работать
Если вы делаете что-то подобное, это будет откат.
@Transactional(rollbackFor=RuntimeException.class)
public List<Car> saveAllOrNone(List<Car> cars) {
for(Car car: cars) {
repo.save(car);
}
}
Все методы IIRC из
CrudRepository
по умолчанию получат аннотацию@Transactional
, поэтому сбой ничего не сохранит в БД.