最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Mybatis中SqlMapper配置的擴(kuò)展與應(yīng)用詳細(xì)介紹(1)

 更新時間:2016年11月08日 08:54:38   作者:linjisong  
這篇文章主要介紹了Mybatis中SqlMapper配置的擴(kuò)展與應(yīng)用(1)的相關(guān)資料,非常不錯具有參考借鑒價(jià)值,需要的朋友可以參考下

奮斗了好幾個晚上調(diào)試程序,寫了好幾篇博客,終于建立起了Mybatis配置的擴(kuò)展機(jī)制。雖然擴(kuò)展機(jī)制是重要的,然而如果沒有真正實(shí)用的擴(kuò)展功能,那也至少是不那么鼓舞人心的,這篇博客就來舉幾個擴(kuò)展的例子。

這次研讀源碼的起因是Oracle和MySQL數(shù)據(jù)庫的兼容性,比如在Oracle中使用雙豎線作為連接符,而MySQL中使用CONCAT函數(shù);比如Oracle中可以使用DECODE函數(shù),而MySQL中只能使用標(biāo)準(zhǔn)的CASE WHEN;又比如Oracle中可以執(zhí)行DELETE FORM TABLE WHERE FIELD1 IN (SELECT FIELD1 FORM TABLE WHERE FIELD2=?),但是MySQL中會拋出異常,等等。

下面就從解決這些兼容性問題開始,首先需要在配置中添加數(shù)據(jù)庫標(biāo)識相關(guān)的配置:

<!-- 自行構(gòu)建Configuration對象 --> 
<bean id="mybatisConfig" class="org.dysd.dao.mybatis.schema.SchemaConfiguration"/>
<bean id="sqlSessionFactory" p:dataSource-ref="dataSource" 
class="org.dysd.dao.mybatis.schema.SchemaSqlSessionFactoryBean">
<!-- 注入mybatis配置對象 -->
<property name="configuration" ref="mybatisConfig"/>
<!-- 自動掃描SqlMapper配置文件 -->
<property name="mapperLocations">
<array>
<value>classpath*:**/*.sqlmapper.xml</value>
</array>
</property>
<!-- 數(shù)據(jù)庫產(chǎn)品標(biāo)識配置 -->
<property name="databaseIdProvider">
<bean class="org.apache.ibatis.mapping.VendorDatabaseIdProvider">
<property name="properties">
<props>
<!-- 意思是如果數(shù)據(jù)庫產(chǎn)品描述中包含關(guān)鍵字MYSQL,則使用mysql作為Configuration中的databaseId,mybatis原生的實(shí)現(xiàn)關(guān)鍵字區(qū)分大小寫,我沒有測試Oracle和DB2 -->
<prop key="MySQL">mysql</prop>
<prop key="oracle">oracle</prop>
<prop key="H2">h2</prop>
<prop key="db2">db2</prop>
</props>
</property>
</bean>
</property>
</bean>

一、連接符問題

1、編寫SQL配置函數(shù)實(shí)現(xiàn)類

public class ConcatSqlConfigFunction extends AbstractSqlConfigFunction{//抽象父類中設(shè)定了默認(rèn)的order級別
@Override
public String getName() {
return "concat";
}
@Override
public String eval(String databaseId, String[] args) {
if(args.length < 2){
Throw.throwException("the concat function require at least two arguments.");
}
if("mysql".equalsIgnoreCase(databaseId)){
return "CONCAT("+Tool.STRING.join(args, ",")+")";
}else{
return Tool.STRING.join(args, "||");
}
}
}

2、在SchemaHandlers類的靜態(tài)代碼塊中注冊,或者在啟動初始化類中調(diào)用SchemaHandlers的方法注冊

static {
//注冊默認(rèn)命名空間的StatementHandler
register("cache-ref", new CacheRefStatementHandler());
register("cache", new CacheStatementHandler());
register("parameterMap", new ParameterMapStatementHandler());
register("resultMap", new ResultMapStatementHandler());
register("sql", new SqlStatementHandler());
register("select|insert|update|delete", new CRUDStatementHandler());
//注冊默認(rèn)命名空間的ScriptHandler
register("trim", new TrimScriptHandler());
register("where", new WhereScriptHandler());
register("set", new SetScriptHandler());
register("foreach", new ForEachScriptHandler());
register("if|when", new IfScriptHandler());
register("choose", new ChooseScriptHandler());
//register("when", new IfScriptHandler());
register("otherwise", new OtherwiseScriptHandler());
register("bind", new BindScriptHandler());
// 注冊自定義命名空間的處理器
registerExtend("db", new DbStatementHandler(), new DbScriptHandler());
// 注冊SqlConfigFunction
register(new DecodeSqlConfigFunction());
register(new ConcatSqlConfigFunction());
// 注冊SqlConfigFunctionFactory
register(new LikeSqlConfigFunctionFactory());
}

上面代碼除了注冊ConcatSQLConfigFunction外,還有一些其它的注冊代碼,這里一并給出,下文將省略。

3、修改SqlMapper配置

<select id="selectString" resultType="string">
select PARAM_NAME, $concat{PARAM_CODE, PARAM_NAME} AS CODE_NAME 
from BF_PARAM_ENUM_DEF
<if test="null != paramName and '' != paramName">
where PARAM_NAME LIKE $CONCAT{'%', #{paramName, jdbcType=VARCHAR}, '%'}
</if>
</select>

4、編寫dao接口類

@Repository
public interface IExampleDao {
public String selectString(@Param("paramName")String paramName);
}

5、編寫測試類

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={
"classpath:spring/applicationContext.xml" 
})
@Component
public class ExampleDaoTest {
@Resource
private IExampleDao dao;
@Test
public void testSelectString(){
String a = dao.selectString("顯示");
Assert.assertEquals("顯示區(qū)域", a);
}
}

6、分別在MySQL和H2中運(yùn)行如下(將mybatis日志級別調(diào)整為TRACE)

(1)MySQL

20161108 00:12:55,235 [main]-[DEBUG] ==> Preparing: select PARAM_NAME, CONCAT(PARAM_CODE,PARAM_NAME) AS CODE_NAME from BF_PARAM_ENUM_DEF where PARAM_NAME LIKE CONCAT('%',?,'%') 
20161108 00:12:55,269 [main]-[DEBUG] ==> Parameters: 顯示(String)
20161108 00:12:55,287 [main]-[TRACE] <== Columns: PARAM_NAME, CODE_NAME
20161108 00:12:55,287 [main]-[TRACE] <== Row: 顯示區(qū)域, DISPLAY_AREA顯示區(qū)域
20161108 00:12:55,289 [main]-[DEBUG] <== Total: 1

(2)H2

20161108 00:23:08,348 [main]-[DEBUG] ==> Preparing: select PARAM_NAME, PARAM_CODE||PARAM_NAME AS CODE_NAME from BF_PARAM_ENUM_DEF where PARAM_NAME LIKE '%'||?||'%' 
20161108 00:23:08,364 [main]-[DEBUG] ==> Parameters: 顯示(String)
20161108 00:23:08,411 [main]-[TRACE] <== Columns: PARAM_NAME, CODE_NAME
20161108 00:23:08,411 [main]-[TRACE] <== Row: 顯示區(qū)域, DISPLAY_AREA顯示區(qū)域
20161108 00:23:08,411 [main]-[DEBUG] <== Total: 1

可以看到,已經(jīng)解決連接符的兼容性問題了。

另外,我們也發(fā)現(xiàn),使用LIKE關(guān)鍵字時,寫起來比較麻煩,那我們就給它一組新的SQL配置函數(shù)吧:

public class LikeSqlConfigFunctionFactory implements ISqlConfigFunctionFactory{
@Override
public Collection<ISqlConfigFunction> getSqlConfigFunctions() {
return Arrays.asList(getLeftLikeSqlConfigFunction(),getRightLikeSqlConfigFunction(),getLikeSqlConfigFunction());
}
private ISqlConfigFunction getLeftLikeSqlConfigFunction(){
return new AbstractLikeSqlConfigFunction(){
@Override
public String getName() {
return "llike";
}
@Override
protected String eval(String arg) {
return "LIKE $concat{'%',"+arg+"}";
}
};
}
private ISqlConfigFunction getRightLikeSqlConfigFunction(){
return new AbstractLikeSqlConfigFunction(){
@Override
public String getName() {
return "rlike";
}
@Override
protected String eval(String arg) {
return "LIKE $concat{"+arg+", '%'}";
}
};
}
private ISqlConfigFunction getLikeSqlConfigFunction(){
return new AbstractLikeSqlConfigFunction(){
@Override
public String getName() {
return "like";
}
@Override
protected String eval(String arg) {
return "LIKE $concat{'%',"+arg+", '%'}";
}
};
}
private abstract class AbstractLikeSqlConfigFunction extends AbstractSqlConfigFunction{
@Override
public String eval(String databaseId, String[] args) {
if(args.length != 1){
Throw.throwException("the like function require one and only one argument.");
}
return eval(args[0]);
}
protected abstract String eval(String arg);
}
}

這里,定義了一組SQL配置函數(shù),左相似,右相似以及中間相似匹配,并且SQL配置函數(shù)還可以嵌套。于是,SqlMapper的配置文件簡化為:

<select id="selectString" resultType="string">
select PARAM_NAME, $concat{PARAM_CODE, PARAM_NAME} AS CODE_NAME 
from BF_PARAM_ENUM_DEF
<if test="null != paramName and '' != paramName">
where PARAM_NAME $like{#{paramName, jdbcType=VARCHAR}}
</if>
</select>

運(yùn)行結(jié)果完全相同。

如果還覺得麻煩,因?yàn)镻ARAM_NAME和paramName是駝峰式對應(yīng),甚至還可以添加一個fieldLike函數(shù),并將配置修改為

where $fieldLike{#{PARAM_NAME, jdbcType=VARCHAR}}

如果再結(jié)合數(shù)據(jù)字典,jdbcType的配置也可自動生成:

where $fieldLike{#{PARAM_NAME}}

這種情形下,如果有多個參數(shù),也不會出現(xiàn)歧義(或者新定義一個配置函數(shù)$likes{}消除歧義),于是可將多個條件簡化成:

where $likes{#{PARAM_NAME, PARAM_NAME2, PARAM_NAME3}}

當(dāng)然,還有更多可挖掘的簡化,已經(jīng)不止是兼容性的范疇了,這里就不再進(jìn)一步展開了。

二、DECODE函數(shù)/CASE ... WHEN

Oracle中的DECODE函數(shù)非常方便,語法如下:

DECODE(條件,值1,返回值1,值2,返回值2,...值n,返回值n[,缺省值])

等價(jià)的標(biāo)準(zhǔn)寫法:

CASE 條件
WHEN 值1 THEN 返回值1
WHEN 值2 THEN 返回值2
...
WHEN 值n THEN 返回值n
[ELSE 缺省值]
END

現(xiàn)在我們來實(shí)現(xiàn)一個$decode配置函數(shù):

public class DecodeSqlConfigFunction extends AbstractSqlConfigFunction{
@Override
public String getName() {
return "decode";
}
@Override
public String eval(String databaseId, String[] args) {
if(args.length < 3){
Throw.throwException("the decode function require at least three arguments.");
}
if("h2".equalsIgnoreCase(databaseId)){//測試時,使用h2代替oracle,正式程序中修改為oracle
return "DECODE("+Tool.STRING.join(args, ",")+")";
}else{
StringBuffer sb = new StringBuffer();
sb.append("CASE ").append(args[0]);
int i=2, l = args.length;
for(; i < l; i= i+2){
sb.append(" WHEN ").append(args[i-1]).append(" THEN ").append(args[i]);
}
if(i == l){//結(jié)束循環(huán)時,兩者相等說明最后一個參數(shù)未使用
sb.append(" ELSE ").append(args[l-1]);
}
sb.append(" END");
return sb.toString();
}
}
}

然后使用SchemaHandlers注冊,修改SqlMapper中配置:

<select id="selectString" resultType="string">
select PARAM_NAME, $decode{#{paramName}, '1', 'A', '2', 'B','C'} AS DECODE_TEST 
from BF_PARAM_ENUM_DEF
<if test="null != paramName and '' != paramName">
where PARAM_NAME $like{#{paramName, jdbcType=VARCHAR}}
</if>
</select>

測試如下:

(1)H2中(以H2代替Oracle)

20161108 06:53:29,747 [main]-[DEBUG] ==> Preparing: select PARAM_NAME, DECODE(?,'1','A','2','B','C') AS DECODE_TEST from BF_PARAM_ENUM_DEF where PARAM_NAME LIKE '%'||?||'%'

(2)MySQL中

20161108 06:50:55,998 [main]-[DEBUG] ==> Preparing: select PARAM_NAME, CASE ? WHEN '1' THEN 'A' WHEN '2' THEN 'B' ELSE 'C' END AS DECODE_TEST from BF_PARAM_ENUM_DEF where PARAM_NAME LIKE '%'||?||'%'

以上所述是小編給大家介紹的Mybatis中SqlMapper配置的擴(kuò)展與應(yīng)用詳細(xì)介紹(1),希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復(fù)大家的。在此也非常感謝大家對腳本之家網(wǎng)站的支持!

相關(guān)文章

  • Java 中通過 key 獲取鎖的方法

    Java 中通過 key 獲取鎖的方法

    這篇文章主要介紹了Java 中通過 key 獲取鎖,本文演示如何對某個 key 加鎖,以保證對該 key 的并發(fā)操作限制,可以實(shí)現(xiàn)同一個 key 一個或者多個線程同時執(zhí)行,需要的朋友可以參考下
    2022-11-11
  • WebService的相關(guān)概念

    WebService的相關(guān)概念

    這篇文章主要介紹了WebService的相關(guān)概念的相關(guān)資料,需要的朋友可以參考下
    2017-10-10
  • Java中消息隊(duì)列任務(wù)的平滑關(guān)閉詳解

    Java中消息隊(duì)列任務(wù)的平滑關(guān)閉詳解

    對于消息隊(duì)列的監(jiān)聽,我們一般使用Java寫一個獨(dú)立的程序,在Linux服務(wù)器上運(yùn)行。程序啟動后,通過消息隊(duì)列客戶端接收消息,放入一個線程池進(jìn)行異步處理,并發(fā)的快速處理。這篇文章主要給大家介紹了關(guān)于Java中消息隊(duì)列任務(wù)的平滑關(guān)閉的相關(guān)資料,需要的朋友可以參考下。
    2017-11-11
  • 基于@MapperScan和@ComponentScan的使用區(qū)別

    基于@MapperScan和@ComponentScan的使用區(qū)別

    這篇文章主要介紹了@MapperScan和@ComponentScan的使用區(qū)別,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • springboot訪問請求404的原因及解決辦法

    springboot訪問請求404的原因及解決辦法

    在使用Spring Boot開發(fā)應(yīng)用程序時,有時可能會遇到訪問請求出現(xiàn)404錯誤的情況,即請求的資源未找到,這篇文章主要給大家介紹了關(guān)于springboot訪問請求404的原因及解決辦法,需要的朋友可以參考下
    2023-09-09
  • java實(shí)現(xiàn)excel和txt文件互轉(zhuǎn)

    java實(shí)現(xiàn)excel和txt文件互轉(zhuǎn)

    本篇文章主要介紹了java實(shí)現(xiàn)excel和txt文件互轉(zhuǎn)的相關(guān)知識。具有很好的參考價(jià)值。下面跟著小編一起來看下吧
    2017-04-04
  • 使用原生JDBC動態(tài)解析并獲取表格列名和數(shù)據(jù)的方法

    使用原生JDBC動態(tài)解析并獲取表格列名和數(shù)據(jù)的方法

    這篇文章主要介紹了使用原生JDBC動態(tài)解析并獲取表格列名和數(shù)據(jù),本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-08-08
  • 淺析SpringBoot自動裝配的實(shí)現(xiàn)

    淺析SpringBoot自動裝配的實(shí)現(xiàn)

    springboot開箱即用,其實(shí)實(shí)現(xiàn)了自動裝配,本文重點(diǎn)給大家介紹SpringBoot是如何做到自動裝配的,感興趣的朋友跟隨小編一起看看吧
    2022-02-02
  • JAVA演示阿里云圖像識別API,印刷文字識別-營業(yè)執(zhí)照識別

    JAVA演示阿里云圖像識別API,印刷文字識別-營業(yè)執(zhí)照識別

    最近有由于工作需要,開始接觸阿里云的云市場的印刷文字識別API-營業(yè)執(zhí)照識別這里我加上了官網(wǎng)的申請說明,只要你有阿里云賬號就可以用,前500次是免費(fèi)的,API說明很簡陋,只能做個簡單參考
    2019-05-05
  • jvm crash的崩潰日志詳細(xì)分析及注意點(diǎn)

    jvm crash的崩潰日志詳細(xì)分析及注意點(diǎn)

    本篇文章主要介紹了jvm crash的崩潰日志詳細(xì)分析及注意點(diǎn)。具有很好的參考價(jià)值,下面跟著小編一起來看下吧
    2017-04-04

最新評論

青铜峡市| 军事| 井陉县| 昌吉市| 乐业县| 衢州市| 叙永县| 遵义市| 师宗县| 聊城市| 罗源县| 海兴县| 广安市| 绍兴县| 喀喇沁旗| 日喀则市| 临桂县| 阳曲县| 莱阳市| 明光市| 湘西| 泰和县| 蕉岭县| 棋牌| 方城县| 嘉义市| 丽水市| 南漳县| 万荣县| 阆中市| 河间市| 咸宁市| 吴江市| 内江市| 陆川县| 循化| 石柱| 安西县| 镇雄县| 鸡东县| 崇礼县|