動態SQL就是經過傳入的參數不同,能夠組成不一樣結構的SQL語句。 這種能夠根據參數的條件而改變SQL結構的SQL語句,咱們稱爲動態SQL語句。使用動態SQL能夠提升代碼重用性。java
<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>調用 [通常不建議用]mysql
不建議的緣由,會致使代碼難以維護。git
條件查詢:(where)github
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)sql
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 )數據庫
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)apache
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>的使用:數組
<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>
動態sql除了支持xml方式之外,仍是支持使用純註解的方式
主要一下四個註解+對應動態sql語句的類文件緩存
1.@SelectProvider 動態查詢SQL語句對應註解
2.@InsertProvider 動態插入SQL語句對應註解
3.@UpdateProvider 動態修改SQL語句對應註解
4.@DeleteProvider 動態刪除SQL語句對應註解mybatis
示例:
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(); } }
在Mybatis裏面,所謂的緩存就是將已經查詢過的記錄放在內存的緩衝區或文件上,這樣若是再次查詢,能夠經過配置的策略,命中已經查詢過的記錄.從而提升查詢的效率。
Mybatis的緩存分爲一級緩存和二級緩存
所謂的一級緩存就是會話(SqlSesion對象)級別的緩存,就是同一個會話,若是已經查詢過的數據會保存一份在內存中,若是會話沒有關閉,再次調用一樣的方法查詢,不會再查詢數據庫,而是直接從緩存中取出以前查詢的數據。一級緩存默認是打開的,並且是關閉不了的。
如下幾種狀況一級緩存會被清空:
1.關閉會話.close()
2.進行了操做(增刪改),提交了commit();
3.手工清除緩存clearCache()
二級緩存是 SqlSessionFactory級別,在整個應用都有效,能夠在多個會話有效
MyBatis自己並無實現二級緩存,二級緩存須要第三方緩存提供商的支持
Ehcache:
下載地址:https://github.com/mybatis/ehcache-cache/releases
學習地址:http://www.mybatis.org/ehcache-cache/
在實際開發中,一個業務可能涉及到多個數據表的查詢,那麼多表查詢就涉及鏈接查詢(等值鏈接), 等值鏈接 表與表之間有一個外鍵關鍵。
可是程序中最終獲取的表封裝的對象, 對象與對象之間是沒有外鍵關係的,對象和對象之間只有依賴關係
對象之間關係主要是四種(什麼關係應該看從哪一個對象的角度)
一對一 關係
一我的對應身份證號
一對多 關係
一個部門對應多個員工
多對一 關係
多個員工對應一個部門
多對多 關係
多個學生對應多個老師,多個學生對應多個課程
MyBatis框架支持多表查詢封裝對象之間關係:
<collection>標籤: 一對多查詢
<association>標籤:多對一和一對一查詢
注:<collection>和<association>爲<resultMap>的子標籤
例:以員工爲中心來查詢關聯部門(多對一關係,多個員工對應一個部門)
數據庫表
員工表 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>
例:以部門爲中心查詢部門的全部信息(包括員工),一個部門對應多個員工
部門類
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>
以上都是用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>
MyBatis的逆向工程能自動幫開發者生成數據庫表對應的 pojo實體文件,自動生成映射文件
自定生成表的各類(CRUD)的sql語句, 可是隻能作單表操做,聯合查詢還得開發者本身編寫
使用逆向工程得先在Eclipse安裝逆向工程的插件
判斷是否安裝成功
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>
主要是數據庫四要素、實體類、映射文件、操做接口的配置視狀況進行修改
選中generatorConfig.xml文件右擊運行
逆向功能不能逆向多表操做,只能逆向單表操做,多表之間有外鍵對應java關聯關係沒辦法映射,須要開發者手動編寫對應代碼。