可能有些人也有過(guò)類似需求,一般都會(huì)選擇使用其他的方式如spring-jdbc等方式解決。
能否通過(guò)mybatis實(shí)現(xiàn)這樣的功能呢?
為了讓通用mapper更徹底的支持多表操作以及更靈活的操作,在2.2.0版本增加了一個(gè)可以直接執(zhí)行sql的新類sqlmapper。
我們來(lái)了解一下sqlmapper。
sqlmapper提供的方法
sqlmapper提供了以下這些公共方法:
- map<string,object> selectone(string sql)
- map<string,object> selectone(string sql, object value)
- <t> t selectone(string sql, class<t> resulttype)
- <t> t selectone(string sql, object value, class<t> resulttype)
- list<map<string,object>> selectlist(string sql)
- list<map<string,object>> selectlist(string sql, object value)
- <t> list<t> selectlist(string sql, class<t> resulttype)
- <t> list<t> selectlist(string sql, object value, class<t> resulttype)
- int insert(string sql)
- int insert(string sql, object value)
- int update(string sql)
- int update(string sql, object value)
- int delete(string sql)
- int delete(string sql, object value)
一共14個(gè)方法,這些方法的命名和參數(shù)和sqlsession接口的很像,只是基本上第一個(gè)參數(shù)都成了sql。
其中object value為入?yún)ⅲ雲(yún)⑿问胶蛃qlsession中的入?yún)⒁粯樱瑤в腥雲(yún)⒌姆椒ǎ谑褂脮r(shí)sql可以包含#{param}或${param}形式的參數(shù),這些參數(shù)需要通過(guò)入?yún)?lái)傳值。需要的參數(shù)過(guò)多的時(shí)候,參數(shù)可以使用map類型。另外這種情況下的sql還支持下面這種復(fù)雜形式:
1
2
|
string sql = "<script>select * from sys_user where 1=1" + "<if test=\"usertype != null\">usertype = #{usertype}</if></script>" ; |
這種情況用的比較少,不多說(shuō)。
不帶有object value的所有方法,sql中如果有參數(shù)需要手動(dòng)拼接成一個(gè)可以直接執(zhí)行的sql語(yǔ)句。
在selectxxx方法中,使用class<t> resulttype可以指定返回類型,否則就是map<string,object>類型。
實(shí)例化sqlmapper
sqlmapper構(gòu)造參數(shù)public sqlmapper(sqlsession sqlsession),需要一個(gè)入?yún)qlsession sqlsession,在一般系統(tǒng)中,可以按照下面的方式獲取:
1
2
3
|
sqlsession sqlsession = (...); //通過(guò)某些方法獲取sqlsession //創(chuàng)建sqlmapper sqlmapper sqlmapper = new sqlmapper(sqlsession); |
如果使用的spring,那么可以按照下面的方式配置<bean>:
1
2
3
|
<bean id= "sqlmapper" class = "com.github.abel533.sql.sqlmapper" scope= "prototype" > <constructor-arg ref= "sqlsession" /> </bean> |
在service中使用的時(shí)候可以直接使用@autowired注入。
簡(jiǎn)單例子
在src/test/java目錄的com.github.abel533.sql包中包含這些方法的測(cè)試。
下面挑幾個(gè)看看如何使用。
selectlist
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
//查詢,返回list<map> list<map<string, object>> list = sqlmapper.selectlist( "select * from country where id < 11" ); //查詢,返回指定的實(shí)體類 list<country> countrylist = sqlmapper.selectlist( "select * from country where id < 11" , country. class ); //查詢,帶參數(shù) countrylist = sqlmapper.selectlist( "select * from country where id < #{id}" , 11 , country. class ); //復(fù)雜點(diǎn)的查詢,這里參數(shù)和上面不同的地方,在于傳入了一個(gè)對(duì)象 country country = new country(); country.setid( 11 ); countrylist = sqlmapper.selectlist( "<script>" + "select * from country " + " <where>" + " <if test=\"id != null\">" + " id < #{id}" + " </if>" + " </where>" + "</script>" , country, country. class ); |
selectone
1
2
3
4
|
map<string, object> map = sqlmapper.selectone( "select * from country where id = 35" ); map = sqlmapper.selectone( "select * from country where id = #{id}" , 35 ); country country = sqlmapper.selectone( "select * from country where id = 35" , country. class ); country = sqlmapper.selectone( "select * from country where id = #{id}" , 35 , country. class ); |
insert,update,delete
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
//insert int result = sqlmapper.insert( "insert into country values(1921,'天朝','tc')" ); country tc = new country(); tc.setid( 1921 ); tc.setcountryname( "天朝" ); tc.setcountrycode( "tc" ); //注意這里的countrycode和countryname故意寫反的 result = sqlmapper.insert( "insert into country values(#{id},#{countrycode},#{countryname})" , tc); //update result = sqlmapper.update( "update country set countryname = '天朝' where id = 35" ); tc = new country(); tc.setid( 35 ); tc.setcountryname( "天朝" ); int result = sqlmapper.update( "update country set countryname = #{countryname}" + " where id in(select id from country where countryname like 'a%')" , tc); //delete result = sqlmapper.delete( "delete from country where id = 35" ); result = sqlmapper.delete( "delete from country where id = #{id}" , 35 ); |
注意
通過(guò)上面這些例子應(yīng)該能對(duì)此有個(gè)基本的了解,但是如果你使用參數(shù)方式,建議閱讀下面的文章:
實(shí)現(xiàn)原理
最初想要設(shè)計(jì)這個(gè)功能的時(shí)候,感覺(jué)會(huì)很復(fù)雜,想的也復(fù)雜,需要很多個(gè)類,因此當(dāng)時(shí)沒(méi)有實(shí)現(xiàn)。
突發(fā)奇想,設(shè)計(jì)了現(xiàn)在的這種方式。并且有種強(qiáng)烈的感覺(jué)就是幸好昨天沒(méi)有嘗試去實(shí)現(xiàn),因?yàn)樽蛱焱砩纤伎歼@個(gè)問(wèn)題的時(shí)候是晚上10點(diǎn)多,而今天晚上7點(diǎn)開(kāi)始思考。我很慶幸在一個(gè)更清醒的狀態(tài)下去寫這段代碼。
下面簡(jiǎn)單說(shuō)思路和實(shí)現(xiàn)方式。
在寫mybatis分頁(yè)插件的時(shí)候熟悉了mappedstatement類。
在寫通用mapper的時(shí)候熟悉了xml轉(zhuǎn)sqlnode結(jié)構(gòu)。
如果我根據(jù)sql動(dòng)態(tài)的創(chuàng)建一個(gè)mappedstatement,然后使用mappedstatement的id在sqlsession中執(zhí)行不就可以了嗎?
想到這一點(diǎn),一切就簡(jiǎn)單了。
看看下面select查詢創(chuàng)建mappedstatement的代碼:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
/** * 創(chuàng)建一個(gè)查詢的ms * @param msid * @param sqlsource 執(zhí)行的sqlsource * @param resulttype 返回的結(jié)果類型 */ private void newselectmappedstatement(string msid, sqlsource sqlsource, final class <?> resulttype) { mappedstatement ms = new mappedstatement.builder( configuration, msid, sqlsource, sqlcommandtype.select) .resultmaps( new arraylist<resultmap>() { { add( new resultmap.builder(configuration, "defaultresultmap" , resulttype, new arraylist<resultmapping>( 0 )).build()); } }) .build(); //緩存 configuration.addmappedstatement(ms); } |
代碼是不是很簡(jiǎn)單,這段代碼的關(guān)鍵是參數(shù)sqlsource,下面是創(chuàng)建sqlsource的方法,分為兩種。
一種是一個(gè)完整的sql,不需要參數(shù)的,可以直接執(zhí)行的:
1
|
staticsqlsource sqlsource = new staticsqlsource(configuration, sql); |
其中configuration從sqlsession中獲取,sql就是用戶傳入到sql語(yǔ)句,是不是也很簡(jiǎn)單?
另一種是支持動(dòng)態(tài)sql的,支持參數(shù)的sqlsource:
1
|
sqlsource sqlsource = languagedriver.createsqlsource(configuration, sql, parametertype); |
是不是也很簡(jiǎn)單?這個(gè)方法其實(shí)可以兼容上面的staticsqlsource,這里比上面多了一個(gè)parametertype,因?yàn)檫@兒是可以傳遞參數(shù)的,另外languagedriver是從configuration中獲取的。
是不是很簡(jiǎn)單?
我一開(kāi)始也沒(méi)想到mybatis直接執(zhí)行sql實(shí)現(xiàn)起來(lái)會(huì)這么的容易。
insert,delete,update方法的創(chuàng)建更容易,因?yàn)樗麄兊姆祷刂刀际莍nt,所以處理起來(lái)更簡(jiǎn)單,有興趣的可以查看sqlmapper的源碼。
總結(jié)
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,謝謝大家對(duì)服務(wù)器之家的支持。如果你想了解更多相關(guān)內(nèi)容請(qǐng)查看下面相關(guān)鏈接
原文鏈接:https://blog.csdn.net/isea533/article/details/44193939