![](/img/trans.png)
[英]Hibernate Spring JPA javax.persistence.TransactionRequiredException: No transactional EntityManager available
[英]Spring @Transactional TransactionRequiredException or RollbackException
我已經閱讀了很多@Transactional批注,我看到了stackoverflow的答案,但對我沒有幫助。 所以我要提出我的問題。
我的情況是用唯一的電子郵件保存用戶。 在數據庫中,我有一個使用電子郵件xxx@xxx.com的用戶,並且正在使用相同的電子郵件地址保存該用戶。 為了保存,我必須使用entityManager.merge()
因為此后胸腺葉綁定集合不重要。
第一個例子:
@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”示例。
當我嘗試保存不存在的電子郵件時,此代碼可以正常工作,因此我認為@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);
// (.....)
}
}
您的交易無效,因為您直接從“公共字符串processNewEmployee”方法中調用“ this.saveEmployee(...)”。
怎么會?
當添加@Transactional時,Spring為您的組件創建一個代理,並代理所有公共方法。 因此,當Spring本身將您的方法作為HTTP Rest Request調用時,它被認為是通過代理正確進行的外部調用,並且根據需要啟動了新的Transaction,並且代碼可以正常工作。
但是,當您具有代理組件並在類代碼中調用“ this.saveEmployee”(具有@Transactional批注)時,實際上實際上是在繞過已創建的代理Spring,並且不會啟動新的Transaction。
解決方案:將整個數據庫邏輯提取到某種服務或DAO中,然后將其自動連接到Rest Controller。 然后,一切都應該像魅力一樣起作用。
無論如何,您都應避免從Controllers直接訪問數據庫,因為這不是很好的做法。 控制器應該盡可能的薄,並且不包含任何業務邏輯,因為它只是訪問系統的一種方式。 如果您的整個邏輯都在“域”中,那么您只需幾行代碼就可以添加其他方式來運行業務功能(例如創建新用戶)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.