一、映射文件
1.簡單的增刪改(需要commit)---查
MyBatis允許增刪改直接定義以下類型返回值
Integer、Long、Boolean、void
我們需要手動提交數據。
sqlSessionFactory.openSession();===>需要手動提交
sqlSessionFactory.openSession(true);===>自動提交
2.獲取insert-自增的主鍵
JDBC中Statement的方法:getGeneratedKeys();--->獲取由於執行此Statement對象而創建的所有自動生成的鍵。
<!--自增主鍵的值 獲取 mysql支持自增主鍵,自增主鍵值的獲取,mybatis也是利用statement.getGeneratedKeys(); useGeneratedKeys="true":使用自增主鍵獲取主鍵值策略 keyProperty:指定對應的主鍵屬性,也就是mybatis獲取到主鍵值之后,將這個值封裝給JavaBean的哪個屬性 --> <insert id="addEmp" parameterType="emp" useGeneratedKeys="true" keyProperty="id"> insert into tbl_employee(last_name,email,gender) values(#{lastName},#{email},#{gender}) </insert>
Oracle:自增的序列
~~ before:從序列中查主鍵的SQL在插入SQL之前執行
<!-- Oracle不支持自增;Oracle使用序列來模擬自增; 每次插入的數據的主鍵是從序列中拿到的值;如何獲取到這個值 --> <insert id="addEmp" databaseId="oracle" parameterType="emp"> /* keyProperty:查出的主鍵值封裝給Javabean的哪個屬性 order="BEFORE":當前SQL在插入SQL之前執行 resultType:查出數據的返回值類型 */ <selectKey keyProperty="id" order="BEFORE" resultType="Integer"> /*編寫查詢主鍵的SQL語句*/ select 序列名.nextval from dual </selectKey> /*插入時的主鍵是從序列中拿到的*/ insert into tbl_employee(id,last_name,email,gender) values (#{id},#{lastName},#{email},#{gender}) </insert>
~~after:
<!-- Oracle不支持自增;Oracle使用序列來模擬自增; 每次插入的數據的主鍵是從序列中拿到的值;如何獲取到這個值 --> <insert id="addEmp" databaseId="oracle" parameterType="emp"> /* keyProperty:查出的主鍵值封裝給Javabean的哪個屬性 order="AFTER":當前SQL在插入SQL之后執行 resultType:查出數據的返回值類型 */ <selectKey keyProperty="id" order="AFTER" resultType="Integer"> /*編寫查詢主鍵的SQL語句 獲取當前的序列值 */ select 序列名.currval from dual </selectKey> insert into tbl_employee(id,last_name,email,gender) values (序列名.nextval,#{lastName},#{email},#{gender}) </insert>
3.映射文件---參數處理(單個參數&多個參數)
單個參數:MyBatis不會做特殊處理。
#{參數名}:取出參數值,參數名可以任意寫。
多個參數:MyBatis會做特殊處理。
多個參數會被封裝成一份Map,
key:param1...paramN,或者參數的索引也可以
value:傳入的參數值
#{ }就是從Map中獲取指定的key的值;
public Employee getEmpByIdAndLastName(Integer id,String lastName);
<select id="getEmpByIdAndLastName" resultType="emp"> select * from tbl_employee where id = #{param1} and last_name = #{param2} </select>
命名參數:明確指定封裝參數值時map的key;@Param("id")
多個參數會被封裝成一個Map,
key:使用@Param注解指定的值
value:參數值
#{指定的key}:取出對應的參數值
public Employee getEmpByIdAndLastName(@Param("id") Integer id,@Param("lastName") String lastName);
<select id="getEmpByIdAndLastName" resultType="emp"> select * from tbl_employee where id = #{id} and last_name = #{lastName} </select>
4.映射文件---參數處理---POJO&TO
POJO:
如果多個參數正好是我們業務邏輯的數據模型,直接傳入POJO;
#{屬性名}:取出傳入的POJO的屬性值
Map:
如果多個參數不是業務模型中的數據,沒有對應的POJO,為了方便,我們也可以傳入Map;
#{key}:取出map中對應的值
public Employee getEmpByMap(Map<String,Object> map);
<select id="getEmpByMap" resultType="emp"> select * from tbl_employee where id=#{id} and last_name=#{lastName} </select>
SqlSession sqlSession = sqlSessionFactory.openSession(); EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class); Map<String,Object> map = new HashMap<String, Object>(); map.put("id",2); map.put("lastName","jesscia"); Employee jesscia = mapper.getEmpByMap(map); System.out.println(jesscia);
TO:
如果多個參數不是業務模型中的數據,但是經常要使用,推薦來編寫一個TO(Transfer Object)數據傳輸對象。
例如:分頁時的Page類。
5.映射文件---參數處理---參數封裝擴展思考
public Employee getEmp(@param("id")Integer id,String lastName);
取值:id===>#{id/param1} last_name===>#{param2}
public Employee getEmp((Integer id,@param("e")Employee emp);
取值:id===>#{param1} last_name===>#{param2.lastName/e,lastName}
##特別注意:如果是Collection(List、Set)類型或者是數組,也會特殊處理。也是把傳入的List或者數組封裝在map中。
key:Collection(collection),如果是List還可以使用這個key(list)
public Employee getEmpById(List<Integer> ids);
取值:取出第一個id值: #{list[0]}
===============可以結合MyBatis源碼,看怎樣處理參數。=============
6.映射文件===參數處理===#與$取值區別
#{ }:可以獲取map中的值或者POJO對象屬性的值;
${ }:可以獲取map中的值或者POJO對象屬性的值;
select * from tbl_employee where id=${id} and last_name=#{lastName}
Preparing: select * from tbl_employee where id=2 and last_name=?
區別:
#{ }:是以預編譯的形式,將參數設置到sql語句中;PreparedStatement;防止sql注入
${ }:取出的值直接拼接在sql語句中,會有安全問題;
大多數情況下,我們取參數的值都應該去使用#{ };
原生JDBC不支持占位符的地方我們就可以使用${ }進行取值;
比如分表、排序。。。:按照年份分表拆分
select * from ${year}_salary where xxx;
select * from tbl_employee order by ${f_name};按照什么排序
7.映射文件===參數處理===#取值時指定參數相關規則
#{ }:更豐富的用法;
規定參數的一些規則:
javaType、jdbcType、mode(存儲過程)、numericScale、
resultMap、typeHandler、jdbcTypeName、expression(未來准備支持的功能)
jdbcType通常需要在某種特定的條件下被設置:
在我們數據為null的時候,有些數據庫可能不能識別mybatis對null的處理。比如Oracle(報錯);
JdbcType OTHER:無效的類型;因為mybatis對所有的null都映射的是原生Jdbc的OTHER類型,Oracle不能正確處理;
MyBatis里有JdbcType枚舉類,與數據庫中的各種類型進行映射。
例如:#{email, JdbcType=NULL},在Oracle環境下,如果email為NUll,怎會出現JdbcType OTHER錯誤,把JdbcType改為NULL就行。即#{email,JdbcType=NULL}。
由於全局配置中:jdbcTypeForNull=OTHER;Oracle不支持;兩種解決方法:
1、#{email, jdbcType=NULL};
2、jdbcTypeForFull=NULL
<setting name="jdbcTypeForNull" value="NULL"/> 在全局配置文件中設置
7.映射文件===select返回List
resultType: 如果返回是一個集合,要寫集合中元素的類型。
public List<Employee> getEmpsByLastNameLike(String lastName);
<select id="getEmpsByLastNameLike" resultType="emp"> select * from tbl_employee where last_name like #{lastName} </select>
List<Employee> list = mapper.getEmpsByLastNameLike("%s%");
System.out.println("list:"+list);
8.映射文件===select記錄封裝Map
返回一條記錄的map;key就是列名,值就是對應的值
//返回一條記錄的map;key就是列名,值就是對應的值 public Map<String,Object> getEmpByIdReturnMap(Integer id);
<select id="getEmpByIdReturnMap" resultType="map"> select * from tbl_employee where id=#{id} </select>
//單條記錄的key值是列名 Map<String, Object> map = mapper.getEmpByIdReturnMap(2); String lastName = (String) map.get("last_name");
返回多條記錄封裝到map中:===注解@MapKey的使用:告訴MyBatis封裝的時候使用哪個屬性作為map的key
//多條記錄封裝一個Map:Map<Integer,Employee>:鍵是這條記錄的主鍵,值是記錄封裝后的Javabean //告訴Mybatis封裝這個Map的時候使用哪個屬性作為map的key。 @MapKey("id") public Map<Integer,Employee> getEmpByLastNameLikeReturnMap(String lastName);
<select id="getEmpByLastNameLikeReturnMap" resultType="emp"> select * from tbl_employee where last_name like #{lastName} </select>
Map<Integer, Employee> map = mapper.getEmpByLastNameLikeReturnMap("%s%");
9.映射文件===select_resultMap===自定義結果映射規則
自動映射:
自定義resultMap,高級映射:
<!--自定義某個Javabean的封裝規則 type:自定義規則的java類型 id:唯一id,方便引用 --> <resultMap id="MyEmp" type="com.atguigu.mybatis.bean.Employee"> <!--指定主鍵列的封裝規則 id:定義主鍵會底層有優化; column:指定哪一列 property:指定對應的Javabean屬性 --> <id column="id" property="id"/> <!--定義普通列封裝規則 --> <result column="last_name" property="lastName"/> <!--其他不指定的列會自動封裝:我們只要寫resultMap就把全部的映射規則全寫上--> <result column="email" property="email"/> <result column="gender" property="gender"/> </resultMap> <!--resultMap:自定義結果集映射規則;--> <select id="getEmpById" resultMap="MyEmp"> select * from tbl_employee where id=#{id} </select>
10.映射文件===select_resultMap===關聯查詢_環境搭建
數據庫准備:
/*創建部門表*/
CREATE TABLE tbl_dept(
id int(11) PRIMARY KEY auto_increment,
dept_name VARCHAR(255)
)
/*向表Employee中插入一列*/
ALTER TABLE tbl_employee ADD COLUMN d_id INT(11);
/*添加約束,外鍵關聯*/
ALTER TABLE tbl_employee ADD CONSTRAINT fk_emp_dept
FOREIGN KEY(d_id) REFERENCES tbl_dept(id)
/*查*/
SELECT e.id id,e.last_name last_name,e.gender gender,e.email email,e.d_id d_id,
d.id did,d.dept_name dept_name
FROM tbl_employee e,tbl_dept d
WHERE e.d_id=d.id AND e.id=2
在Employee類中增加所屬部門(另一個類)信息。
public Employee getEmpAndDept(Integer id);
<!-- 場景一: 查詢Employee的同時查詢員工對應的部門 Employee====Department 一個員工有與之對應的部門信息; --> <!-- 聯合查詢:級聯屬性封裝結果集 --> <resultMap id="MyDifEmp" type="emp"> <id column="id" property="id"/> <result column="last_name" property="lastName"/> <result column="gender" property="gender"/> <result column="email" property="email"/> <result column="did" property="dept.id"/> <result column="dept_name" property="dept.departmentName"/> </resultMap> <select id="getEmpAndDept" resultMap="MyDifEmp"> SELECT e.id id,e.last_name last_name,e.gender gender,e.email email,e.d_id d_id, d.id did,d.dept_name dept_name FROM tbl_employee e,tbl_dept d WHERE e.d_id=d.id AND e.id=#{id} </select>
Employee empAndDept = mapper.getEmpAndDept(2);
System.out.println(empAndDept);
System.out.println(empAndDept.getDept());
11.映射文件===select_resultMap關聯查詢association定義關聯對象封裝規則
<!--使用association定義關聯的單個對象的封裝規則--> <resultMap id="MyDifEmp2" type="emp"> <id column="id" property="id"/> <result column="last_name" property="lastName"/> <result column="gender" property="gender"/> <result column="email" property="email"/> <!--association:可以指定聯合的Javabean對象 property:指定哪個屬性是聯合的對象 javaType:指定屬性的java類型[不能省略] --> <association property="dept" javaType="department"> <id column="did" property="id"/> <result column="dept_name" property="departmentName"/> </association> </resultMap> <select id="getEmpAndDept" resultMap="MyDifEmp2"> SELECT e.id id,e.last_name last_name,e.gender gender,e.email email,e.d_id d_id, d.id did,d.dept_name dept_name FROM tbl_employee e,tbl_dept d WHERE e.d_id=d.id AND e.id=#{id} </select>
12.映射文件===select_resultMap關聯查詢association分步查詢
public Employee getEmpByIdStep(Integer id);
<resultMap id="MyEmpByStep" type="emp"> <id column="id" property="id"/> <result column="last_name" property="lastName"/> <result column="gender" property="gender"/> <result column="email" property="email"/> <!--association:定義關聯對象的封裝規則 select:表明當前屬性是調用select指定的方法查出的結果 column:指定將哪一列的值傳給這個方法 流程:使用select指定的方法(傳入column指定的這列參數的值)查出對象,並封裝給property指定的屬性 --> <association property="dept" select="com.atguigu.mybatis.dao.DepartmentMapper.getDeptById" column="d_id"> </association> </resultMap> <!--使用association進行分步查詢 1、先按照員工id查詢員工信息 2、根據查詢員工信息中的d_id值去部門表查詢部門信息 --> <select id="getEmpByIdStep" resultMap="MyEmpByStep"> select * from tbl_employee where id=#{id} </select>
<mapper namespace="com.atguigu.mybatis.dao.DepartmentMapper"> <select id="getDeptById" resultType="department"> select id,dept_name departmentName from tbl_dept where id=#{id} </select> </mapper>
Employee empByIdStep = mapper.getEmpByIdStep(2);
System.out.println(empByIdStep);
System.out.println(empByIdStep.getDept());
結果:控制台上會出現兩次數據庫查詢
DEBUG 11-16 21:04:50,898 ==> Preparing: select * from tbl_employee where id=? (BaseJdbcLogger.java:145) DEBUG 11-16 21:04:50,923 ==> Parameters: 2(Integer) (BaseJdbcLogger.java:145) DEBUG 11-16 21:04:50,949 ====> Preparing: select id,dept_name departmentName from tbl_dept where id=? (BaseJdbcLogger.java:145) DEBUG 11-16 21:04:50,953 ====> Parameters: 1(Integer) (BaseJdbcLogger.java:145) DEBUG 11-16 21:04:50,957 <==== Total: 1 (BaseJdbcLogger.java:145) DEBUG 11-16 21:04:50,958 <== Total: 1 (BaseJdbcLogger.java:145) Employee{id=2, lastName='jesscia', email='jesscia@qq.com', gender='0', dept=Department{id=1, departmentName='開發部'}} Department{id=1, departmentName='開發部'}
13.映射文件===select_resultMap關聯查詢association分步查詢&延時加載
分步查詢:1.可以組合已有的方法來完成復雜功能,2.可以使用延遲加載
在分步查詢的基礎之上:延時加載
<!--可以使用延遲加載 Employee==>Dept; 我們每次查詢Employee對象時,都將一起查詢出來。 部門信息在我們使用的時候再去查詢。 分步查詢的基礎之上加上兩個配置, -->
在全局配置文件中設置:
<settings> <!--顯示的指定每個我們需要更改的配置的值,即使他是默認的。防止版本更新帶來的問題--> <!--打開延時加載的開關--> <setting name="lazyLoadingEnabled" value="true"/> <!--將積極加載改為消極加載及按需加載--> <setting name="aggressiveLazyLoading" value="false"/> </settings>
然后就可以按需加載了。
14.映射文件===select_resultMap關聯查詢collection定義關聯集合封裝規則
場景二:查詢部門的時候將部門對應的所有員工信息也查詢出來
public Department getDeptByIdPlus(Integer id)throws Exception;
嵌套結果集的方式:
<!--collection:嵌套結果集的方式--> <resultMap id="MyDept" type="department"> <id column="did" property="id"/> <result column="dept_name" property="departmentName"/> <!--collection:定義關聯集合類型的屬性的封裝規則 ofType:指定集合里面元素的類型 --> <collection property="emps" ofType="emp"> <id column="eid" property="id"/> <result column="last_name" property="lastName"/> <result column="email" property="email"/> <result column="gender" property="gender"/> </collection> </resultMap> <select id="getDeptByIdPlus" resultMap="MyDept"> SELECT d.id did,d.dept_name dept_name, e.id eid,e.last_name last_name,e.email email,e.gender gender FROM tbl_dept d LEFT JOIN tbl_employee e ON d.id=e.d_id WHERE d.id=#{id} </select>
15.映射文件===select_resultMap關聯查詢collection分步查詢&延時加載
public Department getDeptByIdStep(Integer id);
<!--==========分步查詢===========--> <resultMap id="MyDept2" type="department"> <id column="id" property="id"/> <result column="dept_name" property="departmentName"/> <collection property="emps" select="com.atguigu.mybatis.dao.EmployeeMapperPlus.getEmpsByDid" column="id"> </collection> </resultMap> <select id="getDeptByIdStep" resultMap="MyDept2"> select id,dept_name departmentName from tbl_dept where id=#{id} </select>
public List<Employee> getEmpsByDid(Integer did);
<select id="getEmpsByDid" resultType="emp"> select * from tbl_employee where d_id=#{did} </select>
小擴展:在association和collection中的column屬性
作用:分步查詢中的要傳遞的參數值
當多列的值傳遞過去:將多列的值封裝成map傳遞;
column="{key1=column1, key2=column2}"
======================================
fetchType=“lazy”:表示使用延遲加載;
-lazy:延遲
-eager:立即
16.映射文件===select_resultMap的discriminator鑒別器
mybatis可以使用discriminator判斷某列的值,然后根據某列的值改變封裝行為。
封裝Employee:
如果查詢出的是女生:就把部門信息查詢出來,否則不查詢;
如果是男生,把last_name這一列的值賦值給email;
<resultMap id="MyEmpDis" type="emp"> <id column="id" property="id"/> <result column="last_name" property="lastName"/> <result column="gender" property="gender"/> <result column="email" property="email"/> <!--column:指定判斷的列名 javaType:列值對應的java類型 --> <discriminator javaType="string" column="gender"> <!--女生 resultType:指定封裝的結果類型--> <case value="0" resultType="emp"> <association property="dept" select="com.atguigu.mybatis.dao.DepartmentMapper.getDeptById" column="d_id"> </association> </case> <!--男生--> <case value="1" resultType="emp"> <id column="id" property="id"/> <result column="last_name" property="lastName"/> <result column="gender" property="gender"/> <result column="last_name" property="email"/> </case> </discriminator> </resultMap>
<select id="getEmpByIdStep" resultMap="MyEmpDis"> select * from tbl_employee where id=#{id} </select>