mybatis註解詳解

http://www.mybatis.org/mybatis-3/zh/sqlmap-xml.htmlcss

 

mybatis的原身是ibatis,如今已經脫離了apache基金會,新官網是http://www.mybatis.org/。

html

mybatis3中增長了使用註解來配置Mapper的新特性,本篇文章主要介紹其中幾個@Provider的使用方式,他們是:@SelectProvider、@UpdateProvider、@InsertProvider和@DeleteProvider。

MyBatis 3 User Guide中的最後一章描述了註解的簡單用法,可是對於這幾個Provider的具體使用方式並無說的很清楚,特別是參數傳遞的方式,徹底沒有說起,對於初次使用的同窗來講,會形成不小的困擾。

通過一些嘗試後,我總結了一些Provider的使用經驗,下面以@SelectProvider爲例,依次描述幾種典型的使用場景。

1.使用@SelectProvider
@SelectProvider是聲明在方法基本上的,這個方法定義在Mapper對應的的interface上。
1 public interface UserMapper {
2     @SelectProvider(type = SqlProvider.class, method = "selectUser")
3     @ResultMap("userMap")
4     public User getUser(long userId);
5 }
上例中是個很簡單的Mapper接口,其中定義了一個方法:getUser,這個方法根據提供的用戶id來查詢用戶信息,並返回一個User實體bean。
這是一個很簡單很經常使用的查詢場景:根據key來查詢記錄並將結果封裝成實體bean。其中:
@SelectProvider註解用於生成查詢用的sql語句,有別於@Select註解,@SelectProvide指定一個Class及其方法,而且經過調用Class上的這個方法來得到sql語句。在咱們這個例子中,獲取查詢sql的方法是SqlProvider.selectUser。
@ResultMap註解用於從查詢結果集RecordSet中取數據而後拼裝實體bean。
 



2.定義拼裝sql的類java

@SelectProvide中type參數指定的Class類,必需要可以經過無參的構造函數來初始化。
@SelectProvide中method參數指定的方法,必須是public的,返回值必須爲String,能夠爲static。
1 public class SqlProvider {
2     public String selectUser(long userId) {
3         return "select * from user where userId=" + userId;
4     }
5 }



3.無參數@SelectProvide方法
在Mapper接口方法上和@SelectProvide指定類方法上,均無參數:
UserMapper.java:spring

1     @SelectProvider(type = SqlProvider.class, method = "selectAllUser")
2     @ResultMap("userMap")
3     public List<User> getAllUser();
SqlProvider.java:
1     public String selectAllUser() {
2         return "select * from user";
3     }



4.一個參數的@SelectProvide方法
對於只有一個參數的狀況,能夠直接使用,參見前面的getUser和selectUser。
可是,若是在getUser方法中,對userId方法使用了@Param註解的話,那麼相應selectUser方法必須接受Map<String, Object>作爲參數:
UserMapper.java:sql

1     @SelectProvider(type = SqlProvider.class, method = "selectUser2")
2     @ResultMap("userMap")
3     public User getUser2(@Param("userId") long userId);

SqlProvider.java:數據庫

1     public String selectUser2(Map<String, Object> para) {
2         return "select * from user where userId=" + para.get("userId");
3     }



5.更多參數的@SelectProvide方法
在超過一個參數的狀況下,@SelectProvide方法必須接受Map<String, Object>作爲參數,
若是參數使用了@Param註解,那麼參數在Map中以@Param的值爲key,以下例中的userId;
若是參數沒有使用@Param註解,那麼參數在Map中以參數的順序爲key,以下例中的password:apache

UserMapper.java:
1     @SelectProvider(type = SqlProvider.class, method = "selectUserCheck")
2     @ResultMap("userMap")
3     public User getUserCheck(@Param("userId") long userId, String password);
SqlProvider.java:
1     public String selectUserCheck(Map<String, Object> para) {
2         return "select * from user where userId=" + para.get("userId") + " and password='" + para.get("1") + "'";
3     }

6.一些限制
在Mapper接口和@SelectProvide方法類中,不要使用重載,也就是說,不要使用方法名相同參數不一樣的方法,以免發生詭異問題。

http://www.blogjava.net/dbstar/archive/2011/08/08/355825.html編程

最近在總結過去一年所作的項目,因爲開發週期或者對需求的把握不是太到位,每一個項目隨着所作的項目進度,從需求分析到code階段總或多或少有一些本身感受不是太完美或沒有盡善盡美的地方,使用開源框架和第三方接口只知道接口調用,對於其內部實現機理老是存在疑惑(這傢伙是怎麼作的,我怎麼沒有想到),雖然各個項目完成後一瘸一拐的仍是能知足當初的開發需求。可是對於追求完美、刨根問底性選手,心中總有根刺,感受不爽(不知道你們有沒有這種感受)。下面經過本身的理解使用java原生的註解方式實現 spring aop的運行機理 (還沒看過spring /mybatis的源代碼,過年的時候研究一下大俠們有好的想法能夠共享一下,話說獨樂樂不如衆樂樂哦)數組

先說說spring AOP使用上的一些限制:緩存

1.若是切點函數有重載時,定義的通知類中方法不能實現方法重載

2.spring AOP只支持方法層面的切口定義,固然這個也是spring的基本原則如spring mvc 與struts2的區別之一就是spring mvc是基於方法的設計struts2是基於類的設計;

3.spring aop 不支持參數級的切口定義,若有時候須要對傳入切口的參數進行安全性,規範性、合法性處理的時候是不支持的。固然對參數處理涉及到解析參數類型獲取、參數類型判斷,對於使用反射機制獲取這個是有必定難度滴。

下面經過詳細的代碼,來說解如何經過使用java的annotation自定義切點接口和經過反射機制實現spring AOP機制。

第一步:自定義AOP中須要的註解接口

class層註解定義:

用途:類接口切點註解定義

package com.dbc.yangg.project;

import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * * @ClassName: MyClassAnnotation * @Description: 類層註解定義 * @author guoyang2011@gmail.com * @date 2014年1月18日 下午11:37:51 * */ @Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface MyClassAnnotation {  String value() default "firstAnno"; }


method層advice定義相似於Spring AOP中@Before,@After,@Around,@AfterThrowing,@AfterReturning等

用途:方法切點接口註解定義

package com.dbc.yangg.project;

import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * * @ClassName: MySecondMethodAnnotation * @Description: 方法層註解定義 * @author guoyang2011@gmail.com * @date 2014年1月18日 下午11:44:44 * */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface MyPointcutAnnotation {  /**  *  * @Title: className  * @Description: TODO  * @param @return advicer class type  * @return Class<?>  * @throws  */  Class<?> className();  /**  *  * @Title: method  * @Description: TODO  * @param @return advicer method name  * @return String  * @throws  */  String method();// }


method parameters 層advicer定義相似mybatis中@Param註解

功能:參數層面切點接口註解定義

package com.dbc.yangg.project;

import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * * @ClassName: MyParameterAnnotation * @Description: 方法中參數層註解定義 * @author guoyang2011@gmail.com * @date 2014年1月18日 下午11:45:15 * */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.PARAMETER) public @interface MyParameterAnnotation {  /**  *  * @Title: opType  * @Description: method 參數類型檢查  * @param @return  * @return MyAopParameterOPType[]  * @throws  */  MyAopParameterOPType[] opType();  /**  *  * @Title: paraType  * @Description: method 參數類型  * @param @return  * @return Class<?>  * @throws  */  Class<?> paraType(); }


處理MyAopParameterOPType類型定義

功能:定義參數切口定義註解處理的類型

package com.dbc.yangg.project;  
 /** * * @ClassName: MyAopParameterOPType * @Description: TODO * @author guoyang2011@gmail.com * @date 2014年1月18日 下午12:07:25 * */ public enum MyAopParameterOPType {  checkForDB("DB"),//特殊字符處理 ,通用轉碼或者其餘處理  checkForSecurity("security"),//參數是否合法等操做  checkDeleteAuthority("DeleteAuthority"),  checkUpdateAuthority("UpdateAuthority");  private String value;  private MyAopParameterOPType(String value){   this.value=value;  }  public String getValue(){   return this.value;  } }

 

第二步:自定義AOP管理模塊

主要功能:自定義AOP處理類,負責解析實際調用切點函數定義的通知

 
package com.dbc.yangg.project;

import java.lang.annotation.Annotation; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import org.apache.ibatis.annotations.SelectProvider; /** * * @ClassName: MyAOPUtils * @Description: * @author guoyang2011@gmail.com * @date 2014年1月18日 下午12:01:05 * */ public class MyAOPUtils {  /**  *  * @Title: myAopUtilsManager  * @Description: 切點函數參數觸發通知事件,全部通知事件的處理接口  * @param @param advicerManagerClass  * @param @param indexArg  * @param @param paraValues  * @param @param paraTypes  * @param @return  * @return boolean  * @throws  */  private static boolean parameterAdvicerUtils(Annotation advicerManagerClass,int indexArg,Object[] paraValues, Class<?>... paraTypes){   if(advicerManagerClass instanceof MyPointcutAnnotation){    //接口參數驗證經過後執行    //切點通知處理    MyPointcutAnnotation AdvicerClass=(MyPointcutAnnotation)advicerManagerClass;    Class<?> adviceClass=AdvicerClass.className();    try {     Method adviceMethod=adviceClass.getMethod(AdvicerClass.method(),paraTypes);     adviceMethod.invoke(adviceClass.newInstance(), paraValues);    } catch (NoSuchMethodException e) {     // TODO Auto-generated catch block     e.printStackTrace();    } catch (SecurityException e) {     // TODO Auto-generated catch block     e.printStackTrace();    } catch (IllegalAccessException e) {     // TODO Auto-generated catch block     e.printStackTrace();    } catch (IllegalArgumentException e) {     // TODO Auto-generated catch block     e.printStackTrace();    } catch (InvocationTargetException e) {     // TODO Auto-generated catch block     e.printStackTrace();    } catch (InstantiationException e) {     // TODO Auto-generated catch block     e.printStackTrace();    }      }else if(advicerManagerClass instanceof MyParameterAnnotation){    //對輸入的參數作一些通用處理和安全性檢查等等    //通常用在DAO層sql拼裝特殊字符檢查,數據格式合法性檢查,轉碼或對調用者使用定義切點接口使用權限,安全性,等信息進行檢查和確認等場合;當切點參數經過通知類中定義的接口處理後再調用切點方法;如MyBatis中經過註解@SelectProvider方式生成合法的SQL語句須要對拼裝的sql語句傳入的參數進行驗證等,還有就是從安全新考慮對傳入的模塊調用者身份進行檢查,MyBatis經過註解方式定義接口實現動態SQL生成中關鍵就是對數據類型的解析    if(indexArg<0){     return true;    }    MyParameterAnnotation AdvicerClass=(MyParameterAnnotation)advicerManagerClass;    //處理切點方法參數的通知,大概思路以下:    //1.解析參數類型    //2.獲取參數值    //3.調用通知處理接口檢查參數合法性    //4.返回檢查結果 true:false   }   return true;  }  /**  *  * @Title: myAopUtilsManager  * @Description: Pointcut method execute advice interface  * @param @param advicerManagerClass 類型  * @param @param paraValues pointcut傳入參數  * @param @param paraTypes pointcut傳入參數類型  * @return void  * @throws  */  private static boolean methodAdvicerUtils(Annotation advicerManagerClass,Object[] paraValues, Class<?>... paraTypes){   return parameterAdvicerUtils(advicerManagerClass,-1,paraValues,paraTypes);  }  /**  *  * @Title: excuteMethodAdvicers  * @Description: TODO  * @param @param pointJoinMethod  * @param @param paraValues  * @return void  * @throws  */  private static boolean excuteMethodAdvicers(Method pointJoinMethod,Object[] paraValues){   boolean result=true;   Annotation[] methodAnns=pointJoinMethod.getAnnotations();   for(Annotation methodAnn:methodAnns){    result=methodAdvicerUtils(methodAnn, paraValues,pointJoinMethod.getParameterTypes());    if(!result){     break;    }   }   return result;  }  /**  *  * @Title: excuteParameterAdvicers  * @Description: TODO  * @param @param pointJoinMethod  * @param @param paraValues  * @param @return  * @return boolean  * @throws  */  private static boolean excuteParameterAdvicers(Method pointJoinMethod,Object[] paraValues){   boolean result=true;     Annotation[][] parameterAnns=pointJoinMethod.getParameterAnnotations();   if(parameterAnns==null||parameterAnns.length==0){    return result;   }   for(int index=0;index<parameterAnns.length;index++){    if(!result){     break;    }    Annotation[] argAnns=parameterAnns[index];    for(Annotation argAnn:argAnns){     result=parameterAdvicerUtils(argAnn,index, paraValues,pointJoinMethod.getParameterTypes());     if(!result){      break;     }    }   }   return result;  }  /**  *  * @Title: excuteAdvicer  * @Description: TODO  * @param @param pointJoinMethod 切點函數  * @param @param paraValues 切點函數 實參  * @param @param methodResultObj 切點函數 返回類型  * @param @return  * @return boolean  * @throws  */  /**  *  * @Title: excuteAdvicer  * @Description: TODO  * @param @param pointJoinMethod 切點函數  * @param @param paraValues 切點函數  * @return void  * @throws  */  public static boolean excuteAdvicer(Method pointJoinMethod,Object[] paraValues,Object methodResultObj){   boolean result=false;   if(excuteParameterAdvicers(pointJoinMethod,paraValues))//切點函數定義的須要驗證的通知驗證經過後執行   {    result=excuteMethodAdvicers(pointJoinMethod, paraValues);   }   return result;  } }
 

第三步:定義業務測試類

主要功能:實際開發中的業務核心類

 
package com.dbc.yangg.project;
/** * * @ClassName: TestAnnotation * @Description: 測試模塊中核心邏輯處理類,使用AOP實現日誌管理、安全管理、事務管理 * @author guoyang2011@gmail.com * @date 2014年1月18日 下午11:41:55 * */ @MyClassAnnotation("TestAnnotation") public class TestAnnotation extends AbstractTestAnnotation{  @MyMethodAnnotation(methodName = "print")  public void print() {   // TODO Auto-generated method stub   System.out.println("pointcut method1 running,method name:print");  }  /**  *  * 定義切點  * 通知類{@link MyTestAdvice}  * 通知方式函數名:doSomeIdleThing  * @param parameter  * @see com.dbc.yangg.project.AbstractTestAnnotation#setParameter(java.lang.String[])  */  @MyPointcutAnnotation(className = MyTestAdvice.class, method = "doSomeIdleThing")  public void setParameter(    @MyParameterAnnotation(      opType = { MyAopParameterOPType.checkForDB,MyAopParameterOPType.checkForSecurity },      paraType = String[].class)    String[] parameter) {   // TODO Auto-generated method stub   System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");   System.out.println("business method running...");   System.out.println("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<");  } }

第四步:定義業務AOP處理類

功能:當執行核心業務中切點時執行的通知

package com.dbc.yangg.project;
/** * * @ClassName: MyTestAdvice * @Description: spring AOP{@link TestAnnotation}}切點處理類 (同spring AOP 切面類@Aspect) * @author guoyang2011@gmail.com * @date 2014年1月18日 下午11:38:09 * */ public class MyTestAdvice {  /**  *  * @Title: doSomeIdleThing  * @Description: {@link TestAnnotation}中setParameter切點執行時觸發此通知@Before,@After,@Around,@AfterThrowing,@AfterReturning<br>  * @param @param parameter  * @return void  * @throws  */  public void doSomeIdleThing(String[] parameter){   System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");   System.out.println("proxy method start running...");   for(String str:parameter){    System.out.println("advice writer!print point args value:"+str);   }   System.out.println("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<");  } }

第五步:測試

package com.dbc.yangg.project;  

import java.lang.annotation.Annotation; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class Init {  public static void main(String[] args){   try {    String[] arg={"hadoop","hbase","pig","hive","mahout","hdfs","mapreduce","yarn"};    Object[] objs=new Object[1];    objs[0]=arg;    Class busClass=Class.forName(TestAnnotation.class.getName());    Method busMethod=busClass.getMethod("setParameter", String[].class);    busMethod.invoke(busClass.newInstance(), objs);    MyAOPUtils.excuteAdvicer(busMethod,objs);   } catch (ClassNotFoundException e) {    // TODO Auto-generated catch block    e.printStackTrace();   } catch (NoSuchMethodException e) {    // TODO Auto-generated catch block    e.printStackTrace();   } catch (SecurityException e) {    // TODO Auto-generated catch block    e.printStackTrace();   } catch (IllegalAccessException e) {    // TODO Auto-generated catch block    e.printStackTrace();   } catch (IllegalArgumentException e) {    // TODO Auto-generated catch block    e.printStackTrace();   } catch (InvocationTargetException e) {    // TODO Auto-generated catch block    e.printStackTrace();   } catch (InstantiationException e) {    // TODO Auto-generated catch block    e.printStackTrace();   }  } }
測試結果:
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
business method running... <<<<<<<<<<<<<<<<<<<<<<<<<<<<<< >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> proxy method start running... advice writer:hadoop advice writer:hbase advice writer:pig advice writer:hive advice writer:mahout advice writer:hdfs advice writer:mapreduce advice writer:yarn <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

http://www.tuicool.com/articles/yAvmIb

 

 

 

 

首先固然得下載mybatis-3.0.5.jar和mybatis-spring-1.0.1.jar兩個JAR包,並放在WEB-INF的lib目錄下(若是你使用maven,則jar會根據你的pom配置的依賴自動下載,並存放在你指定的maven本地庫中,默認是~/.m2/repository),前一個是mybatis核心包,後一個是和spring整合的包。

使用mybatis,必須有個全局配置文件configuration.xml,來配置mybatis的緩存,延遲加載等等一系列屬性,該配置文件示例以下:

Java代碼
  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE configuration
  3. PUBLIC "-//ibatis.apache.org//DTD Config 3.0//EN"
  4. "http://ibatis.apache.org/dtd/ibatis-3-config.dtd">
  5. <configuration>
  6. <settings>
  7. <!-- 全局映射器啓用緩存 -->
  8. <setting name="cacheEnabled" value="true" />
  9. <!-- 查詢時,關閉關聯對象即時加載以提升性能 -->
  10. <setting name="lazyLoadingEnabled" value="true" />
  11. <!-- 設置關聯對象加載的形態,此處爲按需加載字段(加載字段由SQL指 定),不會加載關聯表的全部字段,以提升性能 -->
  12. <setting name="aggressiveLazyLoading" value="false" />
  13. <!-- 對於未知的SQL查詢,容許返回不一樣的結果集以達到通用的效果 -->
  14. <setting name="multipleResultSetsEnabled" value="true" />
  15. <!-- 容許使用列標籤代替列名 -->
  16. <setting name="useColumnLabel" value="true" />
  17. <!-- 容許使用自定義的主鍵值(好比由程序生成的UUID 32位編碼做爲鍵值),數據表的PK生成策略將被覆蓋 -->
  18. <setting name="useGeneratedKeys" value="true" />
  19. <!-- 給予被嵌套的resultMap以字段-屬性的映射支持 -->
  20. <setting name="autoMappingBehavior" value="FULL" />
  21. <!-- 對於批量更新操做緩存SQL以提升性能 -->
  22. <setting name="defaultExecutorType" value="BATCH" />
  23. <!-- 數據庫超過25000秒仍未響應則超時 -->
  24. <setting name="defaultStatementTimeout" value="25000" />
  25. </settings>
  26. <!-- 全局別名設置,在映射文件中只需寫別名,而沒必要寫出整個類路徑 -->
  27. <typeAliases>
  28. <typeAlias alias="TestBean"
  29. type="com.wotao.taotao.persist.test.dataobject.TestBean" />
  30. </typeAliases>
  31. <!-- 非註解的sql映射文件配置,若是使用mybatis註解,該mapper無需配置,可是若是mybatis註解中包含@resultMap註解,則mapper必須配置,給resultMap註解使用 -->
  32. <mappers>
  33. <mapper resource="persist/test/orm/test.xml" />
  34. </mappers>
  35. </configuration>


該文件放在資源文件的任意classpath目錄下,假設這裏就直接放在資源根目錄,等會spring須要引用該文件。

查看ibatis-3-config.dtd發現除了settings和typeAliases還有其餘衆多元素,好比properties,objectFactory,environments等等,這些元素基本上都包含着一些環境配置,數據源定義,數據庫事務等等,在單獨使用mybatis的時候很是重要,好比經過以構造參數的形式去實例化一個sqlsessionFactory,就像這樣:

 
Java代碼
  1. SqlSessionFactory factory = sqlSessionFactoryBuilder.build(reader);
  2. SqlSessionFactory factory = sqlSessionFactoryBuilder.build(reader, properties);
  3. SqlSessionFactory factory = sqlSessionFactoryBuilder.build(reader, environment, properties);


而typeHandlers則用來自定義映射規則,如你能夠自定義將Character映射爲varchar,plugins元素則放了一些攔截器接口,你能夠繼承他們並作一些切面的事情,至於每一個元素的細節和使用,你參考mybatis用戶指南便可。

如今咱們用的是spring,所以除settings和typeAliases元素以外,其餘元素將會失效,故不在此配置,spring會覆蓋這些元素的配置,好比在spring配置文件中指定c3p0數據源定義以下:

Java代碼
  1. <!-- c3p0 connection pool configuration -->
  2. <bean id="testDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
  3. destroy-method="close">
  4. <!-- 數據庫驅動 -->
  5. <property name="driverClass" value="${db.driver.class}" />
  6. <!-- 鏈接URL串 -->
  7. <property name="jdbcUrl" value="${db.url}" />
  8. <!-- 鏈接用戶名 -->
  9. <property name="user" value="${db.username}" />
  10. <!-- 鏈接密碼 -->
  11. <property name="password" value="${db.password}" />
  12. <!-- 初始化鏈接池時鏈接數量爲5個 -->
  13. <property name="initialPoolSize" value="5" />
  14. <!-- 容許最小鏈接數量爲5個 -->
  15. <property name="minPoolSize" value="5" />
  16. <!-- 容許最大鏈接數量爲20個 -->
  17. <property name="maxPoolSize" value="20" />
  18. <!-- 容許鏈接池最大生成100個PreparedStatement對象 -->
  19. <property name="maxStatements" value="100" />
  20. <!-- 鏈接有效時間,鏈接超過3600秒未使用,則該鏈接丟棄 -->
  21. <property name="maxIdleTime" value="3600" />
  22. <!-- 鏈接用完時,一次產生的新鏈接步進值爲2 -->
  23. <property name="acquireIncrement" value="2" />
  24. <!-- 獲取鏈接失敗後再嘗試10次,再失敗則返回DAOException異常 -->
  25. <property name="acquireRetryAttempts" value="10" />
  26. <!-- 獲取下一次鏈接時最短間隔600毫秒,有助於提升性能 -->
  27. <property name="acquireRetryDelay" value="600" />
  28. <!-- 檢查鏈接的有效性,此處小弟不是很懂什麼意思 -->
  29. <property name="testConnectionOnCheckin" value="true" />
  30. <!-- 每一個1200秒檢查鏈接對象狀態 -->
  31. <property name="idleConnectionTestPeriod" value="1200" />
  32. <!-- 獲取新鏈接的超時時間爲10000毫秒 -->
  33. <property name="checkoutTimeout" value="10000" />
  34. </bean>


配置中的${}都是佔位符,在你指定數據庫驅動打war時會自動替換,替換的值在你的父pom中配置,至於c3p0鏈接池的各類屬性詳細信息和用法,你自行參考c3p0的官方文檔,這裏要說明的是checkoutTimeout元素,記得千萬要設大一點,單位是毫秒,假如設置過小,有可能會致使沒等數據庫響應就直接超時了,小弟在這裏吃了很多苦頭,仍是基本功太差。

數據源配置穩當以後,咱們就要開始很是重要的sessionFactory配置了,不管是hibernate仍是mybatis,都須要一個sessionFactory來生成session,sessionFactory配置以下:

Java代碼
  1. <bean id="testSqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
  2. <property name="configLocation" value="classpath:configuration.xml" />
  3. <property name="dataSource" ref="testDataSource" />
  4. </bean>


testSqlSessionFactory有兩處注入,一個就是前面提到的mybatis全局設置文件configuration.xml,另外一個就是上面定義的數據源了(注:hibernate的sessionFactory只需注入hibernate.cfg.xml,數據源定義已經包含在該文件中),好了,sessionFactory已經產生了,因爲咱們用的mybatis3的註解,所以spring的sqlSessionTemplate也不用配置了,sqlSessionTemplate也不用注入到咱們的BaseDAO中了,相應的,咱們須要配置一個映射器接口來對應sqlSessionTemplate,該映射器接口定義了你本身的接口方法,具體實現不用關心,代碼以下:

Java代碼
  1. <!-- data OR mapping interface -->
  2. <bean id="testMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
  3. <property name="sqlSessionFactory" ref="testSqlSessionFactory" />
  4. <property name="mapperInterface" value="com.wotao.taotao.persist.test.mapper.TestMapper" />
  5. </bean>


對應於sqlSessionTemplate,testMapper一樣須要testSqlSessionFactory注入,另一個注入就是你本身定義的Mapper接口,該接口定義了操做數據庫的方法和SQL語句以及不少的註解,稍後我會講到。到此,mybatis和spring整合的文件配置就算OK了(注:若是你須要開通spring對普通類的代理功能,那麼你須要在spring配置文件中加入<aop:aspectj-autoproxy />),至於其餘的如事務配置,AOP切面註解等內容不在本文範圍內,不做累述。

至此,一個完整的myabtis整合spring的配置文件看起來應該以下所示:

Java代碼
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
  4. xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop"
  5. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
  6. http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
  7. http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
  8. http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
  9. <!-- c3p0 connection pool configuration -->
  10. <bean id="testDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
  11. destroy-method="close">
  12. <property name="driverClass" value="${db.driver.class}" />
  13. <property name="jdbcUrl" value="${db.url}" />
  14. <property name="user" value="${db.username}" />
  15. <property name="password" value="${db.password}" />
  16. <property name="initialPoolSize" value="5" />
  17. <property name="minPoolSize" value="5" />
  18. <property name="maxPoolSize" value="20" />
  19. <property name="maxStatements" value="100" />
  20. <property name="maxIdleTime" value="3600" />
  21. <property name="acquireIncrement" value="2" />
  22. <property name="acquireRetryAttempts" value="10" />
  23. <property name="acquireRetryDelay" value="600" />
  24. <property name="testConnectionOnCheckin" value="true" />
  25. <property name="idleConnectionTestPeriod" value="1200" />
  26. <property name="checkoutTimeout" value="10000" />
  27. </bean>
  28. <bean id="testSqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
  29. <property name="configLocation" value="classpath:configuration.xml" />
  30. <property name="dataSource" ref="testDataSource" />
  31. </bean>
  32. <!-- data OR mapping interface -->
  33. <bean id="testMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
  34. <property name="sqlSessionFactory" ref="testSqlSessionFactory" />
  35. <property name="mapperInterface" value="com.wotao.taotao.persist.test.mapper.TestMapper" />
  36. </bean>
  37. <!-- add your own Mapper here -->
  38. <!-- comment here, using annotation -->
  39. <!-- <bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate"> -->
  40. <!-- <constructor-arg index="0" ref="sqlSessionFactory" /> -->
  41. <!-- </bean> -->
  42. <!-- base DAO class, for module business, extend this class in DAO -->
  43. <!-- <bean id="testBaseDAO" class="com.test.dao.TestBaseDAO"> -->
  44. <!-- <property name="sqlSessionTemplate" ref="sqlSessionTemplate" /> -->
  45. <!-- </bean> -->
  46. <!-- <bean id="testDAO" class="com.test.dao.impl.TestDAOImpl" /> -->
  47. <!-- you can DI Bean if you don't like use annotation -->
  48. </beans>



到此爲止,咱們只講了mybatis和spring的整合,尚未真正觸及mybatis的核心:使用mybatis註解代替映射文件編程(不過官方文檔也說了,若是真正想發揮mybatis功能,仍是須要用到映射文件,看來myabtis本身都對mybatis註解沒信心,呵呵),經過上述內容,咱們知道配置搞定,可是testMapper尚未被實現,而註解的使用,所有集中在這個testMapper上,是mybatis註解的核心所在,先來看一下這個testMapper接口是個什麼樣的:

Java代碼
  1. /**
  2. * The test Mapper interface.
  3. *
  4. * @author HuangMin <a href="mailto:minhuang@hengtiansoft.com>send email</a>
  5. *
  6. * @since 1.6
  7. * @version 1.0
  8. *
  9. * #~TestMapper.java 2011-9-23 : afternoon 10:51:40
  10. */
  11. @CacheNamespace(size = 512)
  12. public interface TestMapper {
  13. /**
  14. * get test bean by UID.
  15. *
  16. * @param id
  17. * @return
  18. */
  19. @SelectProvider(type = TestSqlProvider.class, method = "getSql")
  20. @Options(useCache = true, flushCache = false, timeout = 10000)
  21. @Results(value = {
  22. @Result(id = true, property = "id", column = "test_id", javaType = String.class, jdbcType = JdbcType.VARCHAR),
  23. @Result(property = "testText", column = "test_text", javaType = String.class, jdbcType = JdbcType.VARCHAR) })
  24. public TestBean get(@Param("id") String id);
  25. /**
  26. * get all tests.
  27. *
  28. * @return
  29. */
  30. @SelectProvider(type = TestSqlProvider.class, method = "getAllSql")
  31. @Options(useCache = true, flushCache = false, timeout = 10000)
  32. @Results(value = {
  33. @Result(id = true, property = "id", column = "test_id", javaType = String.class, jdbcType = JdbcType.VARCHAR),
  34. @Result(property = "testText", column = "test_text", javaType = String.class, jdbcType = JdbcType.VARCHAR) })
  35. public List<TestBean> getAll();
  36. /**
  37. * get tests by test text.
  38. *
  39. * @param testText
  40. * @return
  41. */
  42. @SelectProvider(type = TestSqlProvider.class, method = "getByTestTextSql")
  43. @Options(useCache = true, flushCache = false, timeout = 10000)
  44. @ResultMap(value = "getByTestText")
  45. public List<TestBean> getByTestText(@Param("testText") String testText);
  46. /**
  47. * insert a test bean into database.
  48. *
  49. * @param testBean
  50. */
  51. @InsertProvider(type = TestSqlProvider.class, method = "insertSql")
  52. @Options(flushCache = true, timeout = 20000)
  53. public void insert(@Param("testBean") TestBean testBean);
  54. /**
  55. * update a test bean with database.
  56. *
  57. * @param testBean
  58. */
  59. @UpdateProvider(type = TestSqlProvider.class, method = "updateSql")
  60. @Options(flushCache = true, timeout = 20000)
  61. public void update(@Param("testBean") TestBean testBean);
  62. /**
  63. * delete a test by UID.
  64. *
  65. * @param id
  66. */
  67. @DeleteProvider(type = TestSqlProvider.class, method = "deleteSql")
  68. @Options(flushCache = true, timeout = 20000)
  69. public void delete(@Param("id") String id);
  70. }


下面逐個對裏面的註解進行分析:
@CacheNamespace(size = 512) : 定義在該命名空間內容許使用內置緩存,最大值爲512個對象引用,讀寫默認是開啓的,緩存內省刷新時間爲默認3600000毫秒,寫策略是拷貝整個對象鏡像到全新堆(如同CopyOnWriteList)所以線程安全。

@SelectProvider(type = TestSqlProvider.class, method = "getSql") : 提供查詢的SQL語句,若是你不用這個註解,你也能夠直接使用@Select("select * from ....")註解,把查詢SQL抽取到一個類裏面,方便管理,同時複雜的SQL也容易操做,type = TestSqlProvider.class就是存放SQL語句的類,而method = "getSql"表示get接口方法須要到TestSqlProvider類的getSql方法中獲取SQL語句。

@Options(useCache = true, flushCache = false, timeout = 10000) : 一些查詢的選項開關,好比useCache = true表示本次查詢結果被緩存以提升下次查詢速度,flushCache = false表示下次查詢時不刷新緩存,timeout = 10000表示查詢結果緩存10000秒。

@Results(value = {
@Result(id = true, property = "id", column = "test_id", javaType = String.class, jdbcType = JdbcType.VARCHAR),
@Result(property = "testText", column = "test_text", javaType = String.class, jdbcType = JdbcType.VARCHAR) }) : 表示sql查詢返回的結果集,@Results是以@Result爲元素的數組,@Result表示單條屬性-字段的映射關係,如:@Result(id = true, property = "id", column = "test_id", javaType = String.class, jdbcType = JdbcType.VARCHAR)能夠簡寫爲:@Result(id = true, property = "id", column = "test_id"),id = true表示這個test_id字段是個PK,查詢時mybatis會給予必要的優化,應該說數組中全部的@Result組成了單個記錄的映射關係,而@Results則單個記錄的集合。另外還有一個很是重要的註解@ResultMap也和@Results差很少,到時會講到。

@Param("id") :全侷限定別名,定義查詢參數在sql語句中的位置再也不是順序下標0,1,2,3....的形式,而是對應名稱,該名稱就在這裏定義。

@ResultMap(value = "getByTestText") :重要的註解,能夠解決複雜的映射關係,包括resultMap嵌套,鑑別器discriminator等等。注意一旦你啓用該註解,你將不得不在你的映射文件中配置你的resultMap,而value = "getByTestText"即爲映射文件中的resultMap ID(注意此處的value = "getByTestText",必須是在映射文件中指定命名空間路徑)。@ResultMap在某些簡單場合能夠用@Results代替,可是複雜查詢,好比聯合、嵌套查詢@ResultMap就會顯得解耦方便更容易管理。
一個映射文件以下所示:

Java代碼
  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE mapper
  3. PUBLIC "-//ibatis.apache.org//DTD Mapper 3.0//EN"
  4. "http://ibatis.apache.org/dtd/ibatis-3-mapper.dtd">
  5. <mapper namespace="com.wotao.taotao.persist.test.mapper.TestMapper">
  6. <resultMap id="getByTestText" type="TestBean">
  7. <id property="id" column="test_id" javaType="string" jdbcType="VARCHAR" />
  8. <result property="testText" column="test_text" javaType="string" jdbcType="VARCHAR" />
  9. </resultMap>
  10. </mapper>


注意文件中的namespace路徑必須是使用@resultMap的類路徑,此處是TestMapper,文件中 id="getByTestText"必須和@resultMap中的value = "getByTestText"保持一致。

@InsertProvider(type = TestSqlProvider.class, method = "insertSql") :用法和含義@SelectProvider同樣,只不過是用來插入數據庫而用的。

@Options(flushCache = true, timeout = 20000) :對於須要更新數據庫的操做,須要從新刷新緩存flushCache = true使緩存同步。

@UpdateProvider(type = TestSqlProvider.class, method = "updateSql") :用法和含義@SelectProvider同樣,只不過是用來更新數據庫而用的。

@Param("testBean") :是一個自定義的對象,指定了sql語句中的表現形式,若是要在sql中引用對象裏面的屬性,只要使用testBean.id,testBean.textText便可,mybatis會經過反射找到這些屬性值。

@DeleteProvider(type = TestSqlProvider.class, method = "deleteSql") :用法和含義@SelectProvider同樣,只不過是用來刪除數據而用的。

如今mybatis註解基本已經講完了,接下來咱們就要開始寫SQL語句了,由於咱們再也不使用映射文件編寫SQL,那麼就不得不在java類裏面寫,就像上面提到的,咱們不得不在TestSqlProvider這個類裏面寫SQL,雖然已經把全部sql語句集中到了一個類裏面去管理,但聽起來彷佛仍然有點噁心,幸虧mybatis提供SelectBuilder和SqlBuilder這2個小工具來幫助咱們生成SQL語句,SelectBuilder專門用來生成select語句,而SqlBuilder則是通常性的工具,能夠生成任何SQL語句,我這裏選擇了SqlBuilder來生成,TestSqlProvider代碼以下:

Java代碼
  1. /*
  2. * #~ test-afternoon10:51:40
  3. */
  4. package com.wotao.taotao.persist.test.sqlprovider;
  5. import static org.apache.ibatis.jdbc.SqlBuilder.BEGIN;
  6. import static org.apache.ibatis.jdbc.SqlBuilder.FROM;
  7. import static org.apache.ibatis.jdbc.SqlBuilder.SELECT;
  8. import static org.apache.ibatis.jdbc.SqlBuilder.SQL;
  9. import static org.apache.ibatis.jdbc.SqlBuilder.WHERE;
  10. import static org.apache.ibatis.jdbc.SqlBuilder.DELETE_FROM;
  11. import static org.apache.ibatis.jdbc.SqlBuilder.INSERT_INTO;
  12. import static org.apache.ibatis.jdbc.SqlBuilder.SET;
  13. import static org.apache.ibatis.jdbc.SqlBuilder.UPDATE;
  14. import static org.apache.ibatis.jdbc.SqlBuilder.VALUES;
  15. import java.util.Map;
  16. /**
  17. * The test sql Provider,define the sql script for mapping.
  18. *
  19. * @author HuangMin <a href="mailto:minhuang@hengtiansoft.com>send email</a>
  20. *
  21. * @since 1.6
  22. * @version 1.0
  23. *
  24. * #~TestSqlProvider.java 2011-9-23 : afternoon 10:51:40
  25. */
  26. public class TestSqlProvider {
  27. /** table name, here is test */
  28. private static final String TABLE_NAME = "test";
  29. /**
  30. * get test by id sql script.
  31. *
  32. * @param parameters
  33. * @return
  34. */
  35. public String getSql(Map<String, Object> parameters) {
  36. String uid = (String) parameters.get("id");
  37. BEGIN();
  38. SELECT("test_id, test_text");
  39. FROM(TABLE_NAME);
  40. if (uid != null) {
  41. WHERE("test_id = #{id,javaType=string,jdbcType=VARCHAR}");
  42. }
  43. return SQL();
  44. }
  45. /**
  46. * get all tests sql script.
  47. *
  48. * @return
  49. */
  50. public String getAllSql() {
  51. BEGIN();
  52. SELECT("test_id, test_text");
  53. FROM(TABLE_NAME);
  54. return SQL();
  55. }
  56. /**
  57. * get test by test text sql script.
  58. *
  59. * @param parameters
  60. * @return
  61. */
  62. public String getByTestTextSql(Map<String, Object> parameters) {
  63. String tText = (String) parameters.get("testText");
  64. BEGIN();
  65. SELECT("test_id, test_text");
  66. FROM(TABLE_NAME);
  67. if (tText != null) {
  68. WHERE("test_text like #{testText,javaType=string,jdbcType=VARCHAR}");
  69. }
  70. return SQL();
  71. }
  72. /**
  73. * insert a test sql script.
  74. *
  75. * @return
  76. */
  77. public String insertSql() {
  78. BEGIN();
  79. INSERT_INTO(TABLE_NAME);
  80. VALUES("test_id", "#{testBean.id,javaType=string,jdbcType=VARCHAR}");
  81. VALUES("test_text", "#{testBean.testText,javaType=string,jdbcType=VARCHAR}");
  82. return SQL();
  83. }
  84. /**
  85. * update a test sql script.
  86. *
  87. * @return
  88. */
  89. public String updateSql() {
  90. BEGIN();
  91. UPDATE(TABLE_NAME);
  92. SET("test_text = #{testBean.testText,javaType=string,jdbcType=VARCHAR}");
  93. WHERE("test_id = #{testBean.id,javaType=string,jdbcType=VARCHAR}");
  94. return SQL();
  95. }
  96. /**
  97. * delete a test sql script.
  98. *
  99. * @return
  100. */
  101. public String deleteSql() {
  102. BEGIN();
  103. DELETE_FROM(TABLE_NAME);
  104. WHERE("test_id = #{id,javaType=string,jdbcType=VARCHAR}");
  105. return SQL();
  106. }
  107. }


BEGIN();表示刷新本地線程,某些變量爲了線程安全,會先在本地存放變量,此處須要刷新。
SELECT,FROM,WHERE等等都是sqlbuilder定義的公用靜態方法,用來組成你的sql字符串。若是你在testMapper中調用該方法的某個接口方法已經定義了參數@Param(),那麼該方法的參數Map<String, Object> parameters即組裝了@Param()定義的參數,好比testMapper接口方法中定義參數爲@Param("testId"),@Param("testText"),那麼parameters的形態就是:[key="testId",value=object1],[key="testText",value=object2],若是接口方法沒有定義@Param(),那麼parameters的key就是參數的順序小標:[key=0,value=object1],[key=1,value=object2],SQL()將返回最終append結束的字符串,sql語句中的形如
#{id,javaType=string,jdbcType=VARCHAR}徹底可簡寫爲#{id},我只是爲了規整如此寫而已。另外,對於複雜查詢還有不少標籤可用,好比:JOIN,INNER_JOIN,GROUP_BY,ORDER_BY等等,具體使用詳情,你能夠查看源碼。

最後記得把你的Mapper接口注入到你的DAO類中,在DAO中引用Mapper接口方法便可。我在BaseDAO中的註解注入以下:

Java代碼
  1. ......
  2. @Repository("testBaseDAO")
  3. public class TestBaseDAO {
  4. ......

 

Java代碼
  1. ......
  2. /**
  3. * @param testMapper
  4. * the testMapper to set
  5. */
  6. @Autowired
  7. public void setTestMapper(@Qualifier("testMapper") TestMapper testMapper) {
  8. this.testMapper = testMapper;
  9. }
  10. ......

 

引自:http://wwww.iteye.com/blog/1235996

 

http://www.cnblogs.com/ibook360/archive/2012/07/16/2594056.html

相關文章
相關標籤/搜索