Java EE应用登录无法获取数据库新数据的技术求助
从你的描述和代码来看,核心问题很明确:你的myList数据是在服务器启动时通过@PostConstruct初始化的,之后再也没有重新加载过。@PostConstruct注解的方法只会在Bean第一次初始化(也就是服务器启动阶段)执行一次,所以后续数据库里的新增、删除操作,根本不会触发这个方法重新获取数据,自然就看不到变化了——重启服务器会重新初始化Bean,所以能看到新数据,但之后又回到老问题。
下面给你几个针对性的解决方案,按推荐程度排序:
1. 去掉内存缓存,每次使用时直接查询数据库
这是最直接也最不容易出错的方案,尤其如果首页数据访问频率不是极高的话,完全可以接受。
修改你的代码,去掉缓存myList的字段,改成每次需要数据时直接调用mc.getDataList():
private MyClass mc; // 移除缓存的myList字段,新增获取方法 public List<MyData> getMyDataList() { return mc.getDataList(); }
这样每次首页需要数据时,都会实时从数据库查询,再也不会有数据不一致的问题。
2. 保留缓存,但实现主动刷新机制
如果因为性能原因必须缓存数据,那你需要在数据发生变更(新增、删除、修改)的业务逻辑里,主动调用刷新方法更新内存中的myList:
private MyClass mc; private List<MyData> myList; @Override @PostConstruct public void initDefaults() { refreshMyDataList(); // 初始化时加载一次 } // 新增刷新方法,在数据变更后调用 public void refreshMyDataList() { myList = mc.getDataList(); } // 对外提供获取数据的方法 public List<MyData> getMyDataList() { return myList; }
比如当你新增一条MyData后,调用这个refreshMyDataList()方法,就能让内存中的数据和数据库同步。
3. 检查JPA二级缓存/查询缓存配置
如果你的JPA提供者(比如Hibernate)开启了二级缓存,或者给FINDALL这个命名查询配置了查询缓存,也会导致数据一直从缓存读取,不查数据库。你可以在查询时强制绕过缓存或者刷新缓存:
修改MyClass中的fetchAllData方法:
public List<MyData> fetchAllData(){ return this.em.createNamedQuery(someClass.FINDALL) // 强制绕过缓存,直接查询数据库 .setHint("javax.persistence.cache.retrieveMode", CacheRetrieveMode.BYPASS) .getResultList(); }
或者检查你的实体类注解,是不是设置了只读缓存(比如@Cacheable(true)+缓存策略为只读),如果是,修改缓存策略为读写模式。
4. 确认Bean的作用域
如果你的这个Bean是@Singleton(单例)作用域,那@PostConstruct确实只会执行一次。如果首页数据是用户相关的,考虑改成@SessionScoped或者@RequestScoped,这样每个会话/请求都会重新初始化Bean,自然能拿到最新数据——不过如果是全局公共数据,这个方案不适用。
内容的提问来源于stack exchange,提问作者Mikachu

