久久久精品网站,成人伊人网,色吧av色av,亚洲AV永久无码精品秋霞电影影院

聯(lián)想t430s筆記本是哪一年出的,聯(lián)想t430s筆記本配置

大家好,今天小編來為大家解答以下的問題,關(guān)于聯(lián)想t430s筆記本是哪一年出的,聯(lián)想t430s筆記本配置,聯(lián)想t430s筆記本是哪一年出的,聯(lián)想t430s筆記本配置這個很多人還不知道,現(xiàn)在讓我們一起來看看吧!聯(lián)想512GB移動固態(tài)到手價389元辦公必備對于現(xiàn)在辦公室上班族和學(xué)生一族來說,妥善的保存資料是很重要的事。聯(lián)想推出的ZX1系列移動固態(tài)硬盤,以時尚的外觀,快速的存儲速度,非常適合上班族

大家好,今天小編來為大家解答以下的問題,關(guān)于聯(lián)想t430s筆記本是哪一年出的,聯(lián)想t430s筆記本配置,聯(lián)想t430s筆記本是哪一年出的,聯(lián)想t430s筆記本配置這個很多人還不知道,現(xiàn)在讓我們一起來看看吧!

聯(lián)想512GB移動固態(tài)到手價389元 辦公必備

對于現(xiàn)在辦公室上班族和學(xué)生一族來說,妥善的保存資料是很重要的事。聯(lián)想推出的ZX1系列移動固態(tài)硬盤,以時尚的外觀,快速的存儲速度,非常適合上班族和學(xué)生使用。在京東商城聯(lián)想SSD京東自營旗艦店,聯(lián)想ZX1移動固態(tài)硬盤512GB秒殺價僅為389元,值得關(guān)注。

聯(lián)想ZX1移動固態(tài)硬盤采用金屬盤神設(shè)計,外觀修長,便于攜帶。在傳輸協(xié)議上,聯(lián)想ZX1采用了U** 3.1 Gen 2協(xié)議,提供430MB/s讀寫速度和400MB/s寫入速度,輕松完成大容量文件、視頻、文件傳輸。

(7913674)

SSH和S**的區(qū)別,抽絲剝繭由內(nèi)到外給你講清楚

SSH 通常指的是 Struts2 做前端控制器,Spring 管理各層的組件,Hibernate 負(fù)責(zé)持久化層。

S** 則指的是 SpringMVC 做前端控制器,Spring 管理各層的組件,MyBatis 負(fù)責(zé)持久化層。

共同之處是都使用了Spring的依賴注入DI來管理各層的組件,使用了面向切面編程AOP來實現(xiàn)日志管理,權(quán)限認(rèn)證,事務(wù)等通用功能的切入。

不同之處是 Struts2 和 SpringMVC 做前端控制器的區(qū)別,以及 Hibernate 和 MyBatis 做持久化時的區(qū)別。但是,Struts2 也可以和 MyBatis 搭配使用,SpringMVC 也可以和 Hibernate 搭配使用。本文為了簡化對比,指定 Struts2 要和 Hibernate 搭配,SpringMVC 要和 MyBatis 搭配。

1.1. SSH 和 S** 的實現(xiàn)原理區(qū)別

所在分層SSHS**頁面層(View)JSPJSP控制器層(Controller)Struts2SpringMVC業(yè)務(wù)層(Service)JavaJava持久層(DAO)HibernateMyBatis數(shù)據(jù)庫層(DB)MySQL/OracleMySQL/Oracle組件管理(Bean)SpringSpring

(1) Struts2 的原理

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

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

2、這個請求經(jīng)過一系列的過濾器(Filter)(這些過濾器中有一個叫做ActionContextCleanUp的可選過濾器,這個過濾器對于Struts2和其他框架的集成很有幫助,例如:SiteMesh Plugin)

3、接著FilterDispatcher被調(diào)用,F(xiàn)ilterDispatcher詢問ActionMapper來決定這個請求是否需要調(diào)用某個Action

FilterDispatcher是控制器的核心,就是mvc中c控制層的核心。下面粗略的分析下FilterDispatcher工作流程和原理:FilterDispatcher進(jìn)行初始化并啟用核心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的話,就去查找靜態(tài)資源 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的話則把控制權(quán)交給ActionProxy dispatcher.serviceAction(request, response, servletContext, mapping); } finally { dispatcher.cleanUpRequest(request); try { ActionContextCleanUp.cleanUp(req); } finally { UtilTimerStack.pop(timerKey); } devModeOverride.remove(); } }

4、如果ActionMapper決定需要調(diào)用某個Action,F(xiàn)ilterDispatcher把請求的處理交給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(); //根據(jù)配置文件找到此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創(chuàng)建一個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); } }

5、ActionProxy通過Configuration Manager詢問框架的配置文件,找到需要調(diào)用的Action類

6、ActionProxy創(chuàng)建一個ActionInvocation的實例。

7、ActionInvocation實例使用命名模式來調(diào)用,在調(diào)用Action的過程前后,涉及到相關(guān)**(Intercepter)的調(diào)用。

8、一旦Action執(zhí)行完畢,ActionInvocation負(fù)責(zé)根據(jù)struts.xml中的配置找到對應(yīng)的返回結(jié)果。返回結(jié)果通常是(但不總是,也可 能是另外的一個Action鏈)一個需要被表示的JSP或者FreeMarker的模版。

9、將處理結(jié)果返回給客戶端

(2) SpringMVC 的原理

執(zhí)行步驟:

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

第二步:前端控制器請求HandlerMapping查找 Handler
可以根據(jù)xml配置、注解進(jìn)行查找

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

第四步:前端控制器調(diào)用處理器適配器去執(zhí)行Handler

第五步:處理器適配器去執(zhí)行Handler

第六步:Handler執(zhí)行完成給適配器返回ModelAn**iew

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

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

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

第十步:前端控制器進(jìn)行視圖渲染
視圖渲染將模型數(shù)據(jù)(在ModelAn**iew對象中)填充到request域

第十一步:前端控制器向用戶響應(yīng)結(jié)果

(3) Hibernate 的原理

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

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

3.通過config.buildSessionFactory();//創(chuàng)建SessionFactory

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

5.session.beginTransaction();//創(chuàng)建事務(wù)Transation

6.persistent operate持久化**作

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

8.關(guān)閉Session

9.關(guān)閉SesstionFactory

(4) MyBatis原理

MyBatis框架執(zhí)行過程:

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

2、通過配置文件,加載MyBatis運(yùn)行環(huán)境,創(chuàng)建SqlSessionFactory會話工廠
SqlSessionFactory 在實際使用時按單例方式。

3、通過SqlSessionFactory創(chuàng)建SqlSession
SqlSession 是一個面向用戶接口(提供**作數(shù)據(jù)庫方法),實現(xiàn)對象是線程不安全的,建議sqlSession應(yīng)用場合在方法體內(nèi)。

4、調(diào)用 sqlSession 的方法去**作數(shù)據(jù)。
如果需要提交事務(wù),需要執(zhí)行 SqlSession 的 commit() 方法。

5、釋放資源,關(guān)閉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。

加載順序可以參考這篇文章的源碼分析了解更多。

(2) SpringMVC

<!– springmvc前端控制器,rest配置 –> <servlet> <servlet-name>springmvc_rest</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!– contextConfigLocation配置springmvc加載的配置文件(配置處理器映射器、適配器等等) 如果不配置contextConfigLocation,默認(rèn)加載的是/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(這里要指出,F(xiàn)ilter和Servlet是不同的。以前認(rèn)為filter是servlet的一種特殊),這就導(dǎo)致了二者的機(jī)制不同,這里就牽涉到Servlet和Filter的區(qū)別了。但是這只是接管用戶請求的兩種不同方式而已,控制權(quán)被Struts2和SpringMVC掌握之后,想做什么事都是可以做到的。

Servlet

servlet是一種運(yùn)行服務(wù)器端的java應(yīng)用程序,具有**于平臺和協(xié)議的特性,并且可以動態(tài)的生成web頁面,它工作在客戶端請求與服務(wù)器響應(yīng)的中間層。最早支持 Servlet 技術(shù)的是 JavaSoft 的 Java Web Server。此后,一些其它的基于 Java 的 Web Server 開始支持標(biāo)準(zhǔn)的 Servlet API。Servlet 的主要功能在于交互式地瀏覽和修改數(shù)據(jù),生成動態(tài) Web 內(nèi)容。這個過程為:

1) 客戶端發(fā)送請求至服務(wù)器端;2) 服務(wù)器將請求信息發(fā)送至 Servlet;3) Servlet 生成響應(yīng)內(nèi)容并將其傳給服務(wù)器。響應(yīng)內(nèi)容動態(tài)生成,通常取決于客戶端的請求;4) 服務(wù)器將響應(yīng)返回給客戶端。在 Web 應(yīng)用程序中,一個 Servlet 在一個時刻可能被多個用戶同時訪問。這時 Web 容器將為每個用戶創(chuàng)建一個線程來執(zhí)行 Servlet。如果 Servlet 不涉及共享資源的問題,不必關(guān)心多線程問題。但如果 Servlet 需要共享資源,需要保證 Servlet 是線程安全的。為了簡化開發(fā)流程,Servlet 3.0 引入了注解(annotation),這使得 web 部署描述符 web.xml 不再是必須的選擇

Filter:Filter是一個可以復(fù)用的代碼片段,可以用來轉(zhuǎn)換HTTP請求、響應(yīng)和頭信息。Filter不像Servlet,它不能產(chǎn)生一個請求或者響應(yīng),它只是修改對某一資源的請求,或者修改從某一的響應(yīng)。Servlet中的過濾器Filter是實現(xiàn)了javax.servlet.Filter接口的服務(wù)器端程序,主要的用途是過濾字符編碼、做一些業(yè)務(wù)邏輯判斷等。其工作原理是,只要你在web.xml文件配置好要攔截的客戶端請求,它都會幫你攔截到請求,此時你就可以對請求或響應(yīng)(Request、Response)統(tǒng)一設(shè)置編碼,簡化**作;同時還可進(jìn)行邏輯判斷,如用戶是否已經(jīng)登陸、有沒有權(quán)限訪問該頁面等等工作。它是隨你的web應(yīng)用啟動而啟動的,只初始化一次,以后就可以攔截相關(guān)請求,只有當(dāng)你的web應(yīng)用停止或重新部署的時候才銷毀。Filter可認(rèn)為是Servlet的一種“變種”,它主要用于對用戶請求進(jìn)行預(yù)處理,也可以對HttpServletResponse進(jìn)行后處理,是個典型的處理鏈。它與Servlet的區(qū)別在于:它不能直接向用戶生成響應(yīng)。完整的流程是:Filter對用戶請求進(jìn)行預(yù)處理,接著將請求交給Servlet進(jìn)行處理并生成響應(yīng),最后Filter再對服務(wù)器響應(yīng)進(jìn)行后處理。

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

Struts2和SpringMVC的核心都是接管用戶的請求,解決傳統(tǒng)Servlet開發(fā)過于繁瑣,重用性不高的問題。

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

Struts2注解方式匹配URL

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

示例

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=””, 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”></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.ModelAn**iew;@RequestMapping(“/admin”)@Controllerpublic class LoginController{ @RequestMapping(“/admin_home”) public String admin_home() throws Exception { return “forward:/shop/index.jsp”; } @RequestMapping(“/exit”) public String logout(ModelAn**iew model, HttpSession session) throws Exception { session.invalidate(); return “redirect:/manager/login.jsp”; }}

SpringMVC配置方式匹配URL

public class ItemsController1 implements Controller { @Override public ModelAn**iew handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { //調(diào)用Service查找 數(shù)據(jù)庫,查詢商品列表,這里使用靜態(tài)數(shù)據(jù)模擬 List<Items> itemsList = new ArrayList<Items>(); //向list中填充靜態(tài)數(shù)據(jù) Items items_1 = new Items(); items_1.setName(“聯(lián)想筆記本”); items_1.setPrice(6000f); items_1.setDetail(“ThinkPad T430 聯(lián)想筆記本電腦!”); Items items_2 = new Items(); items_2.setName(“蘋果手機(jī)”); items_2.setPrice(5000f); items_2.setDetail(“iphone6蘋果手機(jī)!”); itemsList.add(items_1); itemsList.add(items_2); //返回ModelAn**iew ModelAn**iew modelAn**iew = new ModelAn**iew(); //相當(dāng) 于request的setAttribut,在jsp頁面中通過itemsList取數(shù)據(jù) modelAn**iew.addObject(“itemsList”, itemsList); //指定視圖 modelAn**iew.setViewName(“/WEB-INF/jsp/items/itemsList.jsp”); return modelAn**iew; }}

<!– 配置Handler –><bean id=”itemsController1″ name=”/queryItems.action” class=”cn.itcast.s**.controller.ItemsController1″ />

1、Struts2是類級別的攔截, 一個類對應(yīng)一個request上下文,SpringMVC是方法級別的攔截,一個方法對應(yīng)一個request上下文,而方法同時又跟一個url對應(yīng),所以說從架構(gòu)本身上SpringMVC就容易實現(xiàn)restful url,而struts2的架構(gòu)實現(xiàn)起來要費(fèi)勁,因為Struts2中Action的一個方法可以對應(yīng)一個url,而其類屬性卻被所有方法共享,這也就無法用注解或其他方式標(biāo)識其所屬方法了。

2、由上邊原因,SpringMVC的方法之間基本上**的,獨(dú)享request response數(shù)據(jù),請求數(shù)據(jù)通過參數(shù)獲取,處理結(jié)果通過ModelMap交回給框架,方法之間不共享變量,而Struts2搞的就比較亂,雖然方法之間也是**的,但其所有Action變量是共享的,這不會影響程序運(yùn)行,卻給我們編碼 讀程序時帶來麻煩,每次來了請求就創(chuàng)建一個Action,一個Action對象對應(yīng)一個request上下文。

3、由于Struts2需要針對每個request進(jìn)行封裝,把request,session等servlet生命周期的變量封裝成一個一個Map,供給每個Action使用,并保證線程安全,所以在原則上,是比較耗費(fèi)內(nèi)存的。

1.4. Struts2 和 SpringMVC 實現(xiàn) RESTful 的不同

實現(xiàn)上面這個鏈接,其中l(wèi)ocalhost是域名,jpkc是項目名。

Struts2實現(xiàn)方式

<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實現(xiàn)方式

@Controllerpublic class CourseController{ @RequestMapping(“/item/{id}”) public ModelAn**iew get_course_info(ModelAn**iew 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; }}

對于類似于這種鏈接,Struts2實現(xiàn)RESTful風(fēng)格需要在代碼中調(diào)用ServletActionContext.getActionMapping().getName()獲取ActionName。SpringMVC直接將鏈接映射到方法參數(shù)里去了。

如果類似于這種鏈接,Struts2要進(jìn)一步分析鏈接得到id1和id2。SpringMVC依然可以將id2映射到方法參數(shù)上。從調(diào)用的角度來看SpringMVC要方便一些。但是如果將Struts2獲取方式封裝一下,也可以得到同樣的效果。

1.5. Struts2 和 SpringMVC 獲取 request 參數(shù)的不同

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

Struts2 接收 request 參數(shù)

<form class=”login-form” action=”/login_do” method=”post”> <h3 class=”form-title”>登錄系統(tǒng)</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 參數(shù)

<form class=”login-form” action=”admin/login_do” method=”post”> <h3 class=”form-title”>登錄系統(tǒng)</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.ModelAn**iew;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”)@Controllerpublic class LoginController{ @Autowired LoginService loginService; @RequestMapping(value = “/login_do”, method = { RequestMethod.POST }) public void login_do(ModelAn**iew 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,接收參數(shù)Account需要定義一個成員變量,Struts2會自動將對應(yīng)的參數(shù)調(diào)用成員變量的set方法設(shè)置進(jìn)去。處理方法可以在方法內(nèi)獲取到。用完還存在request級別Map中。

SpringMVC的單個方法也對應(yīng)于一個request,接收參數(shù)Account需要定義一個方法參數(shù),SpringMVC會自動將對應(yīng)的參數(shù)設(shè)置到方法參數(shù)中去。處理方法可以在方法內(nèi)獲取到。用完即銷毀。

可以看出兩種框架都可以實現(xiàn)參數(shù)的自動轉(zhuǎn)換。Struts2定義一個成員變量,其他方法都是可以共享的,不用重新定義。SpringMVC每個方法都是**的,方法參數(shù)是每一個方法獨(dú)享的。

各有利弊。

成員變量共享可以避免重復(fù)定義,但是方法一多,用到的成員變量原來越多,整個Action類會慘不忍睹,因為你不知道其中一個方法具體會用到哪幾個成員變量。而且用不到的成員變量也被存儲到request級別Map中了。造成內(nèi)存的浪費(fèi)。

方法參數(shù)是方法獨(dú)享的。則不能復(fù)用到其他方法,但是對于當(dāng)前方法來說有哪些參數(shù)足夠明確,而且不用和其他方法攪合,干脆利落。

從JVM角度來說,Struts2成員變量會被分配到堆中。SpringMVC方法參數(shù)則會存在于方法棧中,一般認(rèn)為棧比堆更輕量一些,方法結(jié)束,用完參數(shù)即回收。堆需要垃圾回收觸發(fā)時才能統(tǒng)一回收。

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(ModelAn**iew 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方式訪問,是通過調(diào)用request的getMethod方法來得到當(dāng)前訪問方式。然后手工的去判斷。

SpringMVC也可以調(diào)用request的getMethod方法來判斷,但是框架本身提供了方便的內(nèi)置判斷。使用注解即可。

Struts2通過**設(shè)置好訪問方式的代碼后,也可以通過注解的方式指定**得到同樣的效果。本身不是太難的事情,兩個框架都可以實現(xiàn),Struts2需要手工實現(xiàn),SpringMVC默認(rèn)提供了。即使SpringMVC不提供,調(diào)用SpringMVC的**也能和Struts2的**的效果一樣。在GET和POST訪問限制方面,并沒有誰優(yōu)誰劣,都可以實現(xiàn)。只是SpringMVC愿意往前多走一小步。

1.7. Struts2 和 SpringMVC **的不同

后臺頁面需要登錄,我們可以使用**限制未登錄的用戶訪問。

Struts2實現(xiàn)**的方式

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(); } // 如果不是管理員就不能進(jìn)入 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還提供了很多默認(rèn)的**供用戶調(diào)用。

<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實現(xiàn)**的方式

public class LoginInterceptor implements HandlerInterceptor{ // 進(jìn)入 Handler方法之前執(zhí)行 // 用于身份認(rèn)證、身份授權(quán) // 比如身份認(rèn)證,如果認(rèn)證通過表示當(dāng)前用戶沒有登陸,需要此方法攔截不再向下執(zhí)行 @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) { // 如果進(jìn)行登陸提交,放行 return true; } // 判斷session HttpSession session = request.getSession(); // 從session中取出用戶身份信息 Account account = (Account) session.getAttribute(“accountSession”); if (account != null) { // 身份存在,放行 return true; } // 執(zhí)行這里表示用戶身份需要認(rèn)證,跳轉(zhuǎn)登陸頁面 request.getRequestDispatcher(“/manager/login.jsp”).forward(request, response); // return false表示攔截,不向下執(zhí)行 // return true表示放行 return false; } // 進(jìn)入Handler方法之后,返回modelAn**iew之前執(zhí)行 // 應(yīng)用場景從modelAn**iew出發(fā):將公用的模型數(shù)據(jù)(比如菜單導(dǎo)航)在這里傳到視圖,也可以在這里統(tǒng)一指定視圖 @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAn**iew modelAn**iew) throws Exception { System.out.println(“HandlerInterceptor1…postHandle”); } // 執(zhí)行Handler完成執(zhí)行此方法 // 應(yīng)用場景:統(tǒng)一異常處理,統(tǒng)一日志處理 @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println(“HandlerInterceptor1…afterCompletion”); }}

<!–** –> <mvc:interceptors> <!–多個**,順序執(zhí)行 –> <!– 登錄認(rèn)證** –> <mvc:interceptor> <mvc:mapping path=”/admin/**” /> <bean class=”com.jpkc.interceptor.LoginInterceptor”></bean> </mvc:interceptor> </mvc:interceptors>

**實現(xiàn)機(jī)制上,Struts2有自己的interceptor機(jī)制,SpringMVC用的是**的AOP方式。都可以實現(xiàn)在前后進(jìn)行攔截。

1.8. Struts2 和 SpringMVC 支持 JSON 的不同

有時我們界面的一些**作,是通過 Ajax 調(diào)用后臺的服務(wù),獲取服務(wù)器返回的 json 數(shù)據(jù),進(jìn)行后續(xù)的**作。

Struts2 實現(xiàn)JSON數(shù)據(jù)返回的方式

<action name=”login_do” class=”com.jpkc.action.AccountAction” method=”login_do”> <result name=”success” type=”json”> <!– 這里指定將被Struts2序列化的屬性,該屬性在action中必須有對應(yīng)的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(“**作失?。?#8221; + json.info); }}, “json”);

SpringMVC 實現(xiàn)JSON數(shù)據(jù)返回的方式

<!–注解適配器 –> <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(“**作失?。?#8221; + json.info); }}, “json”);

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

一種是使用response返回json。

@RequestMapping(value = “/login_do”, method = { RequestMethod.POST }) public void login_do(ModelAn**iew 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(ModelAn**iew 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 都可以實現(xiàn) Ajax 請求返回 JSON。實現(xiàn)方式上,Struts2在配置文件配置返回類型為JSON。SpringMVC在方法上加一個@ResponseBody注解即可返回對應(yīng)類型轉(zhuǎn)成的JSON字符串。都是對返回數(shù)據(jù)轉(zhuǎn)成JSON,但是不得不說SpringMVC的寫法方便太多了。

1.9. Hibernate 和 MyBatis 在 ORM 側(cè)重點的不同

Hibernate對數(shù)據(jù)庫結(jié)構(gòu)提供了較為完整的封裝,Hibernate的O/R Mapping實現(xiàn)了POJO 和數(shù)據(jù)庫表之間的映射,以及SQL 的自動生成和執(zhí)行。程序員往往只需定義好了POJO 到數(shù)據(jù)庫表的映射關(guān)系,即可通過Hibernate 提供的方法完成持久層**作。程序員甚至不需要對SQL 的熟練掌握, Hibernate/O** 會根據(jù)指定的存儲邏輯,自動生成對應(yīng)的SQL 并調(diào)用JDBC 接口加以執(zhí)行。

MyBatis 的著力點,則在于POJO 與SQL之間的映射關(guān)系。然后通過映射配置文件,將SQL所需的參數(shù),以及返回的結(jié)果字段映射到指定POJO。 相對Hibernate“O/R”而言,MyBatis 是一種“Sql Mapping”的ORM實現(xiàn)。

SQL語句支持:Hibernate可以完全不用手寫SQL語句,MyBatis手動維護(hù)SQL語句。Hibernate修改優(yōu)化SQL語句困難,MyBatis由于SQL語句自己控制,優(yōu)化非常方便。

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

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

開發(fā)工作量:Hibernate和MyBatis都有相應(yīng)的代碼生成工具??梢陨珊唵位镜腄AO層方法。

針對高級查詢,Mybatis需要手動編寫SQL語句,以及ResultMap。而Hibernate有良好的映射機(jī)制,開發(fā)者無需關(guān)心SQL的生成與結(jié)果映射,可以更專注于業(yè)務(wù)流程。

1.10. Hibernate 和 MyBatis 在調(diào)優(yōu)方面的不同制定合理的緩存策略;盡量使用延遲加載特性;采用合理的Session管理機(jī)制;

SQL優(yōu)化方面

Hibernate的查詢會將表中的所有字段查詢出來,這一點會有性能消耗。Hibernate也可以自己寫SQL來指定需要查詢的字段,但這樣就破壞了Hibernate開發(fā)的簡潔性。而Mybatis的SQL是手動編寫的,所以可以按需求指定查詢的字段。

Hibernate HQL語句的調(diào)優(yōu)需要將SQL打印出來,而Hibernate的SQL被很多人嫌棄因為太丑了。MyBatis的SQL是自己手動寫的所以調(diào)整方便。但Hibernate具有自己的日志統(tǒng)計。Mybatis本身不帶日志統(tǒng)計,使用Log4j進(jìn)行日志記錄。

擴(kuò)展性方面

Hibernate與具體數(shù)據(jù)庫的關(guān)聯(lián)只需在XML文件中配置即可,所有的HQL語句與具體使用的數(shù)據(jù)庫無關(guān),移植性很好。MyBatis項目中所有的SQL語句都是依賴所用的數(shù)據(jù)庫的,所以不同數(shù)據(jù)庫類型的支持不好。

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

對象管理

Hibernate 是完整的對象/關(guān)系映射解決方案,它提供了對象狀態(tài)管理(state management)的功能,使開發(fā)者不再需要理會底層數(shù)據(jù)庫系統(tǒng)的細(xì)節(jié)。也就是說,相對于常見的 JDBC/SQL 持久層方案中需要管理 SQL 語句,Hibernate采用了更自然的面向?qū)ο蟮囊暯莵沓志没?Java 應(yīng)用中的數(shù)據(jù)。

換句話說,使用 Hibernate 的開發(fā)者應(yīng)該總是關(guān)注對象的狀態(tài)(state),不必考慮 SQL 語句的執(zhí)行。這部分細(xì)節(jié)已經(jīng)由 Hibernate 掌管妥當(dāng),只有開發(fā)者在進(jìn)行系統(tǒng)性能調(diào)優(yōu)的時候才需要進(jìn)行了解。

而MyBatis在這一塊沒有文檔說明,用戶需要對對象自己進(jìn)行詳細(xì)的管理。當(dāng)調(diào)用sqlSession.commit()方法時才會進(jìn)行真正的提交。

抓取策略

Hibernate對實體關(guān)聯(lián)對象的抓取有著良好的機(jī)制。對于每一個關(guān)聯(lián)關(guān)系都可以詳細(xì)地設(shè)置是否延遲加載,并且提供關(guān)聯(lián)抓取、查詢抓取、子查詢抓取、批量抓取四種模式。 它是詳細(xì)配置和處理的。

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

<!– 延遲加載的resultMap –> <resultMap type=”cn.itcast.mybatis.po.Orders” id=”OrdersUserLazyLoadingResultMap”> <!–對訂單信息進(jìn)行映射配置 –> <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”> <!– 實現(xiàn)對用戶信息進(jìn)行延遲加載 –> </association> </resultMap>1.12. Hibernate 和 MyBatis 在緩存機(jī)制的不同

Hibernate緩存
Hibernate一級緩存是Session緩存,利用好一級緩存就需要對Session的生命周期進(jìn)行管理好。建議在一個Action**作中使用一個Session。一級緩存需要對Session進(jìn)行嚴(yán)格管理。

Hibernate二級緩存是SessionFactory級的緩存。 SessionFactory的緩存分為內(nèi)置緩存和外置緩存。內(nèi)置緩存中存放的是SessionFactory對象的一些**屬性包含的數(shù)據(jù)(映射元素?fù)?jù)及預(yù)定SQL語句等),對于應(yīng)用程序來說,它是只讀的。外置緩存中存放的是數(shù)據(jù)庫數(shù)據(jù)的副本,其作用和一級緩存類似.二級緩存除了以內(nèi)存作為存儲介質(zhì)外,還可以選用硬盤等外部存儲設(shè)備。二級緩存稱為進(jìn)程級緩存或SessionFactory級緩存,它可以被所有session共享,它的生命周期伴隨著SessionFactory的生命周期存在和消亡。

MyBatis緩存
MyBatis 包含一個非常強(qiáng)大的查詢緩存特性,它可以非常方便地配置和定制。MyBatis 3 中的緩存實現(xiàn)的很多改進(jìn)都已經(jīng)實現(xiàn)了,使得它更加強(qiáng)大而且易于配置。

一級緩存是SqlSession級別的緩存,二級緩存是mapper(命名空間)級別的緩存,默認(rèn)情況下是沒有開啟二級緩存的。

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

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

映射語句文件中的所有 select 語句將會被緩存。
映射語句文件中的所有 insert,update 和 delete 語句會刷新緩存。
緩存會使用 Least Recently Used(LRU,最近最少使用的)算法來收回。
根據(jù)時間表(比如 no Flush Interval,沒有刷新間隔), 緩存不會以任何時間順序 來刷新。
緩存會存儲列表**或?qū)ο?無論查詢方法返回什么)的 1024 個引用。
緩存會被視為是 read/write(可讀/可寫)的緩存,意味著對象檢索不是共享的,而 且可以安全地被調(diào)用者修改,而不干擾其他調(diào)用者或線程所做的潛在修改。
所有的這些屬性都可以通過緩存元素的屬性來修改。

比如: <cache eviction=”FIFO” flushInterval=”60000″ size=”512″ readOnly=”true”/>

這個更高級的配置創(chuàng)建了一個 FIFO 緩存,并每隔 60 秒刷新,存數(shù)結(jié)果對象或列表的 512 個引用,而且返回的對象被認(rèn)為是只讀的,因此在不同線程中的調(diào)用者之間修改它們會 導(dǎo)致沖突??捎玫氖栈夭呗杂? 默認(rèn)的是 LRU:

LRU – 最近最少使用的:移除最長時間不被使用的對象。
FIFO – 先進(jìn)先出:按對象進(jìn)入緩存的順序來移除它們。
SOFT – 軟引用:移除基于垃圾回收器狀態(tài)和軟引用規(guī)則的對象。
WEAK – 弱引用:更積極地移除基于垃圾收集器狀態(tài)和弱引用規(guī)則的對象。
flushInterval(刷新間隔)可以被設(shè)置為任意的正整數(shù),而且它們代表一個合理的毫秒 形式的時間段。默認(rèn)情況是不設(shè)置,也就是沒有刷新間隔,緩存僅僅調(diào)用語句時刷新。

size(引用數(shù)目)可以被設(shè)置為任意正整數(shù),要記住你緩存的對象數(shù)目和你運(yùn)行環(huán)境的 可用內(nèi)存資源數(shù)目。默認(rèn)值是1024。

readOnly(只讀)屬性可以被設(shè)置為 true 或 false。只讀的緩存會給所有調(diào)用者返回緩 存對象的相同實例。因此這些對象不能被修改。這提供了很重要的性能優(yōu)勢??勺x寫的緩存 會返回緩存對象的拷貝(通過序列化) 。這會慢一些,但是安全,因此默認(rèn)是 false。

相同點
Hibernate和Mybatis的二級緩存除了采用系統(tǒng)默認(rèn)的緩存機(jī)制外,都可以通過實現(xiàn)你自己的緩存或為其他第三方緩存方案,創(chuàng)建適配器來完全覆蓋緩存行為。

不同點
Hibernate的二級緩存配置在SessionFactory生成的配置文件中進(jìn)行詳細(xì)配置,然后再在具體的表-對象映射中配置是那種緩存。

MyBatis的二級緩存配置都是在每個具體的表-對象映射中進(jìn)行詳細(xì)配置,這樣針對不同的表可以自定義不同的緩存機(jī)制。并且Mybatis可以在命名空間**享相同的緩存配置和實例,通過Cache-ref來實現(xiàn)。

兩者比較
因為Hibernate對查詢對象有著良好的管理機(jī)制,用戶無需關(guān)心SQL。所以在使用二級緩存時如果出現(xiàn)臟數(shù)據(jù),系統(tǒng)會報出錯誤并提示。

而MyBatis在這一方面,使用二級緩存時需要特別小心。如果不能完全確定數(shù)據(jù)更新**作的波及范圍,避免Cache的盲目使用。否則,臟數(shù)據(jù)的出現(xiàn)會給系統(tǒng)的正常運(yùn)行帶來很大的隱患。

1.13. Hibernate 和 MyBatis 對比總結(jié)

兩者相同點

Hibernate與MyBatis都可以是通過SessionFactoryBuider由XML配置文件生成SessionFactory,然后由SessionFactory 生成Session,最后由Session來開啟執(zhí)行事務(wù)和SQL語句。其中SessionFactoryBuider,SessionFactory,Session的生命周期都是差不多的。

Hibernate和MyBatis都支持JDBC和JTA事務(wù)處理。

Mybatis優(yōu)勢

MyBatis可以進(jìn)行更為細(xì)致的SQL優(yōu)化,可以減少查詢字段。

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

Hibernate優(yōu)勢

Hibernate的DAO層開發(fā)比MyBatis簡單,Mybatis需要維護(hù)SQL和結(jié)果映射。

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

Hibernate數(shù)據(jù)庫移植性很好,MyBatis的數(shù)據(jù)庫移植性不好,不同的數(shù)據(jù)庫需要寫不同SQL。

Hibernate有更好的二級緩存機(jī)制,可以使用第三方緩存。MyBatis本身提供的緩存機(jī)制不佳,更新**作不能指定刷新指定記錄,會清空整個表,但是也可以使用第三方緩存。

Hibernate 封裝性好,屏蔽了數(shù)據(jù)庫差異,自動生成SQL語句,應(yīng)對數(shù)據(jù)庫變化能力較弱,SQL語句優(yōu)化困難。

MyBatis僅實現(xiàn)了SQL語句和對象的映射,需要針對具體的數(shù)據(jù)庫寫SQL語句,應(yīng)對數(shù)據(jù)庫變化能力較強(qiáng),SQL語句優(yōu)化較為方便。

1.14. SSH 和 S** 對比總結(jié)

SSH 和 S** 的技術(shù)框架的不同只需要比較Struts2和SpringMVC的不同,以及Hibernate和MyBatis的不同。

對于不同的功能,兩大技術(shù)陣營均有對應(yīng)的解決方案。SSH將配置文件開發(fā)用到極致。S**將注解開發(fā)用到極致。

企業(yè)進(jìn)行技術(shù)選型,以低成本**作為技術(shù)選型的原則,根據(jù)項目組的技術(shù)力量來進(jìn)行選擇。

小弟水平有限,只能總結(jié)到這里。更進(jìn)一步的底層代碼級別的對比,才是本質(zhì)的區(qū)別。用法上的區(qū)別只是表象而已,但是對于廣大開發(fā)者來說,誰的開發(fā)者用戶體驗好,顯然更能贏得開發(fā)者的青睞。

關(guān)于聯(lián)想t430s筆記本是哪一年出的,聯(lián)想t430s筆記本配置到此分享完畢,希望能幫助到您。

原創(chuàng)文章,作者:Admin,如若轉(zhuǎn)載,請注明出處:http://xiesong.cn/196859.html

无码精品国产aa精品| 四虎影院在线免费| 99色吧无码| 中文字幕在线一道本| 懂色一区二区三区免费| 亚州多毛的视频| 东京热天堂网| 欧美一区二区影院| 中文精品久久久久国产网址 | 日本三级东京国产一区| 人妻激情网| 久久久久久禁| 东京热AV男人天堂| 一本加勒比HEZYO中文无码| 女同国产99| 在线 亚洲有限| 在线看片免费不卡人成视频| 美麻豆一区二区| 日本V交y人人火| 色婷婷成人| 亚洲欧美韩国| 日韩日b免费视频| 欧美一区久久久www| 亚洲国产欧美日韩精品一区二区三区| 亚州综合区| 超碰@麻豆| 日韩一级av片| 无码av| 美女性爱在线看| 天堂在线中文| 欧美中文字幕图文小说| 在线亚洲五月| 簧片| 婷婷色国产偷v国产偷v| AV爱爱,com| AV成人精品免费| 久久久久久无码精品人妻一区二区| 久久夜色国产精品电影| 色是色欧美| 亚洲永久ww| 国产在线精品一区二区|