一對一查詢
需求
查詢訂單信息關聯查詢用戶信息
sql語句前端
/*經過orders關聯查詢用戶使用user_id一個外鍵,只能關聯查詢出一條用戶記錄就可使用內鏈接*/ SELECT orders.*,user.username,user.sex FROM orders,USER WHERE orders.user_id = user.id
使用resultType實現
一對一查詢映射的pojo
建立pojo包括 訂單信息和用戶信息,resultType才能夠完成映射。建立OrderCustom做爲自定義pojo,繼承sql查詢列多的po類。java
public class OrderCustom extends Orders { //補充用戶信息 private String username; private String sex; private String address; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } @Override public String toString() { return "OrderCustom [username=" + username + ", sex=" + sex + ", address=" + address + "]"; } }
mapper.xmlspring
<!-- 一對一查詢使用reusltType完成 查詢訂單關聯查詢用戶信息 --> <select id="findOrderUserList" resultType="orderCustom"> SELECT orders.*,user.username,user.sex FROM orders,USER WHERE orders.user_id = user.id </select>
mapper.javasql
public interface OrdersMapperCustom { // 一對一查詢,查詢訂單關聯查詢用戶,使用resultType public List<OrderCustom> findOrderUserList() throws Exception; // 一對一查詢,使用resultMap public List<Orders> findOrderUserListResultMap() throws Exception; //一對一查詢,延遲加載 public List<Orders> findOrderUserListLazyLoading() throws Exception; // 一對多查詢,使用resultMap public List<Orders> findOrderAndOrderDetails() throws Exception; // 一對多查詢,使用resultMap public List<User> findUserOrderDetail() throws Exception; }
使用resultMap實現一對一
resultMap映射思路
resultMap提供一對一關聯查詢的映射和一對多關聯查詢映射,一對一映射思路:將關聯查詢的信息映射到pojo中,以下:在Orders類中建立一個User屬性,將關聯查詢的信息映射到User屬性中。數據庫
public class Orders implements Serializable { private Integer id; private Integer userId; private String number; private Date createtime; private String note; //關聯用戶信息 private User user; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public Integer getUserId() { return userId; } public void setUserId(Integer userId) { this.userId = userId; } public String getNumber() { return number; } public void setNumber(String number) { this.number = number == null ? null : number.trim(); } public Date getCreatetime() { return createtime; } public void setCreatetime(Date createtime) { this.createtime = createtime; } public String getNote() { return note; } public void setNote(String note) { this.note = note == null ? null : note.trim(); } public User getUser() { return user; } public void setUser(User user) { this.user = user; } }
mapper.xmlapache
<!-- 一對一查詢使用reusltMap完成 查詢訂單關聯查詢用戶信息 --> <select id="findOrderUserListResultMap" resultMap="ordersUserResultMap" > SELECT orders.*,user.username,user.sex FROM orders,USER WHERE orders.user_id = user.id </select>
resultMap定義緩存
<resultMap type="orders" id="ordersUserResultMap"> <!-- 完成了訂單信息的映射配置 --> <!-- id:訂單關聯用戶查詢的惟 一 標識 --> <id column="id" property="id"/> <result column="user_id" property="userId"/> <result column="number" property="number"/> <result column="createtime" property="createtime"/> <result column="note" property="note"/> <!-- 下邊完成關聯信息的映射 association:用於對關聯信息映射到單個pojo property:要將關聯信息映射到orders的哪一個屬性中 javaType:關聯信息映射到orders的屬性的類型,是user的類型 --> <association property="user" javaType="user"> <!-- id:關聯信息的惟 一標識 --> <!-- property: 要映射到user的哪一個屬性中--> <id column="user_id" property="id"/> <!-- result就是普通列的映射 --> <result column="username" property="username"/> <result column="sex" property="sex"/> </association> </resultMap>
小結
resultType:要自定義pojo 保證sql查詢列和pojo的屬性對應,這種方法相對較簡單,因此應用普遍。
resultMap:使用association完成一對一映射須要配置一個resultMap,過程有點複雜,若是要實現延遲加載就只能用resultMap實現 ,若是爲了方便對關聯信息進行解析,也能夠用association將關聯信息映射到pojo中方便解析。
一對多查詢
需求
查詢全部訂單信息及訂單下的訂單明細信息。
sql語句session
SELECT orders.*,user.username,user.sex ,orderdetail.id orderdetail_id,orderdetail.items_num,orderdetail.items_id FROM orders,USER,orderdetail WHERE orders.user_id = user.id AND orders.id = orderdetail.orders_id
resultMap進行一對多映射思路
resultMap 提供collection完成關聯信息映射到集合對象中。在orders類中建立集合屬性數據結構
public class Orders implements Serializable { private Integer id; private Integer userId; private String number; private Date createtime; private String note; //關聯用戶信息 private User user; //訂單明細 private List<Orderdetail> orderdetails; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public Integer getUserId() { return userId; } public void setUserId(Integer userId) { this.userId = userId; } public String getNumber() { return number; } public void setNumber(String number) { this.number = number == null ? null : number.trim(); } public Date getCreatetime() { return createtime; } public void setCreatetime(Date createtime) { this.createtime = createtime; } public String getNote() { return note; } public void setNote(String note) { this.note = note == null ? null : note.trim(); } public User getUser() { return user; } public void setUser(User user) { this.user = user; } public List<Orderdetail> getOrderdetails() { return orderdetails; } public void setOrderdetails(List<Orderdetail> orderdetails) { this.orderdetails = orderdetails; } }
mapper.xmlmybatis
<!-- 一對多查詢使用reusltMap完成 查詢訂單關聯查詢訂單明細 --> <select id="findOrderAndOrderDetails" resultMap="orderAndOrderDetails" > SELECT orders.*,user.username,user.sex ,orderdetail.id orderdetail_id,orderdetail.items_num,orderdetail.items_id FROM orders,USER,orderdetail WHERE orders.user_id = user.id AND orders.id = orderdetail.orders_id </select>
resultMap定義
<!-- 一對多,查詢訂單及訂單明細 --> <resultMap type="orders" id="orderAndOrderDetails" extends="ordersUserResultMap"> <!-- 映射訂單信息,和用戶信息,這裏使用繼承ordersUserResultMap --> <collection property="orderdetails" ofType="cn.yzu.mybatis.po.Orderdetail"> <!-- id:關聯信息訂單明細的惟 一標識 property:Orderdetail的屬性名 --> <id column="orderdetail_id" property="id"/> <result column="items_num" property="itemsNum"/> <result column="items_id" property="itemsId"/> </collection> </resultMap>
一對多查詢(複雜)
需求
查詢全部用戶信息,關聯查詢訂單及訂單明細信息及商品信息,訂單明細信息中關聯查詢商品信息
pojo定義
在user.java中建立映射的屬性:集合 List<Orders> orderlist
在Orders中建立映射的屬性:集合List<Orderdetail> orderdetails
在Orderdetail中建立商品屬性:pojo Items items
mapper.xml
<!-- 一對多查詢使用reusltMap完成 查詢用戶及訂單和訂單明細,關聯商品,的信息--> <select id="findUserOrderDetail" resultMap="userOrderDetailResultMap" > SELECT orders.*,user.username,user.sex ,orderdetail.id orderdetail_id,orderdetail.items_num,orderdetail.items_id,items.name items_name,items.detail items_detail FROM orders,USER,orderdetail,items WHERE orders.user_id = user.id AND orders.id = orderdetail.orders_id AND items.id = orderdetail.items_id </select>
resultMap
<!-- 一對多查詢,查詢用戶及訂單明細和商品信息 --> <resultMap type="user" id="userOrderDetailResultMap"> <!-- 用戶信息映射 --> <id column="user_id" property="id"/> <result column="username" property="username"/> <result column="sex" property="sex"/> <!-- 訂單信息 --> <collection property="orderlist" ofType="cn.yzu.mybatis.po.Orders"> <id column="id" property="id"/> <result column="user_id" property="userId"/> <result column="number" property="number"/> <result column="createtime" property="createtime"/> <result column="note" property="note"/> <!-- 訂單明細映射 --> <collection property="orderdetails" ofType="cn.yzu.mybatis.po.Orderdetail"> <!-- id:關聯信息訂單明細的惟 一標識 property:Orderdetail的屬性名 --> <id column="orderdetail_id" property="id"/> <result column="items_num" property="itemsNum"/> <result column="items_id" property="itemsId"/> <!-- 商品信息 --> <association property="items" javaType="cn.yzu.mybatis.po.Items"> <id column="item_id" property="id"/> <result column="items_name" property="name"/> <result column="items_detail" property="detail"/> </association> </collection> </collection> </resultMap>
延遲加載
使用延遲加載意義
在進行數據查詢時,爲了提升數據庫查詢性能,儘可能使用單表查詢,由於單表查詢比多表關聯查詢速度要快。若是查詢單表就能夠知足需求,一開始先查詢單表,當須要關聯信息時,再關聯查詢,當須要關聯信息再查詢這個叫延遲加載。
mybatis中resultMap提供延遲加載功能,經過resultMap配置延遲加載。
配置mybatis支持延遲加載
<!-- 全局配置參數 --> <settings> <!-- 延遲加載總開關 --> <setting name="lazyLoadingEnabled" value="true" /> <!-- 設置按需加載 --> <setting name="aggressiveLazyLoading" value="false" /> </settings>
延遲加載實現思路
需求:查詢訂單及用戶的信息,一對一查詢。剛開始只查詢訂單信息,當須要用戶時調用 Orders類中的getUser()方法執行延遲加載 ,向數據庫發出sql。
mapper.xml
<!-- 一對一查詢延遲加載 開始只查詢訂單,對用戶信息進行延遲加載 --> <select id="findOrderUserListLazyLoading" resultMap="orderCustomLazyLoading"> SELECT orders.* FROM orders </select>
resultMap
<!-- 一對一查詢延遲加載 的配置 --> <resultMap type="orders" id="orderCustomLazyLoading"> <!-- 完成了訂單信息的映射配置 --> <!-- id:訂單關聯用戶查詢的惟 一 標識 --> <id column="id" property="id" /> <result column="user_id" property="userId" /> <result column="number" property="number" /> <result column="createtime" property="createtime" /> <result column="note" property="note" /> <!-- 配置用戶信息的延遲加載 select:延遲加載執行的sql所在的statement的id,若是不在同一個namespace須要加namespace sql:根據用戶id查詢用戶信息 column:關聯查詢的列 property:將關聯查詢的用戶信息設置到Orders的哪一個屬性 --> <association property="user" select="cn.yzu.mybatis.mapper.UserMapper.findUserById" column="user_id"></association> </resultMap>
測試代碼
// 一對一查詢延遲加載 @Test public void testFindOrderUserListLazyLoading() throws Exception { SqlSession sqlSession = sqlSessionFactory.openSession(); OrdersMapperCustom ordersMapperCustom = sqlSession.getMapper(OrdersMapperCustom.class); List<Orders> list = ordersMapperCustom.findOrderUserListLazyLoading(); User user = list.get(0).getUser(); System.out.println(user); }
resultType、resultMap、延遲加載使用場景總結
延遲加載:延遲加載實現的方法多種多樣,在只查詢單表就能夠知足需求,爲了提升數據庫查詢性能使用延遲加載,再查詢關聯信息。mybatis提供延遲加載的功能用於service層。
resultType
做用:將查詢結果按照sql列名pojo屬性名一致性映射到pojo中。
場合:常見一些明細記錄的展現,將關聯查詢信息所有展現在頁面時,此時可直接使用resultType將每一條記錄映射到pojo中,在前端頁面遍歷list(list中是pojo)便可。
resultMap:使用association和collection完成一對一和一對多高級映射。
association
做用:將關聯查詢信息映射到一個pojo類中。
場合:爲了方便獲取關聯信息可使用association將關聯訂單映射爲pojo,好比:查詢訂單及關聯用戶信息。
collection
做用:將關聯查詢信息映射到一個list集合中。
場合:爲了方便獲取關聯信息可使用collection將關聯信息映射到list集合中,好比:查詢用戶權限範圍模塊和功能,可以使用collection將模塊和功能列表映射到list中。
查詢緩存
緩存的意義
將用戶常常查詢的數據放在緩存(內存)中,用戶去查詢數據就不用從磁盤上(關係型數據庫數據文件)查詢,從緩存中查詢,從而提升查詢效率,解決了高併發系統的性能問題。
mybatis持久層緩存
mybatis提供一級緩存和二級緩存,mybatis一級緩存是一個SqlSession級別,sqlsession只能訪問本身的一級緩存的數據,二級緩存是跨sqlSession,是mapper級別的緩存,對於mapper級別的緩存不一樣的sqlsession是能夠共享的。
一級緩存
原理:第一次發出一個查詢sql,sql查詢結果寫入sqlsession的一級緩存中,緩存使用的數據結構是一個map<key,value>
key:hashcode+sql+sql輸入參數+輸出參數(sql的惟一標識)
value:用戶信息
同一個sqlsession再次發出相同的sql,就從緩存中取不走數據庫。若是兩次中間出現commit操做(修改、添加、刪除),本sqlsession中的一級緩存區域所有清空,下次再去緩存中查詢不到因此要從數據庫查詢,從數據庫查詢到再寫入緩存。
每次查詢都先從緩存中查詢:若是緩存中查詢到則將緩存數據直接返回。若是緩存中查詢不到就從數據庫查詢
一級緩存配置:mybatis默認支持一級緩存不須要配置。
注意:mybatis和spring整合後進行mapper代理開發,不支持一級緩存,mybatis和spring整合,spring按照mapper的模板去生成mapper代理對象,模板中在最後統一關閉sqlsession。
二級緩存
原理:二級緩存的範圍是mapper級別(mapper同一個命名空間),mapper以命名空間爲單位建立緩存數據結構,結構是map<key、value>。每次查詢先看是否開啓二級緩存,若是開啓從二級緩存的數據結構中取緩存數據,若是從二級緩存沒有取到,再從一級緩存中找,若是一級緩存也沒有,從數據庫查詢。
mybatis二級緩存配置:在覈心配置文件SqlMapConfig.xml中加入<setting name="cacheEnabled" value="true"/>要在你的Mapper映射文件中添加一行: <cache /> ,表示此mapper開啓二級緩存。
查詢結果映射的pojo序列化:mybatis二級緩存須要將查詢結果映射的pojo實現 java.io.serializable接口,若是不實現則拋出異常:org.apache.ibatis.cache.CacheException: Error serializing object. Cause: java.io.NotSerializableException: cn.itcast.mybatis.po.User,二級緩存能夠將內存的數據寫到磁盤,存在對象的序列化和反序列化,因此要實現java.io.serializable接口。若是結果映射的pojo中還包括了pojo,都要實現java.io.serializable接口。
二級緩存禁用:對於變化頻率較高的sql,須要禁用二級緩存,在statement中設置useCache=false能夠禁用當前select語句的二級緩存,即每次查詢都會發出sql去查詢,默認狀況是true,即該sql使用二級緩存。<select id="findOrderListResultMap" resultMap="ordersUserMap" useCache="false">
二級緩存的應用場景
對查詢頻率高,變化頻率低的數據建議使用二級緩存。
對於訪問多的查詢請求且用戶對查詢結果實時性要求不高,此時可採用mybatis二級緩存技術下降數據庫訪問量,提升訪問速度,業務場景好比:耗時較高的統計分析sql、電話帳單查詢sql等。