jeesite緩存問題

?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里獲取,導致,后來獲取的對象的數據都是錯誤的(修改但保存失敗的),這就變相單例化,而且是無法獲得正確數據了。


例如如下的接口

[java]?view plain?copy
  1. @RequiresPermissions("sys:user:edit")??
  2. ????@RequestMapping(value?=?"save")??
  3. ????public?String?save(User?user,?HttpServletRequest?request,?Model?model,?RedirectAttributes?redirectAttributes)?{??
  4. ??
  5. ??????????
  6. ????????//判斷是否有權限修改用戶信息??
  7. ??????????
  8. ????????//先清緩存:因為框架原因,只要更新了該用戶,則會同步更新該用戶緩存,從而無法獲得真正的該用戶信息,所以需要清除掉該緩存,這里先注釋掉,看問題??
  9. ????????//UserUtils.clearCache(user);??
  10. ????????User?oldUser?=?systemService.getUser(user.getId());??
  11. ????????List<String>roleIdListOld?=?oldUser.getRoleIdList();??
  12. ????????User?operator?=?UserUtils.getUser();??
  13. ????????List<String>roleIdListOperator?=?operator.getRoleIdList();??
  14. ????????//自己不能修改自己的權限??
  15. //??????if(user.getId().equals(operator.getId())){??
  16. //??????????addMessage(model,?"修改用戶信息失敗,?不能修改自己的權限");??
  17. //??????????UserUtils.clearCache();??
  18. //??????????return?form(oldUser,?model);??
  19. //??????????}??
  20. ????????if(!roleIdListOperator.containsAll(roleIdListOld)){??
  21. ????????????addMessage(model,?"修改用戶信息失敗,?您的權限不足");??
  22. ????????????UserUtils.clearCache();??
  23. ????????????return?form(oldUser,?model);??
  24. ????????}??
  25. ????????user.setRoleList(roleList);??
  26. ????????//?保存用戶信息??
  27. ????????systemService.saveUser(user);??
  28. ????????//?清除當前用戶緩存??
  29. ????????if?(user.getPhone().equals(UserUtils.getUser().getPhone())){??
  30. ????????????UserUtils.clearCache();??
  31. ????????????//UserUtils.getCacheMap().clear();??
  32. ????????}??
  33. ????????addMessage(redirectAttributes,?"保存用戶'"?+?user.getPhone()?+?"'成功");??
  34. ????????return?"redirect:"?+?adminPath?+?"/sys/user/list?repage";??
  35. ????}??

再看下getUser:

[java]?view plain?copy
  1. public?static?User?getUser(String?id){??
  2. ????User?user?=?(User)CacheUtils.get(USER_CACHE,?USER_CACHE_ID_?+?id);??
  3. ????if?(user?==??null){??
  4. ????????user?=?userDao.get(id);??
  5. ????????if?(user?==?null){??
  6. ????????????return?null;??
  7. ????????}??
  8. ????????user.setRoleList(roleDao.findList(new?Role(user)));??
  9. ????????CacheUtils.put(USER_CACHE,?USER_CACHE_ID_?+?user.getId(),?user);??
  10. ????????CacheUtils.put(USER_CACHE,?USER_CACHE_LOGIN_NAME_?+?user.getPhone(),?user);??
  11. ????}??
  12. ????return?user;??
  13. }??


這里的

[java]?view plain?copy
  1. systemService.getUser(user.getId());??
會一直拿到該對象實例的緩存值,而該值,在修改提交到服務端時,框架已經更新了,再進到controller中。


所以,即使在

[java]?view plain?copy
  1. if(!roleIdListOperator.containsAll(roleIdListOld)){??
  2. ????????????addMessage(model,?"修改用戶信息失敗,?您的權限不足");??
  3. ????????????UserUtils.clearCache();??
  4. ????????????return?form(oldUser,?model);??
  5. ????????}??
這里返回了,其他地方獲取該user的值
[java]?view plain?copy
  1. getUser(user.getId());??
還是會是緩存的值。

也相當于單例的、全局的實例值

解決方法:

在關系到修改等的地方,每次都需要對該實例進行緩存的清空。同時,在修改時,修改對象最好就是拿出db的該記錄,逐個參數進行修改替換:



[java]?view plain?copy
  1. @RequiresPermissions("user:list:edit")??
  2. ????@RequestMapping(value?=?"editUserInfoSave")??
  3. ????public?String?editUserInfoSave(User?user,Model?model,?RedirectAttributes?redirectAttributes)?{??
  4. ??????????
  5. ????????//先清除該user的緩存,防止干擾到其他地方的引用。其實還是會有并發問題,會在清除之前被引用到??
  6. ????????UserUtils.clearCache(user);??
  7. ????????????????//從db中獲取user,注意這個userSave?是修改前的,與user的值不一樣,注意一點:如果直接從getUser(user.getId());中獲取,同時并沒有清緩存的前提下??
  8. ????????????????//UserUtils.clearCache(user);則會導致拿到的user并非DB里的user,而是緩存前端提交的??????????????????
  9. ????????????????User?userSave?=?systemService.getUserFromDB(user.getId());??
  10. ????????/**?
  11. ?????????*?替換更新修改信息?
  12. ?????????*/??
  13. ????????userSave.setName(user.getName());??
  14. ????????userSave.setFirstnameStr(user.getFirstnameStr());??
  15. ????????userSave.setLastnameStr(user.getLastnameStr());??
  16. ????????userSave.setIdStr(user.getIdStr());??
  17. ????????userSave.setUsername(user.getUsername());??
  18. ????????userSave.setBirthdateStr(user.getBirthdateStr());??
  19. ????????userSave.setEmail(user.getEmail());??
  20. ????????userSave.setUserType(user.getUserType());??
  21. ????????userSave.setGenderStr(user.getGenderStr());??
  22. ????????//?保存用戶信息??
  23. ????????systemService.saveUser(userSave);??
  24. ????????addMessage(redirectAttributes,?"保存用戶'"?+?user.getPhone()?+?"'成功");??
  25. ????????return?"redirect:"?+?adminPath?+?"/user/user/list?repage";??
  26. ????}??

這里的getUserFromDB:

[java]?view plain?copy
  1. /**?
  2. ?*?根據ID獲取用戶——通過DB?
  3. ?*?@param?id?
  4. ?*?@return?取不到返回null?
  5. ?*/??
  6. public?static?User?getUserFromDB(String?id){??
  7. ??
  8. ????User?user?=?userDao.get(id);??
  9. ????user.setRoleList(roleDao.findList(new?Role(user)));??
  10. ????return?user;??
  11. }??


因此特別需要注意緩存的使用,不是任何地方都適合使用緩存。

0

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/388023.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/388023.shtml
英文地址,請注明出處:http://en.pswp.cn/news/388023.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

高級Python:定義類時要應用的9種最佳做法

重點 (Top highlight)At its core, Python is an object-oriented programming (OOP) language. Being an OOP language, Python handles data and functionalities by supporting various features centered around objects. For instance, data structures are all objects, …

Java 注解 攔截器

場景描述&#xff1a;現在需要對部分Controller或者Controller里面的服務方法進行權限攔截。如果存在我們自定義的注解&#xff0c;通過自定義注解提取所需的權限值&#xff0c;然后對比session中的權限判斷當前用戶是否具有對該控制器或控制器方法的訪問權限。如果沒有相關權限…

醫療大數據處理流程_我們需要數據來大規模改善醫療流程

醫療大數據處理流程Note: the fictitious examples and diagrams are for illustrative purposes ONLY. They are mainly simplifications of real phenomena. Please consult with your physician if you have any questions.注意&#xff1a;虛擬示例和圖表僅用于說明目的。 …

What's the difference between markForCheck() and detectChanges()

https://stackoverflow.com/questions/41364386/whats-the-difference-between-markforcheck-and-detectchanges轉載于:https://www.cnblogs.com/chen8840/p/10573295.html

ASP.NET Core中使用GraphQL - 第七章 Mutation

ASP.NET Core中使用GraphQL - 目錄 ASP.NET Core中使用GraphQL - 第一章 Hello WorldASP.NET Core中使用GraphQL - 第二章 中間件ASP.NET Core中使用GraphQL - 第三章 依賴注入ASP.NET Core中使用GraphQL - 第四章 GrahpiQLASP.NET Core中使用GraphQL - 第五章 字段, 參數, 變量…

POM.xml紅叉解決方法

方法/步驟 1用Eclipse創建一個maven工程&#xff0c;網上有很多資料&#xff0c;這里不再啰嗦。 2右鍵maven工程&#xff0c;進行更新 3在彈出的對話框中勾選強制更新&#xff0c;如圖所示 4稍等片刻&#xff0c;pom.xml的紅叉消失了。。。

JS前臺頁面驗證文本框非空

效果圖&#xff1a; 代碼&#xff1a; 源代碼&#xff1a; <script type"text/javascript"> function check(){ var xm document.getElementById("xm").value; if(xm null || xm ){ alert("用戶名不能為空"); return false; } return …

python對象引用計數器_在Python中借助計數器對象對項目進行計數

python對象引用計數器前提 (The Premise) When we deal with data containers, such as tuples and lists, in Python we often need to count particular elements. One common way to do this is to use the count() function — you specify the element you want to count …

套接字設置為(非)阻塞模式

當socket 進行TCP 連接的時候&#xff08;也就是調用connect 時&#xff09;&#xff0c;一旦網絡不通&#xff0c;或者是ip 地址無效&#xff0c;就可能使整個線程阻塞。一般為30 秒&#xff08;我測的是20 秒&#xff09;。如果設置為非阻塞模式&#xff0c;能很好的解決這個…

經典問題之「分支預測」

問題 來源 &#xff1a;stackoverflow 為什么下面代碼排序后累加比不排序快&#xff1f; public static void main(String[] args) {// Generate dataint arraySize 32768;int data[] new int[arraySize];Random rnd new Random(0);for (int c 0; c < arraySize; c)data…

vi

vi filename :打開或新建文件&#xff0c;并將光標置于第一行首 vi n filename &#xff1a;打開文件&#xff0c;并將光標置于第n行首 vi filename &#xff1a;打開文件&#xff0c;并將光標置于最后一行首 vi /pattern filename&#xff1a;打開文件&#xff0c;并將光標置…

數字圖像處理 python_5使用Python處理數字的高級操作

數字圖像處理 pythonNumbers are everywhere in our daily life — there are phone numbers, dates of birth, ages, and other various identifiers (driver’s license and social security numbers, for example).電話號碼在我們的日常生活中無處不在-電話號碼&#xff0c;…

05精益敏捷項目管理——超越Scrum

00.我們不是不知道它會給我們帶來麻煩&#xff0c;只是沒想到麻煩會有這么多。——威爾.羅杰斯 01.知識點&#xff1a; a.Scrum是一個強大、特意設計的輕量級框架&#xff0c;器特性就是將軟件開發中在制品的數量限制在團隊層級&#xff0c;使團隊有能力與業務落班一起有效地開…

帶標題的圖片輪詢展示

為什么80%的碼農都做不了架構師&#xff1f;>>> <div> <table width"671" cellpadding"0" cellspacing"0"> <tr height"5"> <td style"back…

linux java 查找進程中的線程

這里對linux下、sun(oracle) JDK的線程資源占用問題的查找步驟做一個小結&#xff1b;linux環境下&#xff0c;當發現java進程占用CPU資源很高&#xff0c;且又要想更進一步查出哪一個java線程占用了CPU資源時&#xff0c;按照以下步驟進行查找&#xff1a;(一)&#xff1a;通過…

定位匹配 模板匹配 地圖_什么是地圖匹配?

定位匹配 模板匹配 地圖By Marie Douriez, James Murphy, Kerrick Staley瑪麗杜里茲(Marie Douriez)&#xff0c;詹姆斯墨菲(James Murphy)&#xff0c;凱里克史塔利(Kerrick Staley) When you request a ride, Lyft tries to match you with the driver most suited for your…

Sprint計劃列表

轉載于:https://www.cnblogs.com/zhs20160715/p/9953586.html

MySQL學習【第十二篇事務中的鎖與隔離級別】

一.事務中的鎖 1.啥是鎖&#xff1f; 顧名思義&#xff0c;鎖就是鎖定的意思 2.鎖的作用是什么&#xff1f; 在事務ACID的過程中&#xff0c;‘鎖’和‘隔離級別’一起來實現‘I’隔離性的作用 3.鎖的種類 共享鎖&#xff1a;保證在多事務工作期間&#xff0c;數據查詢不會被阻…

Android WebKit

這段時間基于項目需要 在開發中與WebView的接觸比較多&#xff0c;前段時間關于HTML5規范塵埃落定的消息出現在各大IT社區頭版上&#xff0c;更有人說&#xff1a;HTML5將顛覆原生App開發 雖然我不太認同這一點 但是關于HTML5JSCSSNative的跨平臺開發模式還是為很多企業節省了開…

jQuery的事件綁定和解綁

1、綁定事件 語法&#xff1a; bind(type,data,fn) 描述&#xff1a;為每一個匹配元素的特定事件&#xff08;像click&#xff09;綁定一個事件處理器函數。 參數解釋&#xff1a; type (String) : 事件類型 data (Object) : (可選) 作為event.data屬性值傳遞給事件對象的額外數…