SSM 框架整合相關

1、 Spring IoC/AOP 底層原理前端

一、 IoCjava

引用 Spring 官方原文:This chapter covers the Spring Framework implementation of the Inversion of Control (IoC) [1] principle. IoC is also known as dependency injection (DI). It is a process whereby objects define their dependencies, that is, the other objects they work with, only through constructor arguments, arguments to a factory method, or properties that are set on the object instance after it is constructed or returned from a factory method. The container then injects those dependencies when it creates the bean. This process is fundamentally the inverse, hence the name Inversion of Control (IoC), of the bean itself controlling the instantiation or location of its dependencies by using direct construction of classes, or a mechanism such as the Service Locator pattern.程序員

「控制反轉(IoC)」也稱爲「依賴注入(DI)」,是一個定義對象依賴的過程,對象只和構造參數,工廠方法參數,對象實例屬性或工廠方法返回相關。容器在建立這些 bean 的時候注入這些依賴。這個過程是一個反向的過程,因此命名爲依賴反轉,對象實例的建立由其提供的構造方法或服務定位機制來實現。
IoC 最大的好處就是「解耦」。spring

  • 1.1容器初始化流程

new ClasspathXmlApplicationContext();
ContextLoaderListener / DispatcherServlet -> WebApplicationContext
ApplicationContext 容器的初始化流程主要由AbstractApplicationContext 類中的 refresh 方法實現。大體過程爲:爲 BeanFactory 對象執行後續處理(如:context:propertyPlaceholder等)->在上下文(Context)中註冊 bean->爲 bean 註冊攔截處理器(AOP 相關)->初始化上下文消息(初始化 id 爲 messgeSource 的國際化 bean 對象)->初始化事件多播(處理事件監聽,如ApplicationEvent 等)->初始化主題資源(SpringUI 主題 ThemeSource)->註冊自定義監聽器->實例化全部非 lazy-init 的 singleton 實例->發佈相應事件(Lifecycle 接口相關實現類的生命週期事件發佈)在 spring 中,構建容器的過程都是同步的。同步操做是爲了保證容器構建的過程當中,不出現多線程資源衝突問題。數據庫

eanFactory 的構建。 BeanFactory 是 ApplicationContext 的父接口。是 spring 框架中的頂級容器工廠對象。BeanFactory 只能管理 bean 對象。沒有其餘功能。如:aop 切面管理,propertyplaceholder 的加載等。 構建 BeanFactory 的功能就是管理 bean 對象。express

建立 BeanFactory 中管理的 bean 對象。
postProcessBeanFactory - 加 載 配 置 中 BeanFactory 無 法 處 理 的 內 容 。 如 : propertyplacehodler 的加載。 invokeBeanFactoryPostProcessors - 將上一步加載的內容,做爲一個容器能夠管理的 bean 對象註冊到 ApplicationContext 中。底層實質是在將 postProcessBeanFactory 中加載的內容包裝成一個容器 ApplicationContext 能夠管理的 bean 對象。
registerBeanPostProcessors - 繼續完成上一步的註冊操做。配置文件中配置的 bean 對象都建立並註冊完成。
initMessageSource- i18n,國際化。初始化國際化消息源。
initApplicationEventMulticaster- 註冊事件多播監聽。如 ApplicationEvent 事件。是 spring框架中的觀察者模式實現機制。 onRefresh - 初始化主題資源(ThemeSource)。spring 框架提供的視圖主題信息。
registerListeners - 建立監聽器,並註冊。
finishBeanFactoryInitialization - 初始化配置中出現的全部的 lazy-init=false 的 bean 對象。且 bean 對象必須是 singleton 的。
finishRefresh - 最後一步。 發佈最終事件。生命週期監聽事件。 spring 容器定義了生命週期接口。能夠實現容器啓動調用初始化,容器銷燬以前調用回收資源。Lifecycle 接口。編程

  • 1.2 多容器/父子容器概念

Spring 框架容許在一個應用中建立多個上下文容器。可是建議容器之間有父子關係。能夠經過 ConfigurableApplicationContext 接口中定義的 setParent 方法設置父容器。一旦設置父子關係,則能夠經過子容器獲取父容器中除 PropertyPlaceHolder 之外的全部資源,父容器不能獲取子容器中的任意資源(相似 Java 中的類型繼承)。
        典型的父子容器: spring 和 springmvc 同時使用的時候。ContextLoaderListener 建立的容器是父容器,DispatcherServlet 建立的容器是子容器。
        保證一個 JVM 中,只有一個樹狀結構的容器樹。能夠經過子容器訪問父容器資源。緩存

  • 1.3 p 域/c 域

Spring2.0 以後引入了 p(property 標籤)域、Spring3.1 以後引入了 c(constractor-arg 標籤)域。能夠簡化配置文件中對 property 和constructor-arg 的配置。安全

<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:c="http://www.springframework.org/schema/c" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="oneBean" class="com.sxt.OneBean" p:a="10" p:o-ref="otherBean" c:a="20" c:o-ref="otherBean"/>
<bean id="otherBean" class="com.sxt.OtherBean" />
</beans>
class OneBean{
int a;
Object o;
public OneBean(int a, Object o){ this.a = a; this.o = o;}
// getters and setters for fields. }
  • 1.4 lookup-meth

lookup-method 一旦應用,Spring 框架會自動使用 CGLIB 技術爲指定類型建立一個動態子類型,並自動實現抽象方法。能夠動態的實現依賴注入的數據準備。
        在效率上,比直接自定義子類型慢。相對來講更加通用。能夠只提供 lookup-method 方法的返回值對象便可實現動態的對象返回。
        在工廠方法難以定製的時候使用。
        也是模板的一種應用。工廠方法的擴展。
        如:工廠方法返回對象類型爲接口類型。且不一樣版本應用返回的對象未必相同時使用。能夠避免屢次開發工廠類。服務器

package com.sxt.lookupmethod;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestLookupMethod {
public static void main(String[] args) {
ApplicationContext context =
new
ClassPathXmlApplicationContext("classpath:lookupmethod/applicationContext.xml");
CommandManager manager = context.getBean("manager", CommandManager.class);
System.out.println(manager.getClass().getName());
manager.process();
}
}
abstract class CommandManager{
public void process() {
MyCommand command = createCommand();
// do something ... System.out.println(command);
}
protected abstract MyCommand createCommand();
}
class MyCommand{
public MyCommand(){
System.out.println("MyCommand instanced");
}
}
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:c="http://www.springframework.org/schema/c" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="manager" class="com.sxt.lookupmethod.CommandManager">
<lookup-method bean="command" name="createCommand"/>
</bean>
<bean id="command" class="com.sxt.lookupmethod.MyCommand"></bean>
</beans>

二、 AOP

面向切面編程,其底層原理就是動態代理實現。若是切面策略目標有接口實現,使用JDK 的動態代理技術;無接口實現則使用 CGLIB 技術生成動態代理。

在商業環境中,接口使用度是很是高的,在這主要分析 Spring 如何使用 JDK 的動態代理 技 術 生 成 動 態 代 理 對 象 。 主 要 代 碼 在JdkDynamicAopProxy 、 AdvisedSupport 、DefaultAdvisorChainFactory、ReflectiveMethodInvocation 類中。

  • 2.1JdkDynamicAopProxy.invoke();
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
 {
 MethodInvocation invocation;
 Object oldProxy = null;
 boolean setProxyContext = false;
 // 獲取代理對象中的目標源對象。 至關於 Service 實現類。
 TargetSource targetSource = this.advised.targetSource;
 Object target = null;
 try {
 // 判斷邏輯目的是避免代理對象執行出現 RuntimeException
 if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
 // The target does not implement the equals(Object) method itself. return equals(args[0]);
 }
 else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
 // The target does not implement the hashCode() method itself. return hashCode();
 }
 else if (method.getDeclaringClass() == DecoratingProxy.class) {
 // There is only getDecoratedClass() declared -> dispatch to proxy config. return AopProxyUtils.ultimateTargetClass(this.advised);
 }
 else if (!this.advised.opaque && method.getDeclaringClass().isInterface()
 &&
 method.getDeclaringClass().isAssignableFrom(Advised.class)) {
 // Service invocations on ProxyConfig with the proxy config... return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
 }
 Object retVal; // return value, 定義返回結果數據的引用。
 if (this.advised.exposeProxy) {
 // Make invocation available if necessary. oldProxy = AopContext.setCurrentProxy(proxy);
 setProxyContext = true;
 }
 // Get as late as possible to minimize the time we "own" the target, // in case it comes from a pool. 目標對象獲取。目標對象的類對象
 target = targetSource.getTarget();
 Class<?> targetClass = (target != null ? target.getClass() : null);
 // Get the interception chain for this method. 獲取代理須要在目標方法執行
 先後,切入的攔截器鏈。 關注方法
 List<Object> chain =
 this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
 // Check whether we have any advice. If we don't, we can fallback on direct
 // reflective invocation of the target, and avoid creating a MethodInvocation. if (chain.isEmpty()) {
 // We can skip creating a MethodInvocation: just invoke the target
 directly
 // Note that the final invoker must be an InvokerInterceptor so we know it
 does
 // nothing but a reflective operation on the target, and no hot swapping or
 fancy proxying. // 若是代理對象沒有須要切人的攔截器,執行目標對象中的方法。
 Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
 retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
 }
 else {
 // We need to create a method invocation... // 建立一個執行器,加入攔截信息,並按照順序執行攔截代碼和目
 標對象中的方法。
 invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
 // Proceed to the joinpoint through the interceptor chain. // 方法執行。按照順序執行攔截代碼和目標對象中的方法。關注方
 法
 retVal = invocation.proceed();
 }
 // Massage return value if necessary. 獲取目標對象中方法的返回結果類
 型。
 Class<?> returnType = method.getReturnType();
 if (retVal != null && retVal == target &&
 returnType != Object.class && returnType.isInstance(proxy) &&
 !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
 // Special case: it returned "this" and the return type of the method
 // is type-compatible. Note that we can't help if the target sets
 // a reference to itself in another returned object. retVal = proxy;
 }
 else if (retVal == null && returnType != Void.TYPE &&
 returnType.isPrimitive()) {
 throw new AopInvocationException( "Null return value from advice does not match primitive return
 type for: " + method);
 }
 return retVal;
 }
 finally {
 if (target != null && !targetSource.isStatic()) {
 // Must have come from TargetSource. targetSource.releaseTarget(target);
 }
 if (setProxyContext) {
 // Restore old proxy. AopContext.setCurrentProxy(oldProxy);
 }
 }
 }
  • 2.2AdvisedSupport.

getInterceptorsAndDynamicInterceptionAdvice

public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) {
// 方法匹配信息, 獲取 spring 容器中的緩存。
MethodCacheKey cacheKey = new MethodCacheKey(method);
// 從已知的緩存中獲取方法緩存匹配信息。
List<Object> cached = this.methodCache.get(cacheKey);
if (cached == null) {
// 查詢代理對象須要執行的攔截信息。關注方法。
cached =
this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
this, method, targetClass);
// 保存緩存數據,爲後續其餘代碼提供緩存內容。
this.methodCache.put(cacheKey, cached);
}
return cached;
}
  • 2.3DefaultAdvisorChainFactory.

getInterceptorsAndDynamicInterceptionAdv

public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
Advised config, Method method, @Nullable Class<?> targetClass) {
// This is somewhat tricky... We have to process sintroduction first, // but we need to preserve order in the ultimate list. List<Object> interceptorList = new ArrayList<>(config.getAdvisors().length);
Class<?> actualClass = (targetClass != null ? targetClass :
method.getDeclaringClass());
boolean hasIntroductions = hasMatchingIntroductions(config, actualClass);
// 通知註冊器。spring 容器會將配置好的全部通知使用註冊器管理。
AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
// 從配置信息中獲取通知對象。
for (Advisor advisor : config.getAdvisors()) {
if (advisor instanceof PointcutAdvisor) {
// Add it conditionally. PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
if (config.isPreFiltered() ||
pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
MethodMatcher mm =
pointcutAdvisor.getPointcut().getMethodMatcher();
if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) {
if (mm.isRuntime()) {
// Creating a new object instance in the getInterceptors()
method
// isn't a problem as we normally cache created chains. for (MethodInterceptor interceptor : interceptors) {
interceptorList.add(new
InterceptorAndDynamicMethodMatcher(interceptor, mm));
}
}
else {
interceptorList.addAll(Arrays.asList(interceptors));
}
}
}
}
else if (advisor instanceof IntroductionAdvisor) {
IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
else {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
return interceptorList;
}
  • 2.4ReflectiveMethodInvocation. proceed
public Object proceed() throws Throwable {
// 開始執行代理方法。包含通知方法和目標對象中的真實方法。
// 判斷當前代理是否還有須要執行通知。若是沒有通知,執行目標代碼。
if (this.currentInterceptorIndex ==
this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
if (interceptorOrInterceptionAdvice instanceof
InterceptorAndDynamicMethodMatcher) {
// Evaluate dynamic method matcher here: static part will already have
// been evaluated and found to match. InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher)
interceptorOrInterceptionAdvice;
if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
}
else {
// Dynamic matching failed. // Skip this interceptor and invoke the next in the chain. return proceed();
}
}
else {
// It's an interceptor, so we just invoke it: The pointcut will have
// been evaluated statically before this object was constructed. return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
  • 2.5AOP 源碼流程圖

三、 AOP 中經常使用的 Pointcut-expressi

AOP 開發中,有很是重要的幾個概念,其中有一個概念叫「切點」。表明通知切入到代碼執行流程的那個位置點。
切點通常經過表達式定義。spring 框架會經過 SpringEL 來解析表達式。表達式有多種定義方式。分別對應不一樣的解析結果。 。

  • 3.1execution 表達式
  • 3.2target 表達式
  • 3.3this 表達式
  • 3.4within 表達式
  • 3.5args 表達式

2、 SpringMVC 組件實現原理

1 執行邏輯圖

2 組件

  • 2.1DispatcherServlet

    -->DispatcherServlet 是整個流程控制的中心,由它調用其它組件處理用戶的請求, DispatcherServlet 的存在下降了組件之間的耦合性。 MVC 模式: 傳統定義,一個 WEB 應用中,只有惟一的一個控制器和客戶端交互. 全部的 客戶端請求和服務器單點接觸. 這個控制器稱爲核心控制器(前端控制器)。 傳統定義中,核 心控制器的實現使用 Servlet 實現。如:SpringMVC,Struts1。

    -->MVC 優點: 單點接觸,能夠有效的解耦。能夠實現功能的重用。

    M - model

    V - view

    C - controller

  • 2.2HandlerMapping

    -->處理映射器。

    -->HandlerMapping 負責 根據用戶 請求找 到 Handler 即處 理器(如 :用戶自 定義 的 Controller),springmvc 提供了不一樣的映射器實現不一樣的映射方式,例如:配置文件方式, 實現接口方式,註解方式等。

    -->映射器至關於配置信息或註解描述。 映射器內部封裝了一個相似 map 的數據結構。使 用 URL 做爲 key,HandlerExecutionChain 做爲 value。核心控制器,能夠經過請求對象(請 求對象中包含請求的 URL)在 handlerMapping 中查詢 HandlerExecutionChain 對象。

    -->是 SpringMVC 核心組件之一。是必不可少的組件。不管是否配置,SpringMVC 會有默 認提供。

    -->如 果 有 mvc:annotation-driven/ 標 籤 配 置 , 默 認 的 映 射 器 : RequestMappingHandlerMapping

    -->若是沒有mvc:annotation-driven/標籤配置,且使用註解開發 SpringMVC 代碼,默認的 映射器是:RequestMappingHandlerMapping。(老版本中有其餘的映射器,可是已通過時。)

  • 2.3HandlerAdapter

    -->經過 HandlerAdapter 對處理器(Handler)進行執行,這是適配器模式的應用,經過擴 展適配器能夠對更多類型的處理器進行執行。

    -->典型的適配器: SimpleControllerHandlerAdapter。最基礎的。處理自定義控制器 (Handler)和 SpringMVC 控制器頂級接口 Controller 之間關聯的。

    -->如 果 定 義 了 mvc:annotation-driven/ 標 籤 配 置 , 使 用

    -->適 配 器 對 象 爲 : HttpRequestHandlerAdapter。 適配器也是 SpringMVC 中的核心組件之一。必須存在。SpringMVC 框架有默認值。

  • 2.4Handl

    -->處理器。

    -->Handler 是 繼 DispatcherServlet 前 端 控 制 器 的 後 端 控制 器 ( 自 定 義 控 制 器 ), 在 DispatcherServlet 的控制下 Handler 對具體的用戶請求進行處理。因爲 Handler 涉及到具體的 用戶業務請求,因此通常狀況須要程序員根據業務需求開發 Handler。

    -->在 SpringMVC 中對 Handler 沒有強制的類型要求。在 SpringMVC 框架中,對 Handler 的引用定義類型爲 Object。

    -->處理器理論上說不是必要的核心組件。

    -->SpringMVC 框架是一個線程不安全的,輕量級的框架。一個 handler 對象,處理全部 的請求。開發過程當中,注意線程安全問題。

  • 2.5ViewResolver

    -->ViewResolver 負責將處理結果生成 View 視圖,ViewResolver 首先根據邏輯視圖名解析 成物理視圖名即具體的頁面地址,再生成 View 視圖對象,最後對 View 進行渲染將處理結 果經過頁面展現給用戶。 -->是 SpringMVC 中 必 要 的 組 件 之 一 。 SpringMVC 提 供 默 認 視 圖 解 析 器 。 InternalResourceViewResolver。內部資源視圖解析器。

    -->視圖解析器是用於處理動態視圖邏輯的。靜態視圖邏輯,不經過 SpringMVC 流程。直 接經過 WEB 中間件(Tomcat)就能夠訪問靜態資源。

3 源碼解讀

3、 MyBatis 自動化生成&關聯查詢

1 mybatis-generator-gui

  1. 1代碼自動生成插件。缺陷:沒有多表操做.自動生成是針對互聯網開發提出的.互聯網開發 中多表操做不多.

  2. 2相似 MyEclipse 中的一個逆向工程組件.根據數據庫表格設計,自動生成實體類型,Mapper/DAO 接口,有必要生成對應的實現類,相關的Mapper/DAO 的配置文件。

  3. 3MyBatis-generator : 是一個開發完善的 JavaSE 工程。主要實現方式,就是使用 JDBC/MyBatis 鏈接數據庫,查詢表格信息,自動化生成對應的 java 代碼。

版本:

gui 版本:提供可視化界面,操做簡單。弊端是一次只能生成一張表格的對應代碼。

console 版本:無可視化界面,操做相對麻煩。優點是能夠一次性生成若干表格的對應 代碼。企業使用。

使用方式:

gui 版本:運行 com.zzg.mybatis.generator.MainUI。

2 mybatis-generator-console

插件工具。 是用於自動生成代碼的。 能夠生成的代碼包括:實體類型,Mapper 接口, Mapper 接口對應的 SQL 映射文件。

  • 2.1代碼生成方式

    關注配置文件:*generatorConfig.xml

    配置文件中配置了須要逆向生成代碼的表格有哪些。還配置了數據庫的連接相關信息。

  • 2.2生成後的 Mapper 使用方式

  • 2.3自動生成代碼的優缺點

    **2.3.1. 優勢**
      A.方便。
      B.SQL 規範。
      C.快捷。
      D.維護成本低
      **2.3.2缺點**
      A.只能單表操做。(互聯網應用中,多表聯合查詢相對較少。)
      B.若是表格中有 Text,BLOB 字段。查詢、更新的時候,須要特殊注意。默認的查詢方法不查詢 Text 和 BLOB 字段,默
        認的更新方法不更新 Text 和 BLOB 字段。必須調用selectByExampleWithBLOBs,updateByExamaleWithBLOBs
        ,updateByPrimaryKeyWithBLOBs

3 Interceptor

  • 是 MyBatis 提供的一個插件(plugin 擴展)。表明攔截器。能夠攔截代碼中的數據庫訪 問操做。就是 Statement 操做。

  • 攔截後,能夠去修改正在執行的 SQL 語句,能夠額外訪問數據庫,能夠實現若干數據 計算和處理。

  • 使用場景很少。針對某類型的 SQL 實現攔截的工具。粒度太粗糙。

  • 市場經常使用的 Interceptor 插件只有 PageHelper。 Interceptor 影響執行效率。

4 關聯查詢

在 MyBatis 中,關聯查詢分爲一次查詢和 N+1 次查詢。

一次查詢:是使用多表聯合查詢 SQL 語法實現。

一次查詢 SQL 語法相對複雜,效率比較高。若是查詢的數據量大,不推薦使用。

N+1 次查詢:是使用多個單表查詢 SQL 語法實現。

N+1 次查詢效率低,屢次訪問數據庫,網絡操做爲屢次。可使用 lazy 實現懶加載。在 MyBatis 中懶加載並非很是好用。

在一對一關係查詢的時候,可使用 AutoMapping 的方式實現查詢。具體語法爲:

select column as `關聯屬性名.關聯對象內部屬性名` from ....

AutoMapping 不推薦使用,語義不明確,維護成本高。

  • 4.1一對一
<resultMap type=」具體類型」 id=」惟一命名」>
<id column=」字段名」 property=」屬性名」/>
<result column=」字段名」 property=」屬性名」/>
<!-- 一次訪問數據庫 -->
<association property=」屬性名」 javaType=」屬性的類型」>
<id column=」字段名」 property=」屬性名」/>
<result column=」字段名」 property=」屬性名」/>
</association>
<!-- n+1 次訪問數據庫 -->
<association property=」屬性名」 javaType=」屬性的類型」
select=」命名空間.標籤 ID 就是要調用的 SQL 語法」
column=」傳遞的參數, {參數名=當前行的字段名}」/>
</resultMap>
  • 4.2一對多&多
<resultMap type=」具體類型」 id=」惟一命名」>
<id column=」字段名」 property=」屬性名」/>
<result column=」字段名」 property=」屬性名」/>
<!-- 一次訪問數據庫 -->
<collection property=」屬性名」 javaType=」屬性的類型」 ofType=」集合中的泛型」>
<id column=」字段名」 property=」屬性名」/>
<result column=」字段名」 property=」屬性名」/>
</ collection >
<!-- n+1 次訪問數據庫 -->
< collection property=」屬性名」 javaType=」屬性的類型」 ofType=」集合中的泛型」
select=」命名空間.標籤 ID 就是要調用的 SQL 語法」
column=」傳遞的參數, {參數名=當前行的字段名}」/>
</resultMap>
  • 4.3深層嵌套 不推薦應用
<resultMap type=」具體類型」 id=」惟一命名」>
<id column=」字段名」 property=」屬性名」/>
<result column=」字段名」 property=」屬性名」/>
<!-- 一次訪問數據庫 -->
<collection property=」屬性名」 javaType=」屬性的類型」 ofType=」集合中的泛型」>
<id column=」字段名」 property=」屬性名」/>
<result column=」字段名」 property=」屬性名」/>
<association property=」」 type=」」>
<id column=」」 property=」」/>
<collection />
</association>
</ collection >
<!-- n+1 次訪問數據庫 -->
< collection property=」屬性名」 javaType=」屬性的類型」
ofType=」集合中的泛型」
select=」命名空間.標籤 ID 就是要調用的 SQL 語法」
column=」傳遞的參數, {參數名=當前行的字段名}」/>
</resultMap>

5 Provider

@InsertProvider @UpdateProvider @DeleteProvider @SelectProvider

6 lazy在 mybatis

核心配置文件中增長下述配置

<!-- 配置環境參數 -->
<settings>
<!-- 開啓延遲加載 -->
<setting name="lazyLoadingEnabled" value="true"/>
<!-- 關閉侵入性延遲加載
侵入性延遲加載表明,若是訪問了主數據對象,關聯數據自動加載。
-->
<setting name="aggressiveLazyLoading" value="false"/>
</settings>

4、 Maven+SSM

O(∩_∩)O哈哈~待續....

相關文章
相關標籤/搜索