我的 JPA 合并功能遇到一些奇怪的问题。我正在尝试获取用户的上次登录时间,并且希望在用户登录时更新数据库中的用户。
成功登录事件的应用程序监听器:
@Component
public class SuccessLoginApplicationListener implements ApplicationListener<AuthenticationSuccessEvent>{
@Autowired
private UserDao userDao;
@Override
public void onApplicationEvent(AuthenticationSuccessEvent loginEvent) {
User user = (User) loginEvent.getAuthentication().getPrincipal();
user.setLastLogin(100000);
userDao.merge(user);
}
}
用户Dao
@Transactional
@Repository("userDao")
public class UserDao{
protected EntityManager em;
@PersistenceContext
public void setEntityManager(EntityManager em) {
this.em = em;
}
public User merge(User user){
return em.merge(user);
}
}
因为实际的代码包括一堆接口(interface)、其他方法等,所以上面的代码应该包括与这个问题相关的所有重要内容,我希望我没有忘记一些东西。
当我在 Controller 中执行以下操作时:
@Controller
@RequestMapping("/profile")
public class ProfileController {
@Autowired
private UserDao userDao;
@RequestMapping(value="", method=RequestMethod.GET)
public String profile(Model model){
User user = getCurrentlyLoggedInUser();
user.setLastLogin(1000000);
userDao.merge(user);
return "account/profile";
}
}
一切都按照我的预期进行,数据库成功更改为新的lastLogin 值。
问题是,当成功登录时,即使我执行与 Controller 中完全相同的操作,数据库也不会获取更新...我已经确认这些方法实际上被调用了( onApplicationEvent
、合并
)。
我完全不知道为什么它在 ApplicationListener
中不起作用,但它在 Controller 中起作用。我是否没有正确理解合并功能?
我读到了以下内容:当您调用合并时,会返回一个托管实体,并且对托管实体的更改应该会在数据库中更新,因此我还在 userDao
中尝试了以下操作:
public User merge(User user){
User user = em.merge(user);
user.setLastLogin(100000);
}
这里也发生同样的事情,当从 ApplicationListener 调用合并函数时,数据库中没有任何更改,但是当从 Controller 调用它时,该字段被正确设置为 100000。
感谢您的阅读,希望对您有所帮助! :)
最佳答案
一般来说,当事务在一种情况下不起作用而在另一种情况下起作用时,您就会拥有一个组件的多个实例。一个应用了 AOP,另一个没有应用。
这通常来自于具有相同的 <context:component-scan />
在 ContextLoaderListener
加载的上下文中和DispatcherServlet
。在具有附加 <tx:annotation-driven />
的上下文中加载的那个将进行有效交易,而其他则不会。
您的ContextLoaderListener
应该加载应用程序全局的所有 bean(服务、daos、数据源等并应用了事务)。您的DispatcherServlet
通常应该只加载与 Web 相关的东西( Controller 、 View 解析器等)。
关于java - JPA 合并在 ApplicationListener 中不起作用,但在 Controller 中起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29791047/