Java 持久層框架之 MyBatis

MyBatis 簡介

MyBatis 是一個基於 Java 的持久層框架,它內部封裝了 JDBC,使開發者只需關注 SQL 語句本身,而不用再花費精力去處理諸如註冊驅動、創建 Connection、配置 Statement 等繁雜過程。

Mybatis 通過 xml 或註解的方式將要執行的各種 StatementPreparedStatement 等配置起來,並通過 Java 對象和 StatementSQL 的動態參數進行映射生成最終執行的 SQL 語句,最後由 MyBatis 框架執行 SQL 並將結果映射成 Java 對象並返回。

MyBatis 與 Hibernate

Hibernate 框架是提供了全面的數據庫封裝機制的 全自動 ORM,即實現了 POJO 和數據庫表之間的映射,以及 SQL 的自動生成和執行。

相對於此,MyBatis 只能算作是 半自動 ORM。其着力點,是在 POJO 類與 SQL 語句之間的映射關係。也就是說,MyBatis 並不會爲程序員自動生成 SQL 語句。具體的 SQL 需要程序員自己編寫,然後通過 SQL 語句映射文件,將 SQL 所需的參數,以及返回的結果字段映射到指定 POJO。

MyBatis 特點

  • XML 文件中配置 SQL 語句,實現了 SQL 語句與代碼的分離,給程序的維護帶來了很大便利。
  • 可以結合數據庫自身的特點靈活控制 SQL 語句,因此能夠實現比 Hibernate 等全自動 ORM 框架更高的查詢效率,能夠完成複雜查詢。

file

Spring 整合 Mybatis

引入依賴

pom.xml 引入 Mybatis 相關依賴。

<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.2.8</version>
</dependency>
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis-spring</artifactId>
    <version>1.3.1</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>4.3.17.RELEASE</version>
</dependency>

創建 Mybatis 配置文件

resource 目錄下創建 mybatis-config 配置文件。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <!-- 全局參數 -->
    <settings>
        <!-- 打印 SQL 語句 -->
        <setting name="logImpl" value="STDOUT_LOGGING" />

        <!-- 使全局的映射器啓用或禁用緩存。 -->
        <setting name="cacheEnabled" value="false"/>

        <!-- 全局啓用或禁用延遲加載。當禁用時,所有關聯對象都會即時加載。 -->
        <setting name="lazyLoadingEnabled" value="true"/>

        <!-- 當啓用時,有延遲加載屬性的對象在被調用時將會完全加載任意屬性。否則,每種屬性將會按需要加載。 -->
        <setting name="aggressiveLazyLoading" value="true"/>

        <!-- 是否允許單條 SQL 返回多個數據集 (取決於驅動的兼容性) default:true -->
        <setting name="multipleResultSetsEnabled" value="true"/>

        <!-- 是否可以使用列的別名 (取決於驅動的兼容性) default:true -->
        <setting name="useColumnLabel" value="true"/>

        <!-- 允許 JDBC 生成主鍵。需要驅動器支持。如果設爲了 true,這個設置將強制使用被生成的主鍵,有一些驅動器不兼容不過仍然可以執行。 default:false  -->
        <setting name="useGeneratedKeys" value="false"/>

        <!-- 指定 MyBatis 如何自動映射 數據基表的列 NONE:不映射 PARTIAL:部分 FULL:全部  -->
        <setting name="autoMappingBehavior" value="PARTIAL"/>

        <!-- 這是默認的執行類型 (SIMPLE: 簡單; REUSE: 執行器可能重複使用prepared statements語句;BATCH: 執行器可以重複執行語句和批量更新) -->
        <setting name="defaultExecutorType" value="SIMPLE"/>

        <!-- 使用駝峯命名法轉換字段。 -->
        <setting name="mapUnderscoreToCamelCase" value="true"/>

        <!-- 設置本地緩存範圍 session:就會有數據的共享 statement:語句範圍 (這樣就不會有數據的共享 ) defalut:session -->
        <setting name="localCacheScope" value="SESSION"/>

        <!-- 設置 JDBC 類型爲空時,某些驅動程序 要指定值, default:OTHER,插入空值時不需要指定類型 -->
        <setting name="jdbcTypeForNull" value="NULL"/>
    </settings>
</configuration>

創建集成配置文件

resource 目錄下創建一個 spring-context-mybatis.xml 的集成配置文件。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">

    <!-- 配置 SqlSession -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <!-- 用於配置對應實體類所在的包,多個 package 之間可以用 ',' 號分割 -->
        <property name="typeAliasesPackage" value="com.antoniopeng.ssm.domain"/>
        <!-- 用於配置對象關係映射-->
        <property name="mapperLocations" value="classpath:/mapper/**/*.xml"/>
                <!-- -用於配置文件所在目錄->
        <property name="configLocation" value="classpath:/mybatis-config.xml"></property>
    </bean>

    <!-- 掃描 Mapper -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.antoniopeng.ssm.dao" />
    </bean>
</beans>

CRUD 案例

新增

<insert id="insert">
    INSERT INTO tb_user (
      id,
      username,
      password,
      phone,
      email,
      created,
      updated
    )
    VALUES
      (
        #{id},
        #{username},
        #{password},
        #{phone},
        #{email},
        #{created},
        #{update}
      )
</insert>

刪除

<delete id="delete">
    DELETE FROM tb_user WHERE id = #{id}
</delete>

查詢

<select id="getById" resultType="TbUser">
    SELECT
      a.id,
      a.username,
      a.password,
      a.phone,
      a.email,
      a.created,
      a.updated AS "update"
    FROM
      tb_user AS a
    WHERE
      a.id = #{id}
</select>

更新

<update id="update">
    UPDATE
      tb_user
    SET
      username = #{username},
      password = #{password},
      phone = #{phone},
      email = #{email},
      created = #{created},
      updated = #{update}
    WHERE id = #{id}
</update>

MyBatis 動態 SQL

動態 SQL 主要用於解決查詢條件不確定的情況:在程序運行期間,根據用戶提交的查詢條件進行查詢。提交的查詢條件不同,執行的 SQL 語句不同。若將每種可能的情況均逐一列出,對所有條件進行排列組合,將會出現大量的 SQL 語句。此時,可使用動態 SQL 來解決這樣的問題。這裏的條件判斷使用的表達式爲 OGNL 表達式。常用的動態 SQL 標籤有 &lt;if&gt;&lt;where&gt;&lt;choose&gt;&lt;foreach&gt; 等。

注意:在 mapper 的動態 SQL 中若出現 &gt;&lt;&gt;=&lt;= 等符號,最好將其轉換爲實體符號。否則,XML 可能會出現解析出錯問題,特別是 &lt; 在 XML 中是絕對不能出現的。

if 標籤

對於該標籤的執行,當 test 的值爲 true 時,會將其包含的 SQL 片斷拼接到其所在的 SQL 語句中。
案例
爲了解決兩個條件均未做設定的情況,在 where 後添加了一個“1=1”的條件。這樣就不至於兩個條件均未設定而出現只剩下一個 where,而沒有任何可拼接的條件的不完整 SQL 語句。

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.antoniopeng.ssm.dao.StudentDao">
    <!-- if -->
    <select id="selectByIf" resultType="com.antoniopeng.ssm.entity.Student">
        SELECT 
                    *
        FROM
            student
        WHERE 1 = 1
        <if test="name != null and name != ''">
            AND name LIKE concat('%', #{name}, '%')
        </if>
        <if test="age != null and age > 0">
            AND age > #{age}
        </if>
    </select>
</mapper>

where 標籤

<if/> 標籤的中存在一個比較麻煩的地方:需要在 where 後手工添加 1=1 的子句。因爲,若 where 後的所有 <if/> 條件均爲 false,而 where 後若又沒有 1=1 子句,則 SQL 中就會只剩下一個空的 where,SQL 出錯。所以,在 where 後,需要添加永爲真子句 1=1,以防止這種情況的發生。但當數據量很大時,會嚴重影響查詢效率。
案例

<select id="selectByWhere" resultType="com.antoniopeng.ssm.entity.Student">
    SELECT
            *
    FROM
      student
    <where>
        <if test="name != null and name != ''">
            AND name LIKE concat('%', #{name}, '%')
        </if>
        <if test="age != null and age > 0">
            AND age > #{age}
        </if>
    </where>
</select>

choose 標籤

該標籤中只可以包含 &lt;when/&gt;&lt;otherwise/&gt;,可以包含多個 &lt;when/&gt; 與一個 &lt;otherwise/&gt;。它們聯合使用,完成 Java 中的開關語句 switch case 功能。
案例
本例要完成的需求是,若姓名不空,則按照姓名查詢;若姓名爲空,則按照年齡查詢;若沒有查詢條件,則沒有查詢結果。

<!-- choose -->
<select id="selectByChoose" resultType="com.antoniopeng.ssm.entity.Student">
    SELECT
        *
    FROM
      student
    <where>
        <choose>
            <when test="name != null and name != ''">
                AND name LIKE concat('%', #{name}, '%')
            </when>
            <when test="age != null and age > 0">
                AND age > #{age}
            </when>
            <otherwise>
                AND 1 != 1
            </otherwise>
        </choose>
    </where>
</select>

foreach 標籤

該標籤用於實現對於數組與集合的遍歷。對其使用,需要注意:collection 表示要遍歷的集合類型,這裏是數組,即 array。opencloseseparator 爲對遍歷內容的 SQL 拼接。
遍歷數組案例

<!-- foreach -->
<select id="selectByForeach" resultType="com.antoniopeng.ssm.entity.Student">
    SELECT
        *
    FROM
      student
    <if test="array != null and array.length > 0">
        WHERE id IN
        <foreach collection="array" open="(" close=")" item="id" separator=",">
            #{id}
        </foreach>
    </if>
</select>

遍歷泛型爲基本類型的集合案例

/**
 * 使用 foreach 標籤以 list 基本類型的形式查詢
 * @param ids
 * @return
 */
public List<Student> selectByForeachWithListBase(List<Long> ids);
<!-- foreach -->
<select id="selectByForeachWithListBase" resultType="com.antoniopeng.ssm.entity.Student">
    SELECT
        *
    FROM
      student
    <if test="list != null and list.size > 0">
        WHERE id IN
        <foreach collection="list" open="(" close=")" item="id" separator=",">
            #{id}
        </foreach>
    </if>
</select>

遍歷泛型爲自定義類型的集合案例

/**
 * 使用 foreach 標籤以 list 自定義類型的形式查詢
 * @param students
 * @return
 */
public List<Student> selectByForeachWithListCustom(List<Student> students);
<!-- foreach -->
<select id="selectByForeachWithListCustom" resultType="com.antoniopeng.ssm.entity.Student">
    SELECT
            *
    FROM
      student
    <if test="list != null and list.size > 0">
        WHERE id IN
        <foreach collection="list" open="(" close=")" item="student" separator=",">
            #{student.id}
        </foreach>
    </if>
</select>

sql 標籤

該標籤用於定義 SQL 片斷,以便其它 SQL 標籤複用。而其它標籤使用該 SQL 片斷, 需要使用 &lt;include/&gt; 子標籤。該標籤可以定義 SQL 語句中的任何部分,所以 &lt;include/&gt; 子標籤可以放在動態 SQL 的任何位置。
案例

<sql id="select">
    SELECT
        id,
        name,
        age,
        score
    FROM
      student
</sql>

使用 sql 標籤

<!-- foreach -->
<select id="selectByForeachWithListCustom" resultType="com.antoniopeng.ssm.entity.Student">
    <include refid="select" />
</select>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章