Mybatis使用小札

前言

Mybatis在我所見過的持久化框架裏真心是一個異類,由於它是sql-centric的,而不是基於對象和表映射的。我會在本文中講一下Mybatis幾個重要的技巧,與本文的上一篇文章Hibernate作個對比。java

Mybatis配置

在ApplicationContext上加上以下配置:mysql

XML<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="mapperLocations" value="classpath*:mapper/*.xml" />
        <property name="configLocation" value="classpath:mybatis-config.xml"/>
    </bean>
    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
        <constructor-arg index="0" ref="sqlSessionFactory" />
    </bean>
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="sbeat.dao" />
</bean>

而後在mybatis-config.xml中作進一步的配置。git

XML<configuration>

    <typeAliases>
        <package name="sbeat.model" />
    </typeAliases>

</configuration>

Mybatis 分頁

Mybatis不支持分頁,因此我採用了PageHelper這個插件,首先在你的Mybatis配置文件里加上一下配置github

XML
<plugins> <!-- com.github.pagehelper爲PageHelper類所在包名 --> <plugin interceptor="com.github.pagehelper.PageHelper"> <property name="dialect" value="mysql" /> <!-- 該參數默認爲false --> <!-- 設置爲true時,會將RowBounds第一個參數offset當成pageNum頁碼使用 --> <!-- 和startPage中的pageNum效果同樣 --> <!-- <property name="offsetAsPageNum" value="false" /> --> <!-- 該參數默認爲false --> <!-- 設置爲true時,使用RowBounds分頁會進行count查詢 --> <!-- <property name="rowBoundsWithCount" value="false" /> --> <!-- 設置爲true時,若是pageSize=0或者RowBounds.limit = 0就會查詢出所有的結果 --> <!-- (至關於沒有執行分頁查詢,可是返回結果仍然是Page類型) --> <property name="pageSizeZero" value="true" /> <!-- 3.3.0版本可用 - 分頁參數合理化,默認false禁用 --> <!-- 啓用合理化時,若是pageNum<1會查詢第一頁,若是pageNum>pages會查詢最後一頁 --> <!-- 禁用合理化時,若是pageNum<1或pageNum>pages會返回空數據 --> <property name="reasonable" value="false" /> <!-- 3.5.0版本可用 - 爲了支持startPage(Object params)方法 --> <!-- 增長了一個`params`參數來配置參數映射,用於從Map或ServletRequest中取值 --> <!-- 能夠配置pageNum,pageSize,count,pageSizeZero,reasonable,不配置映射的用默認值 --> <!-- 不理解該含義的前提下,不要隨便複製該配置 --> <!-- <property name="params" value="pageNum=start;pageSize=limit;" /> --> </plugin> </plugins>

而後在須要分頁的查詢以前,加上下面一句話:spring

javaPageHelper.startPage(pageNum,PAGE_SIZE);

Mybatis 中的sql標籤

因爲Mybatis是經過文本替換組裝生成SQL語句的,因此不難發現它的插入和更新一樣是靜態的,對象裏是null的插入也是null。你數據庫的默認值不起做用而是獲得null,那怎麼解決這個問題呢?sql

XML<sql id="userColumn">
        <trim suffixOverrides=",">
            <if test="id!=null">id,</if>
            <if test="phone!=null">phone,</if>
            <if test="email!=null">email,</if>
            <if test="photo!=null">photo,</if>
        </trim>
</sql>

<sql id="userValue">
        <trim suffixOverrides=",">
            <if test="id!=null">#{id},</if>
            <if test="phone!=null">#{phone},</if>
            <if test="email!=null">#{email},</if>
            <if test="photo!=null">#{photo},</if>
        </trim>
</sql>

<insert id="insert" parameterType="User" useGeneratedKeys="true" keyProperty="id">
        insert into user (<include refid="userColumn" />)
        values (<include refid="userValue"></include>)
</insert>

經過使用include和sql標籤咱們解決了這個問題。數據庫

Mybatis typeHandler

有時候咱們經常想將Collection或者其餘對象直接以Json字符串的形式存在數據庫裏而不是再開一張表,雖然廣泛的觀點是不贊同這種作法,但這種需求倒是實際存在的。怎麼才能在DAO中就將字符串和對象的轉換作掉而不用交給上層顯式地轉換呢?json

採用自定義的Typehandler就能夠,下面給出一個例子mybatis

java@MappedJdbcTypes(JdbcType.VARCHAR)
public class JSONHandler implements TypeHandler<Object> {

    /**
      * json數據和類名的分隔符號
      * */
     private static final char SPLIT = '/'; 


     /**
      * json 轉換成對象
      * */
     private Object jsonToObject(String json) throws RuntimeException{
        if (json == null) {
            return null;
        }
        int index = json.lastIndexOf(SPLIT);
        if (index < 0) {
            return null;
        }
        String key = json.substring(index + 1, json.length());
        json = json.substring(0, index);
        Class<?> cls = null;
        try {
            cls = Class.forName(key);
        } catch (ClassNotFoundException e) {
            throw new RuntimeException("序列化成json時找不到指定的類", e);
        }
        Object ob = JSON.parseObject(json, cls);
        return ob;
    }

    public void setParameter(PreparedStatement ps, int i, Object parameter, JdbcType jdbcType) throws SQLException {
        if(parameter == null){
             ps.setString(i, null);
             return;
        }
            String json = JSON.toJSONString(parameter);
            json  = json + SPLIT + parameter.getClass().getName();
            ps.setString(i, json);

    }

    public Object getResult(ResultSet rs, String columnName) throws SQLException {
        String  json = rs.getString(columnName);
        return  jsonToObject(json);
    }

    public Object getResult(ResultSet rs, int columnIndex) throws SQLException {
        String json=rs.getString(columnIndex);
        return jsonToObject(json);
    }

    public Object getResult(CallableStatement cs, int columnIndex) throws SQLException {
        String  json = cs.getString(columnIndex);
        return  jsonToObject(json);
    }


}

首先設定處理的JDBCType,顯然是變長字符,而後實現給定的接口,最後在Mybatis的配置文件中加上這麼一句。app

XML
<typeHandlers> <typeHandler handler="sbeat.util.helper.JSONHandler" javaType="java.util.List"/> <typeHandler handler="sbeat.util.helper.JSONHandler" javaType="java.util.Map"/> </typeHandlers>

將Map和List均交由該handler處理,但本人實測,這個好像並無什麼卵用,有用的是在Mapper.xml文件中顯式指定,以下所示。

XML<insert>
insert (tags) values (#{tags,typeHandler=sbeat.util.helper.JSONHandler})
</insert>
<resultMap type="Employee" id="employeeResult">
    <result property="tags" column="tags" javaType="java.util.List"  typeHandler="sbeat.util.helper.JSONHandler"/>
</resultMap>

Mybatis 外鍵查詢

外鍵查詢須要使用resultMap的association標籤,以下所示

XML<resultMap type="Message" id="msgResultMap">
        <id property="id" column="id" />
        <result property="created" column="created" />
        <result property="title" column="title" />
        <result property="content" column="content" />
        <result property="has_read" column="has_read" />
        <result property="msgType" column="msgType" />
        <result property="receiverId" column="receiverId" />        
        <association property="sender" javaType="User">
            <id property="id" column="userId"/>
            <result property="name" column="name"/>
            <result property="phone" column="phone"/>
            <result property="passwd" column="passwd"/>
            <result property="photo" column="photo"/>
            <result property="email" column="email"/>
            <result property="userType" column="userType"/>
        </association>
    </resultMap>

Mybatis 多參數

在接口定義中使用@Params註解,並在XML中不定義paramType,以下所示

javapublic List<Feedback> findByTradeId(@Param("tradeId") Long tradeId,@Param("ownerType") UserType ownerType);
XML<select id="findByTradeId" resultType="Feedback">
        select * from feedback where tradeId=#{tradeId} 
        <if test="ownerType!=null">AND ownerType=#{ownerType}</if>
        ORDER BY created DESC
    </select>

Mybatis 逗號問題

逗號的不注意每每是使用Mybatis中出現最多的失誤,能夠經過使用where和set一級trim標籤來儘可能避免,以下所示:

XML<trim suffixOverrides=",">
    <if test="id!=null">id,</if>
    <if test="phone!=null">phone,</if>
</trim>
<set>
    <if test="phone!=null">phone=#{phone},</if>
    <if test="name!=null">name=#{name},</if>
</set>
<where>
    <if test="id!=null">id=#{id}</if>
    <choose>
        <when test="logic_delete!=null">AND logic_delete=#{logic_delete}</when>
        <otherwise>
            AND logic_delete=false
        </otherwise>
    </choose>
    <if test="name!=null"> AND name=#{name}</if>
</where>
相關文章
相關標籤/搜索