MyBatis中,自動映射的三種模式:java
默認的自動映射模式爲PARTIAL。
在MyBatis全局配置文件中,在setting標籤內設置自動映射模式:sql
<!--全局配置參數--> <settings> <setting name="autoMappingBehavior" value="PARTIAL" /> </settings>
若是某些resultMap中不想使用自動映射,則能夠單獨在該resultMap中設置autoMapping屬性爲false:mybatis
<select id="findUserById" parameterType="Long" resultMap="UserResult" autoMapping="false"> select id,name,email from t_user where id=#{id} </select>
這裏autoMapping屬性會忽略全局配置文件中"outoMappingBehavior"映射模式。app
若是Java包裝類使用駝峯命名規則,則要開啓mapUnderscoreToCamelCase屬性,讓自動映射機制將SQL查詢出的非駝峯命名方式的字段名與Java包裝類中的屬性進行自動映射:測試
<settings> <setting name="mapUnderscoreToCamelCase" value="true" /> </settings>
根據一些查詢條件來選擇不一樣的SQL語句:this
<select id="findUserList" parameterType="cn.com.mybatis.po.UserQueryVo" resultType="cn.com.mybatis.po.User"> select * from user <where> <if test="UserQuertVo != null"> <if test="UserQueryVo.gender != null and UserQueryVo.gender !=''"> and user.sex=#{UserQueryVo.gender} </if> <if test="UserQueryVo.username != null and UserQueryVo.username != ''"> and user.username like '%${UserQueryVo.username}%' </if> </if> </where> </select>
當使用"<where>"標籤對包裹if條件語句時,將會忽略查詢條件中的第一個"and"。spa
將複用性比較強的SQL語句封裝成SQL片斷,但在SQL片斷中不支持動態SQL語句的<where>
標籤:代理
<sql id="queryUserWhere"> <!--要複用的SQL語句--> </sql>
引用SQL映射配置:code
<select id="findUserList" parameterType="cn.com.mybatis.po.UserQueryVo" resultType="cn.com.mybatis.po.User"> select * from user <where> <include refid="queryUserWhere"></include> <!--在這裏可能還要引用其餘的SQL片斷--> </where> </select>
除了自身所在的Mapper文件,每一個SQL映射配置還能夠引用外部Mapper文件中的SQL片斷,只須要在refid屬性中填寫SQL片斷的id名添加所在Mapper文件的namespace信息便可。orm
有時查詢語句可能包含多個查詢信息,好比查詢多個id的User用戶:
select * from user where id in (2.4.6)
此時若是要在Mapper文件中配置這樣的語句,這裏定義一個Java包裝類,其屬性爲一個包含多個id信息的List集合:
public class UserQueryVo{ private List<Integer> ids;//包含多個id信息 public List<Integer> getIds(){ return ids; } public void setIds(List<Integer> ids){ this.ids = ids; } }
在Mapper中配置一個SQL片斷,並在查詢SQL映射中引入它:
<sql id="queryUserWhere"> <if test="ids!=null"> <foreach collection="ids" item="user_id" open="and id in (" close=")" separator=","> #{user_id} </foreach> </if> </sql> <select id="findUserList" parameterType="cn.com.mybatis.po.UserQueryVo" resultType="cn.com.mybatis.po.User"> select * from user <where> <include refid="query_user_where"></include> </where> </select>
在SQL片斷裏的"and"用來拼接已有一個或多個查詢條件的語句,當此語句爲第一個查詢條件時,會由於"<where>"的存在而屏蔽第一個"and"。
在實現一對一查詢時,推薦使用resultType。
使用resultMap時,對映射輸出的數據須要單獨定義resultMap,過程有些繁瑣,若是對查詢結果有特殊的要求(好比JavaBean裏面又包含有其餘JavaBean)就可使用。
好比查詢一個購買批次的信息以及建立該批次的用戶,一個批次對應着一個用戶。批次表名爲batch。
首先建立批次表batch對應的Java實體類Batch:
package cn.com.mybatis.po; import java.util.Date; import java.util.List; public class Batch { private int batch_id; private int cus_id; private String number; private Date createtime; private String note; public int getBatch_id() { return batch_id; } public void setBatch_id(int batch_id) { this.batch_id = batch_id; } //其餘的get和set方法省略...... }
建立一個以batch爲父類,而後追加用戶信息:
package cn.com.mybatis.po; public class BatchCustomer extends Batch { private String username; private String acno; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getAcno() { return acno; } public void setAcno(String acno) { this.acno = acno; } }
而後在UserMapper.xml映射文件中定義select類型的查詢語句:
<select id="findBatchCustomer" resultType="cn.com.mybatis.po.BatchCustomer"> SELECT batch.*,customer.username,customer.acno FROM batch INNER JOIN customer ON batch.cus_id = customer.cus_id </select>
編寫測試方法:
@Test public void testBatchCustomer() throws Exception{ SqlSession sqlSession = dataConnection.getSqlSession(); List<BatchCustomer> batchCustomerList = sqlSession.selectList("test.findBatchCustomer"); if(batchCustomerList != null){ BatchCustomer batchCustomer = null; SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); for (int i=0;i<batchCustomerList.size();i++){ batchCustomer = batchCustomerList.get(i); System.out.println("卡號爲" + batchCustomer.getAcno() + "的名爲" +batchCustomer.getUsername()+"的客戶:\\n於"+sdf.format(batchCustomer.getCreatetime()) +"採購了批次號爲"+batchCustomer.getNumber()+"的一批理財產品"); } } sqlSession.close(); }
使用resultMap能夠映射實體類中包裹的其餘實體類。
建立一個封裝了批次屬性和Customer實體類的BatchItem批次類:
package cn.com.mybatis.po; import java.util.Date; import java.util.List; public class BatchItem { private int batch_id; private int cus_id; private String number; private Date createtime; private String note; private Customer customer; public int getBatch_id() { return batch_id; } public void setBatch_id(int batch_id) { this.batch_id = batch_id; } }
SQL映射文件:
<!--一對一查詢,使用resultMap實現--> <resultMap id="BatchInfoMap" type="cn.com.mybatis.po.BatchItem"> <id column="batch_id" property="batch_id"/> <result column="cus_id" property="cus_id"/> <result column="number" property="number"/> <result column="createtime" property="createtime" javaType="Date"/> <result column="note" property="note"/> <association property="customer" javaType="cn.com.mybatis.po.Customer"> <id column="cus_id" property="cus_id"/> <result column="username" property="username"/> <result column="acno" property="acno"/> <result column="gender" property="gender"/> <result column="phone" property="phone"/> </association> </resultMap> <select id="findBatchCustomerToMap" resultMap="BatchInfoMap"> SELECT batch.*,customer.username,customer.acno FROM batch INNER JOIN customer ON batch.cus_id = customer.cus_id </select>
編寫測試類:
@Test public void testBatchCustomerToMap() throws Exception{ SqlSession sqlSession = dataConnection.getSqlSession(); List<BatchItem> batchItemList = sqlSession.selectList("test.findBatchCustomerToMap"); if(batchItemList != null){ BatchItem batchItem = null; Customer customer = null; SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); for (int i=0;i<batchItemList.size();i++){ batchItem = batchItemList.get(i); customer = batchItem.getCustomer(); System.out.println("卡號爲" + customer.getAcno() + "的名爲" +customer.getUsername()+"的客戶:\\n於"+sdf.format(batchItem.getCreatetime()) +"採購了批次號爲"+batchItem.getNumber()+"的一批理財產品"); } } }
好比,查詢一批中一個用戶信息,和有哪些理財產品。
修改一下Batch類:
package cn.com.mybatis.po; import java.util.Date; import java.util.List; public class Batch { private int batch_id; private int cus_id; private String number; private Date createtime; private String note; //批次中包含的理財產品訂購信息 private List<BatchDetail> batchDetials; //get和set方法省略...... }
理財產品的訂購信息實體類以下:
package cn.com.mybatis.po; import java.util.List; public class BatchDetail { private int id; private int batch_id; private int product_id; private int product_num; private FinacialProduct finacialProduct; //get和set方法省略...... }
編寫SQL配置,使用extends標籤繼承上面一對一查詢中的名爲BatchInfoMap的resultMap:
<!--一對多--> <resultMap id="BatchAndBatchDetailResultMap" type="cn.com.mybatis.po.BatchItem" extends="BatchInfoMap"> <collection property="batchDetails" ofType="cn.com.mybatis.po.BatchDetail"> <!-- id:訂單明細的惟一標識 --> <id column="id" property="id"/> <result column="batch_id" property="batch_id"/> <result column="product_id" property="product_id"/> <result column="product_num" property="product_num"/> </collection> </resultMap> <select id="findBatchAndBatchDetail" resultMap="BatchAndBatchDetailResultMap"> SELECT batch.*, customer.username,customer.acno, batchdetail.product_id, batchdetail.product_num FROM ((batch INNER JOIN customer ON batch.cus_id = customer.cus_id) INNER JOIN batchdetail ON batch.batch_id = batchdetail.batch_id) </select>
測試查詢結果:
@Test public void testfindBatchAndBatchDetail() throws Exception{ SqlSession sqlSession=dataConnection.getSqlSession(); //調用userMapper的方法 BatchItem batchItem= sqlSession.selectOne( "test" + ".findBatchAndBatchDetail"); if(batchItem!=null){ SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); Customer customer = batchItem.getCustomer();//取出該批次的用戶信息 //取出該批次訂購的理財產品信息 List<BatchDetail> batchDetails = batchItem.getBatchDetails(); System.out.println("卡號爲"+customer.getAcno()+"的名爲" +customer.getUsername()+"的客戶:\\n於" +sdf.format(batchItem.getCreatetime())+"採購了批次號爲" +batchItem.getNumber()+"的一批理財產品,詳情以下:"); BatchDetail batchDetail = null; if(batchDetails!=null){ for (int i = 0; i < batchDetails.size(); i++) { batchDetail = batchDetails.get(i); System.out.println("id爲"+batchDetail.getProduct_id() +"的理財產品"+batchDetail.getProduct_num()+"份"); } } } sqlSession.close(); }
這裏使用了association與collocation,一個映射單一實體對象,一個映射集合對象。
查詢全部用戶以及用戶對應的批次訂單中全部理財產品的詳細信息。
修改後的Customer用戶類,它包含用戶信息以及用戶下的全部批次信息:
package cn.com.mybatis.po; import java.io.Serializable; import java.util.List; public class Customer implements Serializable{ private int cus_id; private String username; private String acno; private String gender; private String phone; private List<Batch> batchList; //get和set方法省略 }
修改後的Batch批次信息類,它包含單個批次信息以及批次明細列表:
package cn.com.mybatis.po; import java.util.Date; import java.util.List; public class Batch { private int batch_id; private int cus_id; private String number; private Date createtime; private String note; private List<BatchDetail> batchDetials; //get和set方法省略 }
修改後的BatchDetail批次明細類,它包含單個批次明細和對應的理財產品引用:
package cn.com.mybatis.po; import java.util.List; public class BatchDetail { private int id; private int batch_id; private int product_id; private int product_num; private FinacialProduct finacialProduct; //get和set方法省略 }
新增的FinacialProduct產品明細類,包含理財產品的各類屬性:
package cn.com.mybatis.po; import java.util.Date; public class FinacialProduct { private int id; private String name; private double price; private String detail; private String imgpath; private Date invattime; //get和set方法省略 }
編寫Mapper映射文件:
<resultMap id="UserAndProductsResultMap" type="cn.com.mybatis.po.Customer"> <!-- 客戶信息 --> <result column="username" property="username"/> <result column="acno" property="acno"/> <!--批次訂單信息,一個客戶對應多個訂單--> <collection property="batchList" ofType="cn.com.mybatis.po.Batch"> <id column="batch_id" property="batch_id"/> <result column="cus_id" property="cus_id"/> <result column="number" property="number"/> <result column="createtime" property="createtime" javaType="java.util.Date"/> <result column="note" property="note"/> <collection property="batchDetials" ofType="cn.com.mybatis.po.BatchDetail"> <!-- id:訂單明細的惟一標識--> <id column="id" property="id"/> <result column="batch_id" property="batch_id"/> <result column="product_id" property="product_id"/> <result column="product_num" property="product_num"/> <association property="finacialProduct" javaType="cn.com.mybatis.po.FinacialProduct"> <id column="product_id" property="id"/> <result column="name" property="name"/> <result column="price" property="price"/> <result column="detail" property="detail"/> </association> </collection> </collection> </resultMap> <select id="findUserAndProducts" resultMap="UserAndProductsResultMap"> SELECT BATCH.*, CUSTOMER.username, CUSTOMER.acno, BATCHDETAIL.product_id, BATCHDETAIL.product_num, FINACIAL_PRODUCTS.name, FINACIAL_PRODUCTS.detail, FINACIAL_PRODUCTS.price FROM BATCH, CUSTOMER, BATCHDETAIL, FINACIAL_PRODUCTS WHERE BATCH.cus_id = CUSTOMER.cus_id AND BATCHDETAIL.batch_id=BATCH.batch_id AND FINACIAL_PRODUCTS.product_id=BATCHDETAIL.product_id; </select>
在MyBatis中,一般會進行多表聯合查詢,可是有時候並不會當即用到全部的聯合查詢結果。這種「按需查詢」的機制,就可使用延遲加載來實現。
開啓延遲加載功能:
//在全局配置文件中配置setting屬性 <configuration> <settings> <!--打開延遲加載的開關--> <setting name="lazyLoadingEnable" value="true" /> <!--將積極加載改成按需加載--> <setting name="aggressiveLazyLoading" value="false" /> </settings> </configuration>
例如查詢全部批次訂單的信息,而每一個批次訂單中會關聯查詢用戶,延遲加載用戶信息,首先定義只查詢全部批次訂單信息的SQL配置:
<select id="findBatchUserLazyLoading" resultMap="BatchUserLazyLoadingResultMap"> select * from batch </select> <!--延遲加載的resultMap--> <resultMap id="BatchUserLazyLoadingResultMap" type="cn.com.mybatis.po.BatchItem"> <!--對訂單信息進行映射配置--> <id column="batch_id" property="batch_id" /> <result column="cus_id" property="cus_id" /> <result column="number" property="number" /> <result column="createtime" property="createtime" javaType="java.util.Date" /> <result column="note" property="note" /> <!--實現延遲加載用戶信息--> <association property="customer" javaType="cn.com.mybatis.po.Customer" select="findCustomerById" column="cus_id"> </association> </resultMap>
其中select用來指定Mapper.xml配置文件中的某個select標籤對的id。
column是指訂單信息中關聯用戶信息查詢的列。
最後配置延遲加載要執行的獲取用戶信息的SQL:
<select id="findCustomerById" parameterType="int" resultType="cn.com.mybatis.po.Customer"> select * from customer where cus_id=#{id} </select>
其中輸入參數就是association中column中定義的字段信息。
編寫測試方法:
@Test public void testFindBatchCustomerLazyLoading() throws Exception{ SqlSession sqlSession=dataConn.getSqlSession(); //調用userMapper的方法,獲取全部訂單信息(未加載關聯的用戶信息) List<BatchItem> batchItemList=sqlSession.selectList("findBatchUserLazyLoading"); BatchItem batchItem = null; Customer customer = null; for (int i = 0; i < batchItemList.size(); i++) { batchItem = batchItemList.get(i); System.out.println("訂單編號:"+batchItem.getNumber()); //執行getCustomer時纔會去查詢用戶信息,這裏實現了延遲加載 customer=batchItem.getCustomer(); System.out.println("訂購用戶姓名:"+customer.getUsername()); } sqlSession.close(); }
綜上所述,使用延遲加載方法,先執行簡單的查詢SQL(最好查詢單表,也能夠關聯查詢),再按須要加載關聯查詢的其餘信息。
新增一個CustomerMapper.xml,例如對Customer的增、刪、改、查的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="cn.com.mybatis.mapper.CustomerMapper"> <!-- 查詢用戶 --> <select id="findCustomerById" parameterType="int" resultType="cn.com.mybatis.po.Customer"> SELECT * FROM CUSTOMER WHERE cus_id=#{cus_id} </select> <!-- 新增用戶 --> <insert id="insertCustomer" parameterType="cn.com.mybatis.po.Customer"> INSERT INTO CUSTOMER(username,acno,gender,phone) value(#{username},#{acno},#{gender},#{phone}) </insert> <!-- 刪除用戶 --> <delete id="deleteCustomer" parameterType="java.lang.Integer"> DELETE FROM CUSTOMER WHERE cus_id=#{cus_id} </delete> <!-- 修改用戶 --> <update id="updateCustomerAcNo" parameterType="cn.com.mybatis.po.Customer" > UPDATE CUSTOMER SET acno = #{acno} WHERE cus_id=#{cus_id} </update> </mapper>
其中,namespace中的路徑爲即將建立的mapper代理接口的路徑。
使用CustomerMapper.xml的Mapper代理,建立CustomerMapper接口:
package cn.com.mybatis.mapper; import cn.com.mybatis.po.Customer; public interface CustomerMapper { public Customer findCustomerById(int id) throws Exception; public void insertCustomer(Customer customer) throws Exception; public void deleteCustomer(int id) throws Exception; public void updateCustomerAcNo(Customer customer) throws Exception; }
測試動態代理效果:
@Test public void testFindCustomerOnMapper() throws Exception{ SqlSession sqlSession=dataConn.getSqlSession(); //獲取Mapper代理 CustomerMapper customerMapper=sqlSession.getMapper(CustomerMapper.class); //執行Mapper代理對象的查詢方法 Customer customer=customerMapper.findCustomerById(1); System.out.println("用戶姓名:"+customer.getUsername()+"|" +"卡號:"+customer.getAcno()); sqlSession.close(); }
其中SqlSession類的getMapper方法的原理就是,根據Mapper代理接口的類型及Mapper.xml文件的內容,建立一個Mapper接口的實現類,其中實現了具體的增刪改查方法。