SSH(Struts,Spring,Hibernate)和SSM(SpringMVC,Spring,MyBatis)的區別

SSH 一般指的是 Struts2 作前端控制器,Spring 管理各層的組件,Hibernate 負責持久化層。javascript

SSM 則指的是 SpringMVC 作前端控制器,Spring 管理各層的組件,MyBatis 負責持久化層。css

共同之處是都使用了Spring的依賴注入DI來管理各層的組件,使用了面向切面編程AOP來實現日誌管理,權限認證,事務等通用功能的切入。html

不一樣之處是 Struts2 和 SpringMVC 作前端控制器的區別,以及 Hibernate 和 MyBatis 作持久化時的區別。可是,Struts2 也能夠和 MyBatis 搭配使用,SpringMVC 也能夠和 Hibernate 搭配使用。本文爲了簡化對比,指定 Struts2 要和 Hibernate 搭配,SpringMVC 要和 MyBatis 搭配。前端

1.1. SSH 和 SSM 的實現原理區別

所在分層 SSH SSM
頁面層(View) JSP JSP
控制器層(Controller) Struts2 SpringMVC
業務層(Service) Java Java
持久層(DAO) Hibernate MyBatis
數據庫層(DB) MySQL/Oracle MySQL/Oracle
組件管理(Bean) Spring Spring

(1) Struts2 的原理java

這裏寫圖片描述

一個請求在Struts2框架中的處理大概分爲如下幾個步驟:git

一、客戶端初始化一個指向Servlet容器(例如Tomcat)的請求程序員

二、這個請求通過一系列的過濾器(Filter)(這些過濾器中有一個叫作ActionContextCleanUp的可選過濾器,這個過濾器對於Struts2和其餘框架的集成頗有幫助,例如:SiteMesh Plugin)github

三、接着FilterDispatcher被調用,FilterDispatcher詢問ActionMapper來決定這個請求是否須要調用某個Actionweb

FilterDispatcher是控制器的核心,就是mvc中c控制層的核心。下面粗略的分析下FilterDispatcher工做流程和原理:FilterDispatcher進行初始化並啓用核心doFilter。算法

public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { showDeprecatedWarning(); HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) res; ServletContext servletContext = getServletContext(); String timerKey = "FilterDispatcher_doFilter: "; try { // FIXME: this should be refactored better to not duplicate work with the action invocation ValueStack stack = dispatcher.getContainer().getInstance(ValueStackFactory.class).createValueStack(); ActionContext ctx = new ActionContext(stack.getContext()); ActionContext.setContext(ctx); UtilTimerStack.push(timerKey); request = prepareDispatcherAndWrapRequest(request, response); ActionMapping mapping; try { //在這裏找到Action的映射器 mapping = actionMapper.getMapping(request, dispatcher.getConfigurationManager()); } catch (Exception ex) { log.error("error getting ActionMapping", ex); dispatcher.sendError(request, response, servletContext, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, ex); return; } //沒有此Action的話,就去查找靜態資源 if (mapping == null) { // there is no action in this request, should we look for a static resource? String resourcePath = RequestUtils.getServletPath(request); if ("".equals(resourcePath) && null != request.getPathInfo()) { resourcePath = request.getPathInfo(); } if (staticResourceLoader.canHandle(resourcePath)) { staticResourceLoader.findStaticResource(resourcePath, request, response); } else { // this is a normal request, let it pass through chain.doFilter(request, response); } // The framework did its job here return; } //有此Action的話則把控制權交給ActionProxy dispatcher.serviceAction(request, response, servletContext, mapping); } finally { dispatcher.cleanUpRequest(request); try { ActionContextCleanUp.cleanUp(req); } finally { UtilTimerStack.pop(timerKey); } devModeOverride.remove(); } } 

四、若是ActionMapper決定須要調用某個Action,FilterDispatcher把請求的處理交給ActionProxy

public void serviceAction(HttpServletRequest request, HttpServletResponse response, ServletContext context, ActionMapping mapping) throws ServletException { Map<String, Object> extraContext = createContextMap(request, response, mapping, context); // If there was a previous value stack, then create a new copy and pass it in to be used by the new Action ValueStack stack = (ValueStack) request.getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY); boolean nullStack = stack == null; if (nullStack) { ActionContext ctx = ActionContext.getContext(); if (ctx != null) { stack = ctx.getValueStack(); } } if (stack != null) { extraContext.put(ActionContext.VALUE_STACK, valueStackFactory.createValueStack(stack)); } String timerKey = "Handling request from Dispatcher"; try { UtilTimerStack.push(timerKey); String namespace = mapping.getNamespace(); String name = mapping.getName(); String method = mapping.getMethod(); //獲取配置文件 Configuration config = configurationManager.getConfiguration(); //根據配置文件找到此Action並生成ActionProxy ActionProxy proxy = config.getContainer().getInstance(ActionProxyFactory.class).createActionProxy( namespace, name, method, extraContext, true, false); request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, proxy.getInvocation().getStack()); // if the ActionMapping says to go straight to a result, do it! if (mapping.getResult() != null) { Result result = mapping.getResult(); //ActionProxy建立一個ActionInvocation的實例 result.execute(proxy.getInvocation()); } else { proxy.execute(); } // If there was a previous value stack then set it back onto the request if (!nullStack) { request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, stack); } } catch (ConfigurationException e) { logConfigurationException(request, e); sendError(request, response, context, HttpServletResponse.SC_NOT_FOUND, e); } catch (Exception e) { if (handleException || devMode) { sendError(request, response, context, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e); } else { throw new ServletException(e); } } finally { UtilTimerStack.pop(timerKey); } } 

五、ActionProxy經過Configuration Manager詢問框架的配置文件,找到須要調用的Action類

六、ActionProxy建立一個ActionInvocation的實例。

七、ActionInvocation實例使用命名模式來調用,在調用Action的過程先後,涉及到相關攔截器(Intercepter)的調用。

八、一旦Action執行完畢,ActionInvocation負責根據struts.xml中的配置找到對應的返回結果。返回結果一般是(但不老是,也可 能是另外的一個Action鏈)一個須要被表示的JSP或者FreeMarker的模版。

九、將處理結果返回給客戶端

(2) SpringMVC 的原理

這裏寫圖片描述

執行步驟:

第一步:發起請求到前端控制器(DispatcherServlet)

第二步:前端控制器請求HandlerMapping查找 Handler
能夠根據xml配置、註解進行查找

第三步:處理器映射器HandlerMapping向前端控制器返回Handler

第四步:前端控制器調用處理器適配器去執行Handler

第五步:處理器適配器去執行Handler

第六步:Handler執行完成給適配器返回ModelAndView

第七步:處理器適配器向前端控制器返回ModelAndView
ModelAndView是SpringMVC框架的一個底層對象,包括 Model和view

第八步:前端控制器請求視圖解析器去進行視圖解析
根據邏輯視圖名解析成真正的視圖(jsp)

第九步:視圖解析器向前端控制器返回View

第十步:前端控制器進行視圖渲染
視圖渲染將模型數據(在ModelAndView對象中)填充到request域

第十一步:前端控制器向用戶響應結果

(3) Hibernate 的原理

1.經過Configuration().configure();讀取並解析hibernate.cfg.xml配置文件

2.由hibernate.cfg.xml中的<mapping resource="com/xx/User.hbm.xml"/>讀取並解析映射信息

3.經過config.buildSessionFactory();//建立SessionFactory

4.sessionFactory.openSession();//打開Sesssion

5.session.beginTransaction();//建立事務Transation

6.persistent operate持久化操做

7.session.getTransaction().commit();//提交事務

8.關閉Session

9.關閉SesstionFactory

(4) MyBatis原理

這裏寫圖片描述

MyBatis框架執行過程:

一、配置MyBatis的配置文件,SqlMapConfig.xml(名稱不固定)

二、經過配置文件,加載MyBatis運行環境,建立SqlSessionFactory會話工廠
SqlSessionFactory 在實際使用時按單例方式。

三、經過SqlSessionFactory建立SqlSession
SqlSession 是一個面向用戶接口(提供操做數據庫方法),實現對象是線程不安全的,建議sqlSession應用場合在方法體內。

四、調用 sqlSession 的方法去操做數據。
若是須要提交事務,須要執行 SqlSession 的 commit() 方法。

五、釋放資源,關閉SqlSession

1.2. Struts2 和 SpringMVC 在 web.xml 中配置的不一樣

(1) Struts2

<filter> <filter-name>struts2</filter-name> <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class> <init-param> <param-name>filterConfig</param-name> <param-value>classpath:struts2/struts.xml</param-value> </init-param> </filter> <filter-mapping> <filter-name>struts2</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> 

Struts2使用Filter嵌入本身的框架。配置文件加載順序爲:default.properties -> struts-default.xml -> struts-plugins.xml -> struts.xml -> struts.locale。

加載順序能夠參考這篇文章的源碼分析瞭解更多。https://my.oschina.net/gschen/blog/121433

(2) SpringMVC

<!-- springmvc前端控制器,rest配置 --> <servlet> <servlet-name>springmvc_rest</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!-- contextConfigLocation配置springmvc加載的配置文件(配置處理器映射器、適配器等等) 若是不配置contextConfigLocation,默認加載的是/WEB-INF/servlet名稱-serlvet.xml(springmvc-servlet.xml) --> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring/springmvc.xml</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>springmvc_rest</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> 

SpringMVC使用Servlet嵌入本身的框架。

(3)web.xml不一樣之處

SpringMVC的入口是Servlet,而Struts2是Filter(這裏要指出,Filter和Servlet是不一樣的。之前認爲filter是servlet的一種特殊),這就致使了兩者的機制不一樣,這裏就牽涉到Servlet和Filter的區別了。可是這只是接管用戶請求的兩種不一樣方式而已,控制權被Struts2和SpringMVC掌握以後,想作什麼事都是能夠作到的。

Servlet

servlet是一種運行服務器端的java應用程序,具備獨立於平臺和協議的特性,而且能夠動態的生成web頁面,它工做在客戶端請求與服務器響應的中間層。最先支持 Servlet 技術的是 JavaSoft 的 Java Web Server。此後,一些其它的基於 Java 的 Web Server 開始支持標準的 Servlet API。Servlet 的主要功能在於交互式地瀏覽和修改數據,生成動態 Web 內容。這個過程爲:

1) 客戶端發送請求至服務器端;
2) 服務器將請求信息發送至 Servlet; 3) Servlet 生成響應內容並將其傳給服務器。響應內容動態生成,一般取決於客戶端的請求; 4) 服務器將響應返回給客戶端。 在 Web 應用程序中,一個 Servlet 在一個時刻可能被多個用戶同時訪問。這時 Web 容器將爲每一個用戶建立一個線程來執行 Servlet。若是 Servlet 不涉及共享資源的問題,沒必要關心多線程問題。但若是 Servlet 須要共享資源,須要保證 Servlet 是線程安全的。 爲了簡化開發流程,Servlet 3.0 引入了註解(annotation),這使得 web 部署描述符 web.xml 再也不是必須的選擇。 

Filter:Filter是一個能夠複用的代碼片斷,能夠用來轉換HTTP請求、響應和頭信息。Filter不像Servlet,它不能產生一個請求或者響應,它只是修改對某一資源的請求,或者修改從某一的響應。Servlet中的過濾器Filter是實現了javax.servlet.Filter接口的服務器端程序,主要的用途是過濾字符編碼、作一些業務邏輯判斷等。其工做原理是,只要你在web.xml文件配置好要攔截的客戶端請求,它都會幫你攔截到請求,此時你就能夠對請求或響應(Request、Response)統一設置編碼,簡化操做;同時還可進行邏輯判斷,如用戶是否已經登錄、有沒有權限訪問該頁面等等工做。它是隨你的web應用啓動而啓動的,只初始化一次,之後就能夠攔截相關請求,只有當你的web應用中止或從新部署的時候才銷燬。Filter可認爲是Servlet的一種「變種」,它主要用於對用戶請求進行預處理,也能夠對HttpServletResponse進行後處理,是個典型的處理鏈。它與Servlet的區別在於:它不能直接向用戶生成響應。完整的流程是:Filter對用戶請求進行預處理,接着將請求交給Servlet進行處理並生成響應,最後Filter再對服務器響應進行後處理。

Servlet與Filter的區別能夠從這篇文章瞭解更多。http://www.cnblogs.com/doit8791/p/4209442.html

1.3. Struts2 和 SpringMVC 處理用戶請求的不一樣

Struts2和SpringMVC的核心都是接管用戶的請求,解決傳統Servlet開發過於繁瑣,重用性不高的問題。

Struts2和SpringMVC都有註解和配置文件兩種匹配用戶請求URL的方式。

Struts2註解方式匹配URL

參考網址:http://struts.apache.org/docs/convention-plugin.html

首先須要將架包(struts2-convention-plugin-xxx.jar)導入工程中

示例

package com.example.actions; import com.opensymphony.xwork2.ActionSupport; import org.apache.struts2.convention.annotation.Action; import org.apache.struts2.convention.annotation.Actions; import org.apache.struts2.convention.annotation.Result; import org.apache.struts2.convention.annotation.Results; @Results({ @Result(name="failure", location="fail.jsp") }) public class HelloWorld extends ActionSupport { @Action(value="/different/url", results={@Result(name="success", location="http://struts.apache.org", type="redirect")} ) public String execute() { return SUCCESS; } @Action("/another/url") public String doSomething() { return SUCCESS; } } 

Struts2配置方式匹配URL

<package name="package" namespace="/different" extends="struts-default"> <global-results> <result name="failure">/fail.jsp</result> </global-results> <action name="url" class="com.example.actions.HelloWorld" method="execute"> <result name="success" type="redirect">http://struts.apache.org</result> </action> </package> <package name="package2" namespace="/another" extends="struts-default"> <global-results> <result name="failure">/fail.jsp</result> </global-results> <action name="url" class="com.example.actions.HelloWorld" method="doSomething"> </action> </package> 

SpringMVC註解方式匹配URL

package com.jpkc.controller; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.servlet.ModelAndView; @RequestMapping("/admin") @Controller public class LoginController { @RequestMapping("/admin_home") public String admin_home() throws Exception { return "forward:/shop/index.jsp"; } @RequestMapping("/exit") public String logout(ModelAndView model, HttpSession session) throws Exception { session.invalidate(); return "redirect:/manager/login.jsp"; } } 

SpringMVC配置方式匹配URL

public class ItemsController1 implements Controller { @Override public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { //調用Service查找 數據庫,查詢商品列表,這裏使用靜態數據模擬 List<Items> itemsList = new ArrayList<Items>(); //向list中填充靜態數據 Items items_1 = new Items(); items_1.setName("聯想筆記本"); items_1.setPrice(6000f); items_1.setDetail("ThinkPad T430 聯想筆記本電腦!"); Items items_2 = new Items(); items_2.setName("蘋果手機"); items_2.setPrice(5000f); items_2.setDetail("iphone6蘋果手機!"); itemsList.add(items_1); itemsList.add(items_2); //返回ModelAndView ModelAndView modelAndView = new ModelAndView(); //至關 於request的setAttribut,在jsp頁面中經過itemsList取數據 modelAndView.addObject("itemsList", itemsList); //指定視圖 modelAndView.setViewName("/WEB-INF/jsp/items/itemsList.jsp"); return modelAndView; } } 
<!-- 配置Handler --> <bean id="itemsController1" name="/queryItems.action" class="cn.itcast.ssm.controller.ItemsController1" /> 

一、Struts2是類級別的攔截, 一個類對應一個request上下文,SpringMVC是方法級別的攔截,一個方法對應一個request上下文,而方法同時又跟一個url對應,因此說從架構自己上SpringMVC就容易實現restful url,而struts2的架構實現起來要費勁,由於Struts2中Action的一個方法能夠對應一個url,而其類屬性卻被全部方法共享,這也就沒法用註解或其餘方式標識其所屬方法了。

二、由上邊緣由,SpringMVC的方法之間基本上獨立的,獨享request response數據,請求數據經過參數獲取,處理結果經過ModelMap交回給框架,方法之間不共享變量,而Struts2搞的就比較亂,雖然方法之間也是獨立的,但其全部Action變量是共享的,這不會影響程序運行,卻給咱們編碼 讀程序時帶來麻煩,每次來了請求就建立一個Action,一個Action對象對應一個request上下文。

三、因爲Struts2須要針對每一個request進行封裝,把request,session等servlet生命週期的變量封裝成一個一個Map,供給每一個Action使用,並保證線程安全,因此在原則上,是比較耗費內存的。

1.4. Struts2 和 SpringMVC 實現 RESTful 的不一樣

http://localhost/jpkc/item/1609032329404095427579225

實現上面這個連接,其中localhost是域名,jpkc是項目名。

Struts2實現方式

<package name="course_info_package" namespace="/item" extends="struts-default"> <action name="*" class="com.jpkc.action.CourseAction" method="get_course_info"> <result name="success">/story/story_02.jsp</result> </action> </package> 
public class CourseAction extends ActionSupport { public String get_course_info() { String actionName = ServletActionContext.getActionMapping().getName(); CourseInfo courseInfoFromDB = courseInfoDAO.findById(actionName); if (courseInfoFromDB == null) { return "404"; } Course courseFromDB = courseDAO.findById(actionName); if (courseFromDB == null) { return "404"; } setCourseInfo(courseInfoFromDB); setCourse(courseFromDB); return SUCCESS; } } 

SpringMVC實現方式

@Controller
public class CourseController { @RequestMapping("/item/{id}") public ModelAndView get_course_info(ModelAndView model, @PathVariable("id") String id) { if (CM.validIsEmptyWithTrim(id)) { model.addObject("message", "沒有找到此視頻頁面"); model.setViewName("/WEB-INF/jsp/error"); return model; } CourseInfo courseInfoFromDB=null; try { courseInfoFromDB = courseInfoService.selectByPrimaryKey(id); } catch (Exception e1) { System.out.println("沒有找到課程信息"); } if (courseInfoFromDB == null) { model.addObject("message", "沒有找到此視頻頁面"); model.setViewName("/WEB-INF/jsp/error"); return model; } Course courseFromDB = null; try { courseFromDB = courseService.selectByPrimaryKey(id); } catch (Exception e) { System.out.println("沒有查找到課程"); } if (courseFromDB == null) { model.addObject("message", "沒有找到此視頻頁面"); model.setViewName("/WEB-INF/jsp/error"); return model; } model.addObject("courseInfo", courseInfoFromDB); model.addObject("course", courseFromDB); model.setViewName("/story/story_02"); return model; } } 

對於相似於http://localhost/jpkc/item/id1這種連接,Struts2實現RESTful風格須要在代碼中調用ServletActionContext.getActionMapping().getName()獲取ActionName。SpringMVC直接將連接映射到方法參數裏去了。

若是相似於http://localhost/jpkc/id2/id1這種連接,Struts2要進一步分析連接獲得id1和id2。SpringMVC依然能夠將id2映射到方法參數上。從調用的角度來看SpringMVC要方便一些。可是若是將Struts2獲取方式封裝一下,也能夠獲得一樣的效果。

1.5. Struts2 和 SpringMVC 獲取 request 參數的不一樣

前臺頁面有一個表單須要提交。

Struts2 接收 request 參數

<form class="login-form" action="/login_do" method="post"> <h3 class="form-title">登陸系統</h3> <div class="alert alert-danger display-hide"> <button class="close" data-close="alert"></button> <span> 請輸入用戶名和密碼 </span> </div> <div class="form-group"> <label class="control-label visible-ie8 visible-ie9">用戶名</label> <div class="input-icon"> <i class="fa fa-user"></i> <input class="form-control placeholder-no-fix" type="text" autocomplete="off" placeholder="用戶名" name="account.id" /> </div> </div> <div class="form-group"> <label class="control-label visible-ie8 visible-ie9">密碼</label> <div class="input-icon"> <i class="fa fa-lock"></i> <input class="form-control placeholder-no-fix" type="password" autocomplete="off" placeholder="密碼" name="account.password" /> </div> </div> <div class="form-actions"> <button type="submit" class="btn green pull-right"> 登陸 <i class="m-icon-swapright m-icon-white"></i> </button> </div> </form> 
package com.jpkc.pojo; import java.io.Serializable; public class Account implements Serializable { private String id; private String password; private String name; public Account() { super(); // TODO Auto-generated constructor stub } public String getId() { return id; } public void setId(String id) { this.id = id; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getName() { return name; } public void setName(String name) { this.name = name; } } 
package com.jpkc.action; import java.util.HashMap; import java.util.Map; import com.jpkc.common.CM; import com.jpkc.pojo.Account; public class AccountAction extends BaseAction { private Account account; public String login_do() { String method = getRequest().getMethod(); if (method.toUpperCase().equals("GET")) { return "404"; } if (account == null || CM.validIsEmpty(account.getId()) || CM.validIsEmpty(account.getPassword())) { return ERROR; } getSession().setAttribute("accountSession", account); return SUCCESS; } public Account getAccount() { return account; } public void setAccount(Account account) { this.account = account; } } 

SpringMVC 接收 request 參數

<form class="login-form" action="admin/login_do" method="post"> <h3 class="form-title">登陸系統</h3> <div class="alert alert-danger display-hide"> <button class="close" data-close="alert"></button> <span> 請輸入用戶名和密碼 </span> </div> <div class="form-group"> <label class="control-label visible-ie8 visible-ie9">用戶名</label> <div class="input-icon"> <i class="fa fa-user"></i> <input class="form-control placeholder-no-fix" type="text" autocomplete="off" placeholder="用戶名" name="id" /> </div> </div> <div class="form-group"> <label class="control-label visible-ie8 visible-ie9">密碼</label> <div class="input-icon"> <i class="fa fa-lock"></i> <input class="form-control placeholder-no-fix" type="password" autocomplete="off" placeholder="密碼" name="password" /> </div> </div> <div class="form-actions"> <button type="submit" class="btn green pull-right"> 登陸 <i class="m-icon-swapright m-icon-white"></i> </button> </div> </form> 
package com.jpkc.pojo; import java.io.Serializable; public class Account implements Serializable { private String id; private String password; private String name; public Account() { super(); // TODO Auto-generated constructor stub } public String getId() { return id; } public void setId(String id) { this.id = id; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getName() { return name; } public void setName(String name) { this.name = name; } } 
package com.jpkc.controller; import java.util.HashMap; import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import org.codehaus.jackson.map.ObjectMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.servlet.ModelAndView; import com.jpkc.common.CM; import com.jpkc.exception.CustomException; import com.jpkc.mapper.CourseInfoMapper; import com.jpkc.pojo.Account; import com.jpkc.pojo.CourseInfo; import com.jpkc.service.LoginService; @RequestMapping("/admin") @Controller public class LoginController { @Autowired LoginService loginService; @RequestMapping(value = "/login_do", method = { RequestMethod.POST }) public void login_do(ModelAndView model, HttpServletRequest request, HttpServletResponse response, HttpSession session, Account account) throws Exception { response.setCharacterEncoding("utf-8"); response.setContentType("application/json;charset=utf-8"); Map<String, Object> json = new HashMap<String, Object>(); String info; if (account == null || CM.validIsEmpty(account.getId()) || CM.validIsEmpty(account.getPassword())) { info = "用戶名、密碼都是必填項。"; json.put("success", false); json.put("info", info); response.getWriter().write(new ObjectMapper().writeValueAsString(json)); return; } session.setAttribute("accountSession", account); json.put("success", true); response.getWriter().write(new ObjectMapper().writeValueAsString(json)); return; } } 

Struts2單個方法能夠處理一個request,接收參數Account須要定義一個成員變量,Struts2會自動將對應的參數調用成員變量的set方法設置進去。處理方法能夠在方法內獲取到。用完還存在request級別Map中。

SpringMVC的單個方法也對應於一個request,接收參數Account須要定義一個方法參數,SpringMVC會自動將對應的參數設置到方法參數中去。處理方法能夠在方法內獲取到。用完即銷燬。

能夠看出兩種框架均可以實現參數的自動轉換。Struts2定義一個成員變量,其餘方法都是能夠共享的,不用從新定義。SpringMVC每一個方法都是獨立的,方法參數是每個方法獨享的。

各有利弊。

成員變量共享能夠避免重複定義,可是方法一多,用到的成員變量原來越多,整個Action類會慘不忍睹,由於你不知道其中一個方法具體會用到哪幾個成員變量。並且用不到的成員變量也被存儲到request級別Map中了。形成內存的浪費。

方法參數是方法獨享的。則不能複用到其餘方法,可是對於當前方法來講有哪些參數足夠明確,並且不用和其餘方法攪合,乾脆利落。

從JVM角度來講,Struts2成員變量會被分配到堆中。SpringMVC方法參數則會存在於方法棧中,通常認爲棧比堆更輕量一些,方法結束,用完參數即回收。堆須要垃圾回收觸發時才能統一回收。

1.6. Struts2 和 SpringMVC 限制訪問方式GET和POST的不一樣

在上例中,表單提交有密碼,須要指定只接受POST提交方式。

Struts2指定POST方式

public String login_do() { String method = getRequest().getMethod(); if (method.toUpperCase().equals("GET")) { return "404"; } } 

SpringMVC指定POST方式

@RequestMapping(value = "/login_do", method = { RequestMethod.POST }) public void login_do(ModelAndView model, HttpServletRequest request, HttpServletResponse response, HttpSession session, Account account) throws Exception { response.setCharacterEncoding("utf-8"); response.setContentType("application/json;charset=utf-8"); Map<String, Object> json = new HashMap<String, Object>(); String info; if (account == null || CM.validIsEmpty(account.getId()) || CM.validIsEmpty(account.getPassword())) { info = "用戶名、密碼都是必填項。"; json.put("success", false); json.put("info", info); response.getWriter().write(new ObjectMapper().writeValueAsString(json)); return; } session.setAttribute("accountSession", account); json.put("success", true); response.getWriter().write(new ObjectMapper().writeValueAsString(json)); return; } 

Struts2限制只能經過POST方式訪問,是經過調用request的getMethod方法來獲得當前訪問方式。而後手工的去判斷。

SpringMVC也能夠調用request的getMethod方法來判斷,可是框架自己提供了方便的內置判斷。使用註解便可。

Struts2經過攔截器設置好訪問方式的代碼後,也能夠經過註解的方式指定攔截器獲得一樣的效果。自己不是太難的事情,兩個框架均可以實現,Struts2須要手工實現,SpringMVC默認提供了。即便SpringMVC不提供,調用SpringMVC的攔截器也能和Struts2的攔截器的效果同樣。在GET和POST訪問限制方面,並無誰優誰劣,均可以實現。只是SpringMVC願意往前多走一小步。

1.7. Struts2 和 SpringMVC 攔截器的不一樣

後臺頁面須要登陸,咱們可使用攔截器限制未登陸的用戶訪問。

Struts2實現攔截器的方式

public class ManagerLoginInterceptor extends AbstractInterceptor { @Override public String intercept(ActionInvocation invocation) throws Exception { String actionName = ServletActionContext.getActionMapping().getName(); // 若是是登陸、註冊、退出的話就不要攔截了 if (actionName.equals("exit") || actionName.equals("login") || actionName.equals("login_do") || actionName.equals("regist") || actionName.equals("regist_do")) { return invocation.invoke(); } // 若是不是管理員就不能進入 Manager managerTemp = (Manager) ServletActionContext.getRequest().getSession().getAttribute("managerSession"); if (managerTemp == null) { return "manager_login"; } //驗證成功,放行。 return invocation.invoke(); } } 
<package name="admin_package" namespace="/admin" extends="ssh-default"> <interceptors> <interceptor name="LoginManagerValidate" class="com.example.interceptor.ManagerLoginInterceptor"> </interceptor> <!-- 自定義攔截器棧-攔截未登陸的管理員- --> <interceptor-stack name="LoginManagerValidateStack"> <interceptor-ref name="LoginManagerValidate"></interceptor-ref> <interceptor-ref name="defaultStack"></interceptor-ref> </interceptor-stack> </interceptors> <action name="m_*" class="com.example.action.ManagerAction" method="m_{1}"> <interceptor-ref name="LoginManagerValidateStack"></interceptor-ref> <result name="success" type="json"> <param name="root">json</param> </result> </action> </package> 

Struts2還提供了不少默認的攔截器供用戶調用。

<interceptors>  
           <interceptor name="alias"class="com.opensymphony.xwork2.interceptor.AliasInterceptor"/> <interceptor name="autowiring"class="com.opensymphony.xwork2.spring.interceptor.ActionAutowiringInterceptor"/> <interceptor name="chain"class="com.opensymphony.xwork2.interceptor.ChainingInterceptor"/> <interceptor name="conversionError"class="org.apache.struts2.interceptor.StrutsConversionErrorInterceptor"/> <interceptor name="clearSession"class="org.apache.struts2.interceptor.ClearSessionInterceptor"/> <interceptor name="createSession"class="org.apache.struts2.interceptor.CreateSessionInterceptor"/> <interceptor name="debugging"class="org.apache.struts2.interceptor.debugging.DebuggingInterceptor"/> <interceptor name="externalRef"class="com.opensymphony.xwork2.interceptor.ExternalReferencesInterceptor"/> <interceptor name="execAndWait"class="org.apache.struts2.interceptor.ExecuteAndWaitInterceptor"/> <interceptor name="exception"class="com.opensymphony.xwork2.interceptor.ExceptionMappingInterceptor"/> <interceptor name="fileUpload"class="org.apache.struts2.interceptor.FileUploadInterceptor"/> <interceptor name="i18n"class="com.opensymphony.xwork2.interceptor.I18nInterceptor"/> <interceptor name="logger"class="com.opensymphony.xwork2.interceptor.LoggingInterceptor"/> <interceptor name="modelDriven"class="com.opensymphony.xwork2.interceptor.ModelDrivenInterceptor"/> <interceptor name="scopedModelDriven"class="com.opensymphony.xwork2.interceptor.ScopedModelDrivenInterceptor"/> <interceptor name="params"class="com.opensymphony.xwork2.interceptor.ParametersInterceptor"/> <interceptor name="actionMappingParams"class="org.apache.struts2.interceptor.ActionMappingParametersInteceptor"/> <interceptor name="prepare"class="com.opensymphony.xwork2.interceptor.PrepareInterceptor"/> <interceptor name="staticParams"class="com.opensymphony.xwork2.interceptor.StaticParametersInterceptor"/> <interceptor name="scope"class="org.apache.struts2.interceptor.ScopeInterceptor"/> <interceptor name="servletConfig"class="org.apache.struts2.interceptor.ServletConfigInterceptor"/> <interceptor name="sessionAutowiring"class="org.apache.struts2.spring.interceptor.SessionContextAutowiringInterceptor"/> <interceptor name="timer"class="com.opensymphony.xwork2.interceptor.TimerInterceptor"/> <interceptor name="token"class="org.apache.struts2.interceptor.TokenInterceptor"/> <interceptor name="tokenSession"class="org.apache.struts2.interceptor.TokenSessionStoreInterceptor"/> <interceptor name="validation"class="org.apache.struts2.interceptor.validation.AnnotationValidationInterceptor"/> <interceptor name="workflow"class="com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor"/> <interceptor name="store"class="org.apache.struts2.interceptor.MessageStoreInterceptor"/> <interceptor name="checkbox"class="org.apache.struts2.interceptor.CheckboxInterceptor"/> <interceptor name="profiling"class="org.apache.struts2.interceptor.ProfilingActivationInterceptor"/> <interceptor name="roles"class="org.apache.struts2.interceptor.RolesInterceptor"/> <interceptor name="jsonValidation"class="org.apache.struts2.interceptor.validation.JSONValidationInterceptor"/> <interceptornameinterceptorname="annotationWorkflow"class="com.opensymphony.xwork2.interceptor.annotations.AnnotationWorkflowInterceptor"/> 

SpringMVC實現攔截器的方式

public class LoginInterceptor implements HandlerInterceptor { // 進入 Handler方法以前執行 // 用於身份認證、身份受權 // 好比身份認證,若是認證經過表示當前用戶沒有登錄,須要此方法攔截再也不向下執行 @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 獲取請求的url String url = request.getRequestURI(); // 判斷url是不是公開 地址(實際使用時將公開 地址配置配置文件中) // 這裏公開地址是登錄提交的地址 if (url.indexOf("login") >= 0 || url.indexOf("exit") >= 0) { // 若是進行登錄提交,放行 return true; } // 判斷session HttpSession session = request.getSession(); // 從session中取出用戶身份信息 Account account = (Account) session.getAttribute("accountSession"); if (account != null) { // 身份存在,放行 return true; } // 執行這裏表示用戶身份須要認證,跳轉登錄頁面 request.getRequestDispatcher("/manager/login.jsp").forward(request, response); // return false表示攔截,不向下執行 // return true表示放行 return false; } // 進入Handler方法以後,返回modelAndView以前執行 // 應用場景從modelAndView出發:將公用的模型數據(好比菜單導航)在這裏傳到視圖,也能夠在這裏統一指定視圖 @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("HandlerInterceptor1...postHandle"); } // 執行Handler完成執行此方法 // 應用場景:統一異常處理,統一日誌處理 @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("HandlerInterceptor1...afterCompletion"); } } 
<!--攔截器 --> <mvc:interceptors> <!--多個攔截器,順序執行 --> <!-- 登陸認證攔截器 --> <mvc:interceptor> <mvc:mapping path="/admin/**" /> <bean class="com.jpkc.interceptor.LoginInterceptor"></bean> </mvc:interceptor> </mvc:interceptors> 

攔截器實現機制上,Struts2有本身的interceptor機制,SpringMVC用的是獨立的AOP方式。均可以實如今先後進行攔截。

1.8. Struts2 和 SpringMVC 支持 JSON 的不一樣

有時咱們界面的一些操做,是經過 Ajax 調用後臺的服務,獲取服務器返回的 json 數據,進行後續的操做。

Struts2 實現JSON數據返回的方式

<action name="login_do" class="com.jpkc.action.AccountAction" method="login_do"> <result name="success" type="json"> <!-- 這裏指定將被Struts2序列化的屬性,該屬性在action中必須有對應的getter方法 --> <param name="root">json</param> </result> </action> 
public class AccountAction extends BaseAction { // 經常使用變量 private Map<String, Object> json;// 返回到前臺的map對象 private Account account; public AccountAction() { json = new HashMap<String, Object>(); } public String login_do() { if (account == null || CM.validIsEmpty(account.getId()) || CM.validIsEmpty(account.getPassword())) { info = "用戶名、密碼都是必填項。"; json.put("success", false); json.put("info", info); return SUCCESS; } getSession().setAttribute("accountSession", account); json.put("success", true); return SUCCESS; } } 
$.post("login_do", $(".login-form").serialize(), function(json) { if (json.success == true) { window.location.href="shop/index.jsp"; } else { alert("操做失敗:" + json.info); } }, "json"); 

SpringMVC 實現JSON數據返回的方式

<!--註解適配器 --> <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"> <property name="messageConverters"> <list> <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"></bean> </list> </property> </bean> 
$.post("login_do", $(".login-form").serialize(), function(json) { if (json.success == true) { window.location.href="shop/index.jsp"; } else { alert("操做失敗:" + json.info); } }, "json"); 

SpringMVC在控制器中返回json有兩種方式。

一種是使用response返回json。

@RequestMapping(value = "/login_do", method = { RequestMethod.POST }) public void login_do(ModelAndView model, HttpServletRequest request, HttpServletResponse response, HttpSession session, Account account) throws Exception { response.setCharacterEncoding("utf-8"); response.setContentType("application/json;charset=utf-8"); Map<String, Object> json = new HashMap<String, Object>(); String info; if (account == null || CM.validIsEmpty(account.getId()) || CM.validIsEmpty(account.getPassword())) { info = "用戶名、密碼都是必填項。"; json.put("success", false); json.put("info", info); response.getWriter().write(new ObjectMapper().writeValueAsString(json)); return; } session.setAttribute("accountSession", account); json.put("success", true); response.getWriter().write(new ObjectMapper().writeValueAsString(json)); return; } 

另外一種是使用@ResponseBody註解方式。

@RequestMapping(value = "/login_do", method = { RequestMethod.POST }) public @ResponseBody Map<String, Object> login_do(ModelAndView model, HttpServletRequest request, HttpServletResponse response, HttpSession session, Account account) throws Exception { Map<String, Object> json = new HashMap<String, Object>(); String info; if (account == null || CM.validIsEmpty(account.getId()) || CM.validIsEmpty(account.getPassword())) { info = "用戶名、密碼都是必填項。"; json.put("success", false); json.put("info", info); return json; } session.setAttribute("accountSession", account); json.put("success", true); return json; } 

能夠看出,Struts2 和 SpringMVC 均可以實現 Ajax 請求返回 JSON。實現方式上,Struts2在配置文件配置返回類型爲JSON。SpringMVC在方法上加一個@ResponseBody註解便可返回對應類型轉成的JSON字符串。都是對返回數據轉成JSON,可是不得不說SpringMVC的寫法方便太多了。

1.9. Hibernate 和 MyBatis 在 ORM 側重點的不一樣

Hibernate對數據庫結構提供了較爲完整的封裝,Hibernate的O/R Mapping實現了POJO 和數據庫表之間的映射,以及SQL 的自動生成和執行。程序員每每只需定義好了POJO 到數據庫表的映射關係,便可經過Hibernate 提供的方法完成持久層操做。程序員甚至不須要對SQL 的熟練掌握, Hibernate/OJB 會根據指定的存儲邏輯,自動生成對應的SQL 並調用JDBC 接口加以執行。

MyBatis 的着力點,則在於POJO 與SQL之間的映射關係。而後經過映射配置文件,將SQL所需的參數,以及返回的結果字段映射到指定POJO。 相對Hibernate「O/R」而言,MyBatis 是一種「Sql Mapping」的ORM實現。

SQL語句支持:Hibernate能夠徹底不用手寫SQL語句,MyBatis手動維護SQL語句。Hibernate修改優化SQL語句困難,MyBatis因爲SQL語句本身控制,優化很是方便。

開發速度:Hibernate的真正掌握要比Mybatis來得難些。Mybatis框架相對簡單很容易上手,但也相對簡陋些。

開發社區:Hibernate 與Mybatis都是流行的持久層開發框架,但Hibernate開發社區相對多熱鬧些,支持的工具也多,更新也快。而Mybatis相對平靜,工具較少。

開發工做量:Hibernate和MyBatis都有相應的代碼生成工具。能夠生成簡單基本的DAO層方法。

針對高級查詢,Mybatis須要手動編寫SQL語句,以及ResultMap。而Hibernate有良好的映射機制,開發者無需關心SQL的生成與結果映射,能夠更專一於業務流程。

1.10. Hibernate 和 MyBatis 在調優方面的不一樣

  • 制定合理的緩存策略;
  • 儘可能使用延遲加載特性;
  • 採用合理的Session管理機制;

SQL優化方面

Hibernate的查詢會將表中的全部字段查詢出來,這一點會有性能消耗。Hibernate也能夠本身寫SQL來指定須要查詢的字段,但這樣就破壞了Hibernate開發的簡潔性。而Mybatis的SQL是手動編寫的,因此能夠按需求指定查詢的字段。

Hibernate HQL語句的調優須要將SQL打印出來,而Hibernate的SQL被不少人嫌棄由於太醜了。MyBatis的SQL是本身手動寫的因此調整方便。但Hibernate具備本身的日誌統計。Mybatis自己不帶日誌統計,使用Log4j進行日誌記錄。

擴展性方面

Hibernate與具體數據庫的關聯只需在XML文件中配置便可,全部的HQL語句與具體使用的數據庫無關,移植性很好。MyBatis項目中全部的SQL語句都是依賴所用的數據庫的,因此不一樣數據庫類型的支持很差。

1.11. Hibernate 和 MyBatis 在對象管理與抓取策略的不一樣

對象管理

Hibernate 是完整的對象/關係映射解決方案,它提供了對象狀態管理(state management)的功能,使開發者再也不須要理會底層數據庫系統的細節。也就是說,相對於常見的 JDBC/SQL 持久層方案中須要管理 SQL 語句,Hibernate採用了更天然的面向對象的視角來持久化 Java 應用中的數據。

換句話說,使用 Hibernate 的開發者應該老是關注對象的狀態(state),沒必要考慮 SQL 語句的執行。這部分細節已經由 Hibernate 掌管穩當,只有開發者在進行系統性能調優的時候才須要進行了解。

而MyBatis在這一塊沒有文檔說明,用戶須要對對象本身進行詳細的管理。當調用sqlSession.commit()方法時纔會進行真正的提交。

抓取策略

Hibernate對實體關聯對象的抓取有着良好的機制。對於每個關聯關係均可以詳細地設置是否延遲加載,而且提供關聯抓取、查詢抓取、子查詢抓取、批量抓取四種模式。 它是詳細配置和處理的。

而Mybatis的延遲加載是全局配置的,在resultMap中使用association中的select指定延遲加載去執行的statement的id。

<!-- 延遲加載的resultMap --> <resultMap type="cn.itcast.mybatis.po.Orders" id="OrdersUserLazyLoadingResultMap"> <!--對訂單信息進行映射配置 --> <id column="id" property="id"/> <result column="user_id" property="userId"/> <result column="number" property="number"/> <result column="createtime" property="createtime"/> <result column="note" property="note"/> <association property="user" javaType="cn.itcast.mybatis.po.User" select="cn.itcast.mybatis.mapper.UserMapper.findUserById" column="user_id"> <!-- 實現對用戶信息進行延遲加載 --> </association> </resultMap> 

1.12. Hibernate 和 MyBatis 在緩存機制的不一樣

Hibernate緩存
Hibernate一級緩存是Session緩存,利用好一級緩存就須要對Session的生命週期進行管理好。建議在一個Action操做中使用一個Session。一級緩存須要對Session進行嚴格管理。

Hibernate二級緩存是SessionFactory級的緩存。 SessionFactory的緩存分爲內置緩存和外置緩存。內置緩存中存放的是SessionFactory對象的一些集合屬性包含的數據(映射元素據及預約SQL語句等),對於應用程序來講,它是隻讀的。外置緩存中存放的是數據庫數據的副本,其做用和一級緩存相似.二級緩存除了之內存做爲存儲介質外,還能夠選用硬盤等外部存儲設備。二級緩存稱爲進程級緩存或SessionFactory級緩存,它能夠被全部session共享,它的生命週期伴隨着SessionFactory的生命週期存在和消亡。

MyBatis緩存
MyBatis 包含一個很是強大的查詢緩存特性,它能夠很是方便地配置和定製。MyBatis 3 中的緩存實現的不少改進都已經實現了,使得它更增強大並且易於配置。

一級緩存是SqlSession級別的緩存,二級緩存是mapper(命名空間)級別的緩存,默認狀況下是沒有開啓二級緩存的。

要開啓二級緩存,你須要在你的 SQL 映射文件中添加一行: <cache/>

字面上看就是這樣。這個簡單語句的效果以下:

映射語句文件中的全部 select 語句將會被緩存。
映射語句文件中的全部 insert,update 和 delete 語句會刷新緩存。
緩存會使用 Least Recently Used(LRU,最近最少使用的)算法來收回。
根據時間表(好比 no Flush Interval,沒有刷新間隔), 緩存不會以任什麼時候間順序 來刷新。
緩存會存儲列表集合或對象(不管查詢方法返回什麼)的 1024 個引用。
緩存會被視爲是 read/write(可讀/可寫)的緩存,意味着對象檢索不是共享的,而 且能夠安全地被調用者修改,而不干擾其餘調用者或線程所作的潛在修改。
全部的這些屬性均可以經過緩存元素的屬性來修改。

好比: <cache eviction="FIFO" flushInterval="60000" size="512" readOnly="true"/>

這個更高級的配置建立了一個 FIFO 緩存,並每隔 60 秒刷新,存數結果對象或列表的 512 個引用,並且返回的對象被認爲是隻讀的,所以在不一樣線程中的調用者之間修改它們會 致使衝突。可用的收回策略有, 默認的是 LRU:

LRU – 最近最少使用的:移除最長時間不被使用的對象。
FIFO – 先進先出:按對象進入緩存的順序來移除它們。
SOFT – 軟引用:移除基於垃圾回收器狀態和軟引用規則的對象。
WEAK – 弱引用:更積極地移除基於垃圾收集器狀態和弱引用規則的對象。
flushInterval(刷新間隔)能夠被設置爲任意的正整數,並且它們表明一個合理的毫秒 形式的時間段。默認狀況是不設置,也就是沒有刷新間隔,緩存僅僅調用語句時刷新。

size(引用數目)能夠被設置爲任意正整數,要記住你緩存的對象數目和你運行環境的 可用內存資源數目。默認值是1024。

readOnly(只讀)屬性能夠被設置爲 true 或 false。只讀的緩存會給全部調用者返回緩 存對象的相同實例。所以這些對象不能被修改。這提供了很重要的性能優點。可讀寫的緩存 會返回緩存對象的拷貝(經過序列化) 。這會慢一些,可是安全,所以默認是 false。

相同點
Hibernate和Mybatis的二級緩存除了採用系統默認的緩存機制外,均可以經過實現你本身的緩存或爲其餘第三方緩存方案,建立適配器來徹底覆蓋緩存行爲。

不一樣點
Hibernate的二級緩存配置在SessionFactory生成的配置文件中進行詳細配置,而後再在具體的表-對象映射中配置是那種緩存。

MyBatis的二級緩存配置都是在每一個具體的表-對象映射中進行詳細配置,這樣針對不一樣的表能夠自定義不一樣的緩存機制。而且Mybatis能夠在命名空間中共享相同的緩存配置和實例,經過Cache-ref來實現。

二者比較
由於Hibernate對查詢對象有着良好的管理機制,用戶無需關心SQL。因此在使用二級緩存時若是出現髒數據,系統會報出錯誤並提示。

而MyBatis在這一方面,使用二級緩存時須要特別當心。若是不能徹底肯定數據更新操做的波及範圍,避免Cache的盲目使用。不然,髒數據的出現會給系統的正常運行帶來很大的隱患。

1.13. Hibernate 和 MyBatis 對比總結

二者相同點

Hibernate與MyBatis均可以是經過SessionFactoryBuider由XML配置文件生成SessionFactory,而後由SessionFactory 生成Session,最後由Session來開啓執行事務和SQL語句。其中SessionFactoryBuider,SessionFactory,Session的生命週期都是差很少的。

Hibernate和MyBatis都支持JDBC和JTA事務處理。

Mybatis優點

MyBatis能夠進行更爲細緻的SQL優化,能夠減小查詢字段。

MyBatis容易掌握,而Hibernate門檻較高。

Hibernate優點

Hibernate的DAO層開發比MyBatis簡單,Mybatis須要維護SQL和結果映射。

Hibernate對對象的維護和緩存要比MyBatis好,對增刪改查的對象的維護要方便。

Hibernate數據庫移植性很好,MyBatis的數據庫移植性很差,不一樣的數據庫須要寫不一樣SQL。

Hibernate有更好的二級緩存機制,可使用第三方緩存。MyBatis自己提供的緩存機制不佳,更新操做不能指定刷新指定記錄,會清空整個表,可是也可使用第三方緩存。


Hibernate 封裝性好,屏蔽了數據庫差別,自動生成SQL語句,應對數據庫變化能力較弱,SQL語句優化困難。

MyBatis僅實現了SQL語句和對象的映射,須要針對具體的數據庫寫SQL語句,應對數據庫變化能力較強,SQL語句優化較爲方便。

1.14. SSH 和 SSM 對比總結

SSH 和 SSM 的技術框架的不一樣只須要比較Struts2和SpringMVC的不一樣,以及Hibernate和MyBatis的不一樣。

對於不一樣的功能,兩大技術陣營均有對應的解決方案。SSH將配置文件開發用到極致。SSM將註解開發用到極致。

企業進行技術選型,以低成本高回報做爲技術選型的原則,根據項目組的技術力量來進行選擇。

小弟水平有限,只能總結到這裏。更進一步的底層代碼級別的對比,纔是本質的區別。用法上的區別只是表象而已,可是對於廣大開發者來講,誰的開發者用戶體驗好,顯然更能贏得開發者的青睞。

我在GitHub上上傳了同一個項目分別用SSH和SSM開發的例子。僅供參考。https://github.com/ganecheng/SSH_SSM

這裏有一份Java工具和技術的調查,能夠參考一下,http://f.dataguru.cn/article-9978-1.html

1.15. 參考文獻

http://blog.csdn.net/firejuly/article/details/8190229

http://blog.csdn.net/chenyi0834/article/details/7334963

http://blog.csdn.net/gane_cheng/article/details/52787040

http://blog.csdn.net/gane_cheng/article/details/52759099

http://blog.csdn.net/gane_cheng/article/details/52751206

http://blog.csdn.net/chenleixing/article/details/44570681

相關文章
相關標籤/搜索