![](/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.