MyBatis直接執行SQL的工具SqlMapper

來源:互聯網
上載者:User

標籤:mybatis   sql   

可能有些人也有過類似需求,一般都會選擇使用其他的方式如Spring-JDBC等方式解決。

能否通過MyBatis實現這樣的功能呢?

為了讓通用Mapper更徹底的支援多表操作以及更靈活的操作,在2.2.0版本增加了一個可以直接執行SQL的新類SqlMapper

通過這篇部落格,我們來瞭解一下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個方法,這些方法的命名和參數和SqlSession介面的很像,只是基本上第一個參數都成了sql。

其中Object value為入參,入參形式和SqlSession中的入參一樣,帶有入參的方法,在使用時sql可以包含#{param}${param}形式的參數,這些參數需要通過入參來傳值。需要的參數過多的時候,參數可以使用Map類型。另外這種情況下的sql還支援下面這種複雜形式:

String sql = "<script>select * from sys_user where 1=1"  +         "<if test=\"usertype != null\">usertype = #{usertype}</if></script>";

這種情況用的比較少,不多說。

不帶有Object value的所有方法,sql中如果有參數需要手動拼接成一個可以直接執行的sql語句。

selectXXX方法中,使用Class<T> resultType可以指定傳回型別,否則就是Map<String,Object>類型。

執行個體化 SqlMapper

SqlMapper構造參數public SqlMapper(SqlSession sqlSession),需要一個入參SqlSession sqlSession,在一般系統中,可以按照下面的方式擷取:

SqlSession sqlSession = (...);//通過某些方法擷取sqlSession//建立sqlMapperSqlMapper sqlMapper = new SqlMapper(sqlSession);

如果使用的Spring,那麼可以按照下面的方式配置<bean>:

<bean id="sqlMapper" class="com.github.abel533.sql.SqlMapper" scope="prototype">  <constructor-arg ref="sqlSession"/></bean>

在Service中使用的時候可以直接使用@Autowired注入。

簡單例子

src/test/java目錄的com.github.abel533.sql包中包含這些方法的測試。

下面挑幾個看看如何使用。

selectList
//查詢,返回List<Map>List<Map<String, Object>> list = sqlMapper.selectList("select * from country where id < 11");//查詢,返回指定的實體類List<Country> countryList = sqlMapper.selectList("select * from country where id < 11", Country.class);//查詢,帶參數countryList = sqlMapper.selectList("select * from country where id < #{id}", 11, Country.class);//複雜點的查詢,這裡參數和上面不同的地方,在於傳入了一個對象Country country = new Country();country.setId(11);countryList = sqlMapper.selectList("<script>" +        "select * from country " +        "   <where>" +        "       <if test=\"id != null\">" +        "           id &lt; #{id}" +        "       </if>" +        "   </where>" +        "</script>", country, Country.class);
selectOne
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
//insertint 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);//updateresult = 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);//deleteresult = sqlMapper.delete("delete from country where id = 35");result = sqlMapper.delete("delete from country where id = #{id}", 35);
注意

通過上面這些例子應該能對此有個基本的瞭解,但是如果你使用參數方式,建議閱讀下面的文章:

深入瞭解MyBatis參數

實現原理

2015-03-09:最初想要設計這個功能的時候,感覺會很複雜,想的也複雜,需要很多個類,因此當時沒有實現。

2015-03-10:突發奇想,設計了現在的這種方式。並且有種強烈的感覺就是幸好昨天沒有嘗試去實現,因為昨天晚上思考這個問題的時候是晚上10點多,而今天(10號)是7點開始思考。我很慶幸在一個更清醒的狀態下去寫這段代碼。

下面簡單說思路和實現方式。

在寫MyBatis分頁外掛程式的時候熟悉了MappedStatement類。

在寫通用Mapper的時候熟悉了xmlSqlNode結構。

如果我根據SQL動態建立一個MappedStatement,然後使用MappedStatementidsqlSession中執行不就可以了嗎?

想到這一點,一切就簡單了。

看看下面select查詢建立MappedStatement的代碼:

/** * 建立一個查詢的MS * * @param msId * @param sqlSource 執行的sqlSource * @param resultType 返回的結果類型 */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);}

代碼是不是很簡單,這段代碼的關鍵是參數sqlSource,下面是建立SqlSource的方法,分為兩種。

一種是一個完整的sql,不需要參數的,可以直接執行的:

StaticSqlSource sqlSource = new StaticSqlSource(configuration, sql);

其中configurationsqlSession中擷取,sql就是使用者傳入到sql語句,是不是也很簡單?

另一種是支援動態sql的,支援參數的SqlSource

SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql, parameterType);

是不是也很簡單?這個方法其實可以相容上面的StaticSqlSource,這裡比上面多了一個parameterType,因為這兒是可以傳遞參數的,另外languageDriver是從configuration中擷取的。

是不是很簡單?

我一開始也沒想到MyBatis直接執行sql實現起來會這麼的容易。

insert,delete,update方法的建立更容易,因為他們的傳回值都是int,所以處理起來更簡單,有興趣的可以去通用Mapper下的包com.github.abel533.sql中查看SqlMapper的源碼。

MyBatis直接執行SQL的工具SqlMapper

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.