jeesite缓存问题
来源:互联网 发布:嵇康 山涛 知乎 编辑:程序博客网 时间:2024/05/22 14:27
jeesite,其框架主要为:
后端
核心框架:Spring Framework 4.0
安全框架:Apache Shiro 1.2
视图框架:Spring MVC 4.0
服务端验证:Hibernate Validator 5.1
布局框架:SiteMesh 2.4
工作流引擎:Activiti 5.15、FoxBPM 6
任务调度:Spring Task 4.0
持久层框架:MyBatis 3.2
数据库连接池:Alibaba Druid 1.0
缓存框架:Ehcache 2.6、Redis
日志管理:SLF4J 1.7、Log4j
工具类:Apache Commons、Jackson 2.2、Xstream 1.4、Dozer 5.3、POI 3.9
2、前端
JS框架:jQuery 1.9。
CSS框架:Twitter Bootstrap 2.3.1。
客户端验证:JQuery Validation Plugin 1.11。
富文本:CKEcitor
文件管理:CKFinder
动态页签:Jerichotab
手机端框架:Jingle
数据表格:jqGrid
对话框:jQuery jBox
下拉选择框:jQuery Select2
树结构控件:jQuery zTree
日期控件: My97DatePicker
这里对于jeesite,感觉其功能还是挺强大的,但是有一点致命缺点,就是其缓存机制,本来缓存是为了提速,但是,当这里的缓存加上了MVC,并且在前端进行请求后,不适时宜地将请求的相关类对象进行缓存,这就导致了单例化和伪持久化。怎么说来?就是说,当前端修改Person对象实例,并提交到服务端试图保存时,由于某些原因,如权限不足导致保存失败,这本来应该是很正常的,但是,偏偏由于在这之前,缓存将Person对象实例更新了,从而缓存中的该实例是修改后的,这样,后来再次获取该对象,由于缓存存在,优先取缓存而不是从DB里获取,导致,后来获取的对象的数据都是错误的(修改但保存失败的),这就变相单例化,而且是无法获得正确数据了。
例如如下的接口
- @RequiresPermissions("sys:user:edit")
- @RequestMapping(value = "save")
- public String save(User user, HttpServletRequest request, Model model, RedirectAttributes redirectAttributes) {
- //判断是否有权限修改用户信息
- //先清缓存:因为框架原因,只要更新了该用户,则会同步更新该用户缓存,从而无法获得真正的该用户信息,所以需要清除掉该缓存,这里先注释掉,看问题
- //UserUtils.clearCache(user);
- User oldUser = systemService.getUser(user.getId());
- List<String>roleIdListOld = oldUser.getRoleIdList();
- User operator = UserUtils.getUser();
- List<String>roleIdListOperator = operator.getRoleIdList();
- //自己不能修改自己的权限
- // if(user.getId().equals(operator.getId())){
- // addMessage(model, "修改用户信息失败, 不能修改自己的权限");
- // UserUtils.clearCache();
- // return form(oldUser, model);
- // }
- if(!roleIdListOperator.containsAll(roleIdListOld)){
- addMessage(model, "修改用户信息失败, 您的权限不足");
- UserUtils.clearCache();
- return form(oldUser, model);
- }
- user.setRoleList(roleList);
- // 保存用户信息
- systemService.saveUser(user);
- // 清除当前用户缓存
- if (user.getPhone().equals(UserUtils.getUser().getPhone())){
- UserUtils.clearCache();
- //UserUtils.getCacheMap().clear();
- }
- addMessage(redirectAttributes, "保存用户'" + user.getPhone() + "'成功");
- return "redirect:" + adminPath + "/sys/user/list?repage";
- }
再看下getUser:
- public static User getUser(String id){
- User user = (User)CacheUtils.get(USER_CACHE, USER_CACHE_ID_ + id);
- if (user == null){
- user = userDao.get(id);
- if (user == null){
- return null;
- }
- user.setRoleList(roleDao.findList(new Role(user)));
- CacheUtils.put(USER_CACHE, USER_CACHE_ID_ + user.getId(), user);
- CacheUtils.put(USER_CACHE, USER_CACHE_LOGIN_NAME_ + user.getPhone(), user);
- }
- return user;
- }
这里的
- systemService.getUser(user.getId());
所以,即使在
- if(!roleIdListOperator.containsAll(roleIdListOld)){
- addMessage(model, "修改用户信息失败, 您的权限不足");
- UserUtils.clearCache();
- return form(oldUser, model);
- }
- getUser(user.getId());
也相当于单例的、全局的实例值
解决方法:
在关系到修改等的地方,每次都需要对该实例进行缓存的清空。同时,在修改时,修改对象最好就是拿出db的该记录,逐个参数进行修改替换:
- @RequiresPermissions("user:list:edit")
- @RequestMapping(value = "editUserInfoSave")
- public String editUserInfoSave(User user,Model model, RedirectAttributes redirectAttributes) {
- //先清除该user的缓存,防止干扰到其他地方的引用。其实还是会有并发问题,会在清除之前被引用到
- UserUtils.clearCache(user);
- //从db中获取user,注意这个userSave 是修改前的,与user的值不一样,注意一点:如果直接从getUser(user.getId());中获取,同时并没有清缓存的前提下
- //UserUtils.clearCache(user);则会导致拿到的user并非DB里的user,而是缓存前端提交的
- User userSave = systemService.getUserFromDB(user.getId());
- /**
- * 替换更新修改信息
- */
- userSave.setName(user.getName());
- userSave.setFirstnameStr(user.getFirstnameStr());
- userSave.setLastnameStr(user.getLastnameStr());
- userSave.setIdStr(user.getIdStr());
- userSave.setUsername(user.getUsername());
- userSave.setBirthdateStr(user.getBirthdateStr());
- userSave.setEmail(user.getEmail());
- userSave.setUserType(user.getUserType());
- userSave.setGenderStr(user.getGenderStr());
- // 保存用户信息
- systemService.saveUser(userSave);
- addMessage(redirectAttributes, "保存用户'" + user.getPhone() + "'成功");
- return "redirect:" + adminPath + "/user/user/list?repage";
- }
这里的getUserFromDB:
- /**
- * 根据ID获取用户——通过DB
- * @param id
- * @return 取不到返回null
- */
- public static User getUserFromDB(String id){
- User user = userDao.get(id);
- user.setRoleList(roleDao.findList(new Role(user)));
- return user;
- }
因此特别需要注意缓存的使用,不是任何地方都适合使用缓存。
- 顶
- 0
- 踩
- jeesite缓存问题
- JeeSite缓存的坑
- jeesite dbname 问题
- jeesite相关问题
- jeesite遇到的问题
- jeesite日期传参问题
- jeesite- shiro权限配置问题
- JeeSite
- JeeSite
- JeeSite
- jeesite
- JeeSite mybatis 升级3.4.0 foreach问题
- 部署好jeesite访问报jstl 问题
- jeesite框架搭建的相关问题
- mysql jeesite 大量数据 count 问题
- Jeesite增加spring-data-redis缓存功能以及相关配置
- jeesite Service里面 new service 出现棘手的问题
- 关于jeesite部署无法找到ContextLoaderListener的问题?
- [Drools]JAVA规则引擎 -- Drools
- useradd、userdel、passwd、groupadd、chgrp、chown、df、du、sort、wget
- QR_ENCODE_3.2 qrencode 二维码生成和识别
- 附加数据库.sql
- UICollectionView详解
- jeesite缓存问题
- springmvc中@InitBinder
- 面试官这样,面试就有戏了!
- 【BZOJ1133】[POI2009]Kon【DP】
- 依赖倒置原则(Dependence Inversion Principle)
- 阿里云 内网 访问外网外网的解决方案
- ListView不会填充完整个界面,想在下方继续添加控件的方法
- Android移动端IM开发之应用层实现TCP长连接多路复用
- [android] 关于ListView的 addHeaderView(...) 方法