深刻學習Mybatis框架(二)- 進階

1.動態SQL

1.1 什麼是動態SQL?

  動態SQL就是經過傳入的參數不同,能夠組成不一樣結構的SQL語句。 這種能夠根據參數的條件而改變SQL結構的SQL語句,咱們稱爲動態SQL語句。使用動態SQL能夠提升代碼重用性。html

1.2 XML方式的實現

  1.2.1 須要使用到的標籤

<if> 用於判斷,相似java的if(){}
<foreach>通常用戶批量處理的SQL語句,相似java的foreach循環,
<trim> :切割標籤,主要用於切割關鍵字的頭和尾的字符.新版的Mybatis使用的概率不多.
<set>:使用 set標籤就是SQL語言的set關鍵字,能夠在update 的時候set 關鍵字後面的,逗號能夠自動忽略
<where>:使用where標籤做爲SQL語言的where關鍵字,好處若是where後面的條件都不成立,忽略where關鍵字.
<choose> <when> <otherwise> : java的swithc case
<sql> 用於聲明公有的SQL語句塊.,在操做標籤中使用<include>調用 [通常不建議用]java

不建議的緣由,會致使代碼難以維護。mysql

  1.2.2 使用示例

  條件查詢:(where)git

public List<User> selectByCondition(User user);
<!-- 條件查詢 -->
    <select id="selectByCondition" parameterType="com.gjs.pojo.User" resultType="com.gjs.pojo.User">
        select * from user <where>
            <!-- if標籤:條件判斷標籤 -->
            <if test="name!=null"> name = #{name} <!--或者使用模糊查詢: name like concat('%',#{name},'%') -->
            </if>
            <if test="age != null"> and age = #{age} </if>
        </where>
</select>

 

  修改:(set)github

public int updateByNotNull(User user);
<update id="updateByNotNull" parameterType="com.gjs.pojo.User"> update user <!-- set -->
        <set>
            <if test="name != null">name=#{name},</if>
            <if test="password != null">password=#{password},</if>
            <if test="age != null">age=#{age}</if>
        </set>
         where id=#{id} </update>

 

  根據條件統計個數(trim )sql

public Long selectTotalByCondition(User user);
<!-- 動態SQL語句trim標籤 perfix : 動態sql語句的前綴 (WHERE,SET) prefixOverrides : 自動截取掉或者替換條(WHERE 多餘後面 關鍵字 :AND-OR) -->
    <select id="selectTotalByCondition" parameterType="com.gjs.pojo.User" resultType="long" > select count(*) from user <trim prefix="WHERE" prefixOverrides="AND|OR">
            <if test="name!=null"> name like concat('%',#{name},'%') </if>
            <if test="age != null"> and age = #{age} </if>
        </trim>
    </select>
 <!-- set操做: <trim prefix="SET" suffixOverrides=","> -->

 

  批量刪除:(foreach)數據庫

public int deleteByIds(@Param("ids")List<Integer> ids);
<delete id="deleteByIds" parameterType="Integer"> delete from user where id in <!-- 動態sql語句 foreach 循環標籤 <foreach collection="" open="" close="" item="" separator=""></foreach> collection : 要循環集合或者數組 open :開始位置符號 前小括號 ( close : 開始位置符號 後小括號 ) item : 每次循環的數據 separator : 分隔符 逗號 , -->
          <foreach collection="ids" open="(" close=")" item="id" separator=","> #{id} </foreach>
    </delete>

<sql>的使用:apache

<sql id="condition_sql">
          <where>
              <if test="name !=null">
                  <!-- name like '%${name}%' --> name like concat('%',#{name},'%') </if>
            <if test="age !=null"> and age = #{age} </if>          
          </where>
    </sql>
 
     <select id="selectByCondition" parameterType="com.gjs.pojo.User" resultType="com.gjs.pojo.User"> select * from user <!-- 引入sql片斷.  refid :被引入sql片斷的id -->
          <include refid="condition_sql_by_trim"/
      </select>

 

1.3 註解方式實現

動態sql除了支持xml方式之外,仍是支持使用純註解的方式
主要一下四個註解+對應動態sql語句的類文件數組

1.@SelectProvider 動態查詢SQL語句對應註解
2.@InsertProvider 動態插入SQL語句對應註解
3.@UpdateProvider 動態修改SQL語句對應註解
4.@DeleteProvider 動態刪除SQL語句對應註解緩存

  

示例:
Usermapper

package com.gjs.mapper; import java.util.List; import org.apache.ibatis.annotations.DeleteProvider; import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.SelectProvider; import org.apache.ibatis.annotations.UpdateProvider; import com.gjs.pojo.User; import com.gjs.pojo.UserProvider; public interface UserMapper { /* * 條件查詢 * type : 編寫動態sql語句的類對應的字節碼 * method : 編寫動態sql語句類對應的方法名稱 * 此方法返回的是一個String字符串,字符串就是用於註解方法查詢的sql語句 */ @SelectProvider(type= UserProvider.class,method="selectByCondition") public List<User> selectByCondition(User user); //根據條件統計總數
    @SelectProvider(type= UserProvider.class,method="selectTotalByCondition") public Long selectTotalByCondition(User user); //修改
    @UpdateProvider(type= UserProvider.class,method="updateByNotNull") public int updateByNotNull(User user); //批量刪除
    @DeleteProvider(type=UserProvider.class,method="deleteByIds") public int deleteByIds(@Param("ids")List<Integer> ids); }

  UserProvider
  構建方法參數規則:
    1.非數組、集合的參數,調用方法是什麼,構建SQL語句的方法就是什麼
    2.是數組、集合的參數,構建的方法須要包一層Map。如:調用方法爲:String[] ids ,構建方法格式爲Map<String,String[]> ids

package com.gjs.pojo; import java.util.List; import org.apache.ibatis.annotations.Param; public class UserProvider { public String selectByCondition(User user) { StringBuilder sb = new StringBuilder(); sb.append("select * from user where 1=1 "); if(user.getName()!=null) { //因爲最後字符串仍是返回給Mybatis執行的全部這裏須要使用OGNL表達式來獲取對象屬性的值
            sb.append("and name like concat('%',#{name},'%') "); } if(user.getAge()!=null) { sb.append("and age = #{age}"); } return sb.toString(); } public String selectTotalByCondition(User user) { StringBuilder sb = new StringBuilder(); sb.append("select count(1) from user where 1=1 "); if(user.getName()!=null) { sb.append("and name like concat('%',#{name},'%') "); } if(user.getAge()!=null) { sb.append("and age = #{age}"); } return sb.toString(); } public String updateByNotNull(User user) { StringBuilder sb = new StringBuilder(); sb.append("update user set "); if(user.getName()!=null) { sb.append("name = #{name},"); }if(user.getPassword()!=null) { sb.append("password = #{password},"); }if(user.getAge()!=null) { sb.append("age = #{age},"); } sb.deleteCharAt(sb.length()-1);//刪除末尾多餘的逗號","
        sb.append("where id = #{id}"); return sb.toString(); } public String deleteByIds(@Param("ids")List<Integer> ids) { StringBuilder sb = new StringBuilder(); sb.append("delete from user where id in("); for (int i = 0; i < ids.size(); i++) { sb.append("#{ids["+i+"]},"); } sb.deleteCharAt(sb.length()-1);//刪除末尾多餘的逗號","
        sb.append(")"); return sb.toString(); } }

2.緩存

  在Mybatis裏面,所謂的緩存就是將已經查詢過的記錄放在內存的緩衝區或文件上,這樣若是再次查詢,能夠經過配置的策略,命中已經查詢過的記錄.從而提升查詢的效率。
Mybatis的緩存分爲一級緩存和二級緩存

  2.1 一級緩存

   所謂的一級緩存就是會話(SqlSesion對象)級別的緩存,就是同一個會話,若是已經查詢過的數據會保存一份在內存中,若是會話沒有關閉,再次調用一樣的方法查詢,不會再查詢數據庫,而是直接從緩存中取出以前查詢的數據。一級緩存默認是打開的,並且是關閉不了的。
  如下幾種狀況一級緩存會被清空:
    1.關閉會話.close()
    2.進行了操做(增刪改),提交了commit();
    3.手工清除緩存clearCache()

  2.2 二級緩存

二級緩存是 SqlSessionFactory級別,在整個應用都有效,能夠在多個會話有效
MyBatis自己並無實現二級緩存,二級緩存須要第三方緩存提供商的支持
Ehcache:
下載地址:https://github.com/mybatis/ehcache-cache/releases
學習地址:http://www.mybatis.org/ehcache-cache/

 

3.MyBatis的對象關係映射

  在實際開發中,一個業務可能涉及到多個數據表的查詢,那麼多表查詢就涉及鏈接查詢(等值鏈接), 等值鏈接 表與表之間有一個外鍵關鍵。
  可是程序中最終獲取的表封裝的對象, 對象與對象之間是沒有外鍵關係的,對象和對象之間只有依賴關係

  對象之間關係主要是四種(什麼關係應該看從哪一個對象的角度)

一對一 關係
  一我的對應身份證號
一對多 關係
  一個部門對應多個員工
多對一 關係
  多個員工對應一個部門
多對多 關係
  多個學生對應多個老師,多個學生對應多個課程

  MyBatis框架支持多表查詢封裝對象之間關係:
    <collection>標籤: 一對多查詢
    <association>標籤:多對一和一對一查詢
  注:<collection>和<association>爲<resultMap>的子標籤

 

3.1 多對一查詢(<association>聯合查詢標籤)(N+1)

  例:以員工爲中心來查詢關聯部門(多對一關係,多個員工對應一個部門)

 

 數據庫表

員工表 CREATE TABLE `employee` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(50) DEFAULT NULL, `dept_id` int(11) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8; 部門表 CREATE TABLE `department` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;

部門類

package com.gjs.pojo; public class Department { private Integer id; private String name; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Department(Integer id, String name) { super(); this.id = id; this.name = name; } public Department() { super(); } @Override public String toString() { return "Department [id=" + id + ", name=" + name + "]"; } }

員工類(Employee)

package com.gjs.pojo; public class Employee { private Integer id; private String name; //以員工爲中心來關聯部門,多對一關係,多個員工對應一個部門 : many2one
    private Department dept; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Department getDept() { return dept; } public void setDept(Department dept) { this.dept = dept; } @Override public String toString() { return "Employee [id=" + id + ", name=" + name + ", dept=" + dept + "]"; } }

接口

package com.gjs.mapper; import com.gjs.pojo.Employee; public interface Many2OneMapper { /** * 根據與員工的編碼查詢出員工對應的全部信息(包含部門) * @param id * @return
     */
    public Employee selectByEmpId(Integer id); }

 接口映射配置文件

<?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">
<!-- 配置映射 namespace : 命名空間(通俗說法: 給當前映射文件的惟一標識:起一個惟一的名字) -->
<mapper namespace="com.gjs.mapper.Many2OneMapper">
    
    <!-- 因爲查詢出來的結果於com.gjs.pojo.Employee中的屬性不一致(Department dept),因此不能自動映射 -->
    <select id="selectByEmpId" resultMap="emp_map" parameterType="int">
        select * from employee where id = #{id} </select>
    
    <resultMap type="com.gjs.pojo.Employee" id="emp_map">
        <id property="id" column="id"/>
        <result property="name" column="name"/>
        <!-- 問題:private Department dept; 對象如何映射? 解決方案: 使用聯合查詢標籤 <association property="" column="" select=""></association> property : 須要映射額屬性 dept column : 已知的部門外檢列 dept_id select : 調用查詢經過部門id查詢出對應部門對象的功能的id 值規則 : 映射文件的命名空間 + 點兒(.) + 功能id 若是是在同一個命名空間,能夠省略命名空間和點 -->
        <association property="dept" column="dept_id" select="selectByDeptId"/>
    </resultMap>
    
    <select id="selectByDeptId" parameterType="int" resultType="com.gjs.pojo.Department">
        select * from department where id = #{id} </select>
</mapper>

 

3.2 多對一查詢(<collection>集合映射標籤)(N+1)

例:以部門爲中心查詢部門的全部信息(包括員工),一個部門對應多個員工
部門類

package com.gjs.pojo; import java.util.List; public class Department { private Integer id; private String name; //以部門爲中心查詢部門的全部信息(包含員工) //一個部門有多個員工 一對多關係:one2many // 部門的元員工使用 list集合包裝
    private List<Employee> emps; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public List<Employee> getEmps() { return emps; } public void setEmps(List<Employee> emps) { this.emps = emps; } public Department(Integer id, String name) { super(); this.id = id; this.name = name; } public Department() { super(); } @Override public String toString() { return "Department [id=" + id + ", name=" + name + ", emps=" + emps + "]"; } }

員工類

package com.gjs.pojo; public class Employee { private Integer id; private String name; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Employee [id=" + id + ", name=" + name + "]"; } }

接口

package com.gjs.mapper; import com.gjs.pojo.Department; public interface One2ManyMapper { /** * 根據與部門的編碼查詢出部門對應的全部信息(包含全部員工) * @param id * @return */
    public Department selectByDeptId(Integer id); }

接口對應的映射配置文件

<?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">
<!-- 配置映射 namespace : 命名空間(通俗說法: 給當前映射文件的惟一標識:起一個惟一的名字) -->
<mapper namespace="com.gjs.mapper.One2ManyMapper">
    
    <select id="selectByDeptId" parameterType="int" resultMap="dept_map">
        select * from department where id = #{id} </select>
    
    <resultMap type="com.gjs.pojo.Department" id="dept_map">
        <id property="id" column="id"/>
        <result property="name" column="name"/>
        <!-- 問題 :List<Employee> emps; 集合如何映射? 解決方案: 使用 <collection>集合映射 <collection property="" column="" select=""/> property :須要映射的屬性 emps 對應的list集合 column : 部門自己的主鍵 id select : 關聯查詢的功能id 規則 : 命名空間+點+功能id。 若是同一個命名空間下面直接 功能id便可 -->
        <collection property="emps" column="id" select="selectEmpsByDeptId"/>
    </resultMap>
    
    <select id="selectEmpsByDeptId" resultType="com.gjs.pojo.Employee" parameterType="int">
        select * from employee where id = #{dept_id} </select>
</mapper>

3.3 等值鏈接方式查詢

  以上都是用N+1的方式。MyBatis的對象關係映射還有一種等值鏈接方式。
  以一對多爲例:


pojo類和接口皆與3.2的相同

映射配置文件:

<?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">
<!-- 配置映射 namespace : 命名空間(通俗說法: 給當前映射文件的惟一標識:起一個惟一的名字) -->
<mapper namespace="com.gjs.mapper.One2ManyMapper">
    
    <select id="selectByDeptId" parameterType="int" resultMap="dept_map">
        select e.id e_id ,e.name e_name,d.id d_id,d.name d_name from department d JOIN employee e ON d.id = e.dept_id WHERE d.id = #{id}; </select>
    
    <resultMap type="com.gjs.pojo.Department" id="dept_map">
        <id property="id" column="d_id"/>
        <result property="name" column="d_name"/>
        <!--
             <collection property="emps" ofType=""> 在標籤內部屬性進行手動映射 </collection> property : 要映射的屬性 ofType: 要映射集合泛型的類型 -->
        <collection property="emps" ofType="com.gjs.pojo.Employee">
            <id property="id" column="e_id"/>
            <result property="name" column="e_name"/>
        </collection>
    </resultMap>
</mapper>

4.MyBatis的逆向工程

  MyBatis的逆向工程能自動幫開發者生成數據庫表對應的 pojo實體文件,自動生成映射文件
  自定生成表的各類(CRUD)的sql語句, 可是隻能作單表操做,聯合查詢還得開發者本身編寫

  4.1逆向工程的插件安裝步驟

    使用逆向工程得先在Eclipse安裝逆向工程的插件

   

  

  

 

   

  判斷是否安裝成功

  

  4.2 逆向工程建立步驟

    4.2.1.新建一個項目,導入mybatis.jar包和數據庫驅動包

    4.2.2 建立生成配置文件

  generatorConfig.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN" "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
  <context id="context1">
   <!-- 註釋構建 -->
    <commentGenerator>
       <!-- 去掉全部的註釋 -->
        <property name="suppressAllComments" value="true"/>
        <property name="suppressDate" value="true"/>
    </commentGenerator>
    
    <!-- 數據庫四要素 -->
    <jdbcConnection connectionURL="jdbc:mysql://localhost:3306/mybatis" driverClass="com.mysql.jdbc.Driver" userId="root" password="1234"/>
    <!-- 實體類 : pojo targetPackage : 實體類生成後存放的包 targetProject : 存放的目錄通常都放在 src下面 -->
    <javaModelGenerator targetPackage="com.gjs.pojo" targetProject="mybatis-generator/src" />
    <!-- 映射文件 -->
    <sqlMapGenerator targetPackage="com.gjs.mapper" targetProject="mybatis-generator/src" />
    <!-- 操做接口 type 生成映射的形式 ANNOTATEDMAPPER : 純註解的,沒有xml映射 XMLMAPPER : 生成的有xml映射文件 -->
    <javaClientGenerator  targetPackage="com.gjs.mapper" targetProject="mybatis-generator/src" type="XMLMAPPER" />
    
    <!-- 要生成對應表的配置 tableName : 數據庫表名 //若是下面所有是true,mybatis直接可使用純面向對象開發
 enableCountByExample : 是否生成查詢總數的 Example enableDeleteByExample : 是否生成刪除的 Example enableSelectByExample : 是否生成查詢集合的 Example enableUpdateByExample : 是否生成修改的 Example -->
    <table  tableName="user"  enableCountByExample="false" enableDeleteByExample="false" enableSelectByExample="true" enableUpdateByExample="false"></table>
    <table  tableName="employee" enableCountByExample="false" enableDeleteByExample="false" enableSelectByExample="true" enableUpdateByExample="false"></table>
    <table  tableName="department" enableCountByExample="false" enableDeleteByExample="false" enableSelectByExample="true" enableUpdateByExample="false"></table>
  </context>
</generatorConfiguration>

主要是數據庫四要素、實體類、映射文件、操做接口的配置視狀況進行修改

    4.2.3 開始逆向工程

  選中generatorConfig.xml文件右擊運行

  

  4.3.逆向功能的缺點

  逆向功能不能逆向多表操做,只能逆向單表操做,多表之間有外鍵對應java關聯關係沒辦法映射,須要開發者手動編寫對應代碼。

原文出處:https://www.cnblogs.com/gaojinshun/p/11145826.html

相關文章
相關標籤/搜索