Я прочитал много комментариев @Transactional, я увидел ответы stackoverflow, но это мне не помогает. Поэтому я задаю свой вопрос.Spring @Transactional TransactionRequiredException или RollbackException
Моим случаем является сохранение пользователя с уникальным электронным письмом. В БД у меня есть пользователь с адресом электронной почты [email protected], и я сохраняю пользователя с тем же адресом электронной почты. Для экономии я должен использовать entityManager.merge()
из-за этого сообщения thymeleaf binding collections не важно.
Первый пример:
@Controller
public class EmployeeController extends AbstractCrudController {
// rest of code (...)
@RequestMapping(value = urlFragment + "/create", method = RequestMethod.POST)
public String processNewEmployee(Model model, @ModelAttribute("employee") User employee, BindingResult result, HttpServletRequest request) {
prepareUserForm(model);
if (!result.hasErrors()) {
try {
saveEmployee(employee);
model.addAttribute("success", true);
} catch (Exception e) {
model.addAttribute("error", true);
}
}
return "crud/employee/create";
}
@Transactional
public void saveEmployee(User employee) {
entityManager.merge(employee);
}
private void prepareUserForm(Model model) {
HashSet<Position> positions = new HashSet<Position>(positionRepository.findByEnabledTrueOrderByNameAsc());
HashSet<Role> roles = new HashSet<Role>(roleRepository.findAll());
User employee = new User();
model.addAttribute("employee", employee);
model.addAttribute("allPositions", positions);
model.addAttribute("allRoles", roles);
}
}
Этот код бросает TransactionRequiredException, я не знаю, почему? Похоже @Transactional аннотаций не работал, так что я переехал аннотацию processNewEmployee()
Второй пример:
@Controller
public class EmployeeController extends AbstractCrudController {
// rest of code (...)
@Transactional
@RequestMapping(value = urlFragment + "/create", method = RequestMethod.POST)
public String processNewEmployee(Model model, @ModelAttribute("employee") User employee, BindingResult result, HttpServletRequest request) {
prepareUserForm(model);
if (!result.hasErrors()) {
try {
entityManager.merge(employee);
model.addAttribute("success", true);
} catch (Exception e) {
model.addAttribute("error", true);
}
}
return "crud/employee/create";
}
private void prepareUserForm(Model model) { /*(.....)*/ }
}
И этот код бросает PersistenceException (из-за ConstraintViolationException) и, конечно, я получил «Сделку отмеченный как rollbackOnly "exeption.
Когда я пытаюсь сохранить электронную почту, которая не существует, этот код работает нормально, поэтому я уверен, что аннотация @Transactional настроена хорошо.
Если это важно, я помещаю свою TransationManagersConfig:
@Configuration
@EnableTransactionManagement
public class TransactionManagersConfig implements TransactionManagementConfigurer {
@Autowired
private EntityManagerFactory emf;
@Autowired
private DataSource dataSource;
@Bean
public PlatformTransactionManager transactionManager() {
JpaTransactionManager tm =
new JpaTransactionManager();
tm.setEntityManagerFactory(emf);
tm.setDataSource(dataSource);
return tm;
}
public PlatformTransactionManager annotationDrivenTransactionManager() {
return transactionManager();
}
}
Не могли бы вы объяснить, что я, что я делаю неправильно, и предложить возможные решения этой проблемы?
Решение:
Благодаря R4J я создал UserService и в моем EmployeeController я использую его вместо entityManager.merge() теперь работает отлично
@Service
public class UserService {
@PersistenceContext
private EntityManager entityManager;
@Transactional
public void merge(User user) {
entityManager.merge(user);
}
}
И EmployeeController:
@Controller
public class EmployeeController extends AbstractCrudController {
@Autowired
private UserService userService;
@RequestMapping(value = urlFragment + "/create", method = RequestMethod.POST)
public String processNewEmployee(Model model, @ModelAttribute("employee") User employee, BindingResult result, HttpServletRequest request) {
// (.....)
userService.merge(employee);
// (.....)
}
}
Thx для вашего ответа и совета по DDD. Я понимаю, что вы написали, и я попытаюсь изменить коэффициент кода. Теперь я обновляю свой вопрос, пожалуйста, посмотрите на мое решение и дайте мне несколько комментариев, если он в порядке или нет, поэтому я мог бы отметить ваш ответ как правильный. – Purzynski
Теперь он выглядит намного лучше. Прокси весной может быть сложным время от времени;) –