У меня очень простое приложение для загрузки Spring Boot/JPA с контроллером, уровнем сервиса и репозиторием, который не сохраняет обновления, насколько я понимаю должен.Spring Boot JPA @Transactional @Service не обновляется, но @Transactional в контроллере
Тривиальным Entity:
@Entity
public class Customer {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
private String name;
protected Customer() {}
public Customer(String name) { this.name = name; }
// standard getters,setters //
}
Тривиальным Repository:
@Repository
public interface CustomerRepository extends CrudRepository<Customer, Long> {}
Простой Сервис слой:
// If the service is @Transactional and the controller is not, the update does NOT occur
@Transactional
@Service
public class CustomerService {
private static final Logger LOG = getLogger(CustomerService.class);
@Autowired
private CustomerRepository customerRepository;
boolean updateCustomerName(Long id, String name) {
Customer customer = customerRepository.findOne(id);
if (customer == null) { return false; }
// Modifies the entity
customer.setName(name);
// No explicit save()
return true;
}
}
И контроллер REST, который использует все:
// If the controller is @Transactional and the service is not, the update occurs
@RestController
@RequestMapping("/mvc")
public class CustomerController {
@Autowired
private CustomerService customerService;
@RequestMapping(path = "{id}", method = RequestMethod.PUT)
public ResponseEntity updateCustomerName(@PathVariable Long id, @RequestParam("name") String name) {
customerService.updateCustomerName(id,name);
return ResponseEntity.noContent().build();
}
}
Они соединены друг с другом с помощью простого однострочника SpringBootApplication
Я SQL журналов отладки включен и увидеть выбирает, обновления и т.д.
С выше код: Если метод обслуживания вызывается контроллер, модифицированный объект не не использовался. Журналы SQL показывают select
объекта, но не update
.
Там также не обновление, если ничего не будет помечен @Transactional
Однако, просто перемещая @Transactional
аннотации из класса обслуживания в класс контроллера, то SQL update
делает происходит.
Если я добавлю явный метод customerRepository.save(customer)
к методу службы, это обновление также произойдет. Но я понимаю, что ORM автоматически сохраняет измененные постоянные объекты.
Я уверен, что проблема имеет какое-то отношение к жизненному циклу EntityManager в веб-запросе, но я озадачен. Нужно ли выполнять дополнительную настройку?
Полный пример на https://github.com/monztech/SO-41515160
EDIT: Эта задача была решена, смотри ниже. В спецификации Spring @Transactional
не работает в пакетах-частных методах и по ошибке не делает метод службы обновлений общедоступным.
Обновление произойдет, если метод public
, а класс обслуживания содержит аннотацию @Transactional
.
У меня есть другой вопрос, однако. Почему нужна аннотация для @Transactional
? (обновление не происходит без него). Должен ли диспетчер объектов по-прежнему сохранять объект из-за механизма открытого сеанса, который использует Spring, независимо от какой-либо транзакции?
Попробуйте использовать @Transactional (readOnly = false), хотя значение по умолчанию - false.Это немного странно, потому что, если метод findOne извлекает значения из БД, этот метод корректно работает с @Transactional (работающим внутри транзакционного контекста, завернутым декодером TransactionalManager и так далее ...). И да, Клиент в этом транзакционном контексте управляется в постоянном контексте jpa, поэтому он должен быть обновлен при возврате метода. – Dani
readOnly = false не влияет. Благодарю. Это странно. Я ветеран Hibernate/Spring, но раньше не использовал его в Spring Boot. Кажется, я пропустил какой-то шаг, но мне не повезло. – Monz
Интересный вопрос. Можете ли вы попробовать 2 вещи, чтобы увидеть, что происходит. 1. Сделайте общедоступным метод службы и попробуйте добавить транзакционную аннотацию непосредственно к методу. 2. Независимо от 1, в вашем коде, как есть (кроме создания общедоступного метода), создайте интерфейс, который определяет метод обновления, и ваша служба реализует этот интерфейс. –