數據庫級別
表與表的關係(即:明確數據庫中表與表之間的外鍵關係)
業務關係
(即:明確業務中表與表的關係(創建在具體的業務上))
sql語句以下:php
SELECT
orders.id,
orders.user_id,
orders.number,
user.username,
user.sex
FROM
orders,
user
WHERE orders.user_id = user.id;
(1)建立擴展PO類
通常User.java類要和數據表表字段一致,最好不要在這裏面添加其餘字段,今天學習mybatis的逆向工程時,會根據表結構,生成po類,若是在po類中擴展字段,此時會被覆蓋掉。
因此針對要擴展的po類,咱們須要建立一個擴展類,來繼承它。html
/**
* 經過此類映射訂單和用戶查詢的結果,讓此類繼承包括字段較多的pojo類
* @author Bruce
*
*/
public class OrdersExt extends Orders {
// 添加用戶屬性
// user.username
// user.sex
private String username;
private String sex;
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;
}
}
(2)編寫mapper接口
建立OrdersMapper接口類,在類中添加如下內容:前端
public interface OrdersMapper {
// 一對一映射之 resultType
// 查詢訂單信息,關聯查詢建立訂單的用戶信息(用戶名稱和性別)
public List<OrdersExt> findOrdersAndUser();
}
(3)編寫映射文件
建立OrdersMapper.xml映射文件,在映射文件中添加如下內容:java
<mapper namespace="com.itheima.mybatis.mapper.OrdersMapper">
<!-- 一對一映射之 resultType -->
<!-- 查詢訂單信息,關聯查詢建立訂單的用戶信息(用戶名稱和性別) -->
<select id="findOrdersAndUser" resultType="com.itheima.mybatis.po.OrdersExt">
SELECT
orders.id,
orders.user_id,
orders.number,
user.username,
user.sex
FROM
orders,
user
WHERE orders.user_id = user.id
</select>
</mapper>
(4)加載映射文件
在config/SqlMapConfig.xml中,添加如下內容:mysql
<!-- 加載mapper,即加載映射文件 -->
<mappers>
<!-- 使用相對於類路徑的資源,加載配置文件 -->
<!--
<mapper resource="sqlmap/User.xml"/>
<mapper resource="mapper/UserMapper.xml"/>
<mapper resource="mapper/OrdersMapper.xml"/>
-->
<!-- 推薦使用:批量加載mapper文件,須要mapper接口文件和mapper映射文件名稱相同且在同一個包下 -->
<package name="com.itheima.mybatis.mapper"/>
</mappers>
(5)編寫測試代碼git
@Test
public void testFindUserById() {
// 根據SqlSessionFactory建立SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 建立OrdersMapper對象
// 由Mybatis經過sqlSession來建立動態代理對象
OrdersMapper mapper = sqlSession.getMapper(OrdersMapper.class);
List<OrdersExt> list = mapper.findOrdersAndUser();
System.out.println(list);
sqlSession.close();
}
(6)小結github
平鋪式
的映射,即:數據庫查詢出多少條記錄,則映射成多少個對象。對象嵌套對象
的一種映射方式。(1)修改擴展PO類
在OrdersExt類中,添加User對象web
/**
* 經過此類映射訂單和用戶查詢的結果,讓此類繼承包括字段較多的pojo類
* 在OrdersExt類中,添加User對象
* @author Bruce
*
*/
public class OrdersExt extends Orders {
// 添加用戶屬性
// user.username
// user.sex
private String username;
private String sex;
// 添加用戶對象(用戶信息)
private User user;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
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;
}
}
(2)編寫mapper接口redis
// 一對一映射之 resultMap
// 查詢訂單信息,關聯查詢建立訂單的用戶信息(用戶名稱和性別)
public List<OrdersExt> findOrdersAndUserResultMap();
(3)編寫映射文件spring
<!-- 聲明/定義一個resultMap -->
<resultMap type="com.itheima.mybatis.po.OrdersExt" id="OrdersAndUserResultMap">
<!-- 訂單信息映射 -->
<id column="id" property="id"/>
<result column="user_id" property="userId"/>
<result column="number" property="number"/>
<!-- 用戶信息映射(一對一) -->
<!--
association標籤:定義一個一對一關係
property:指定關聯對象要映射到OrdersExt的哪一個屬性上
javaType:指定關聯對象所要映射的java類型
id標籤:指定關聯對象結果集的惟一標識,很重要,建議在關聯查詢時必須寫上,不寫不會報錯,可是會影響性能
-->
<association property="user" javaType="com.itheima.mybatis.po.User">
<id column="user_id" property="id"/>
<result column="username" property="username"/>
<result column="sex" property="sex"/>
</association>
</resultMap>
<!-- 一對一映射之 resultMap -->
<!-- 查詢訂單信息,關聯查詢建立訂單的用戶信息(用戶名稱和性別) -->
<select id="findOrdersAndUserResultMap" resultMap="OrdersAndUserResultMap">
SELECT
orders.id,
orders.user_id,
orders.number,
user.username,
user.sex
FROM
orders,
user
WHERE orders.user_id = user.id
</select>
(4)加載映射文件
已配置,此處無需再次配置。
(5)編寫測試代碼
@Test
public void testFindOrdersAndUserResultMap() {
// 根據SqlSessionFactory建立SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 建立OrdersMapper對象
// 由Mybatis經過sqlSession來建立動態代理對象
OrdersMapper mapper = sqlSession.getMapper(OrdersMapper.class);
List<OrdersExt> list = mapper.findOrdersAndUserResultMap();
System.out.println(list);
sqlSession.close();
}
(6)小結
對象嵌套對象
)時,須要使用resultMap進行映射,好比:查詢訂單列表,而後在點擊列表中的查看訂單明細按鈕,這個時候就須要使用resultMap進行結果映射。而resultType更適應於查詢訂單明細信息,好比,查詢訂單明細列表。實現一對一查詢:
若是使用resultMap的話,映射一對多關聯關係要使用collection標籤
。sql語句以下:
SELECT
orders.id,
orders.user_id,
orders.number,
user.username,
user.sex,
orderdetail.id detail_id,
orderdetail.items_id,
orderdetail.items_num
FROM
orders,
user,
orderdetail
WHERE orders.user_id = user.id
AND orders.id = orderdetail.orders_id;
(1)修改擴展PO類
在OrdersExt類中添加如下屬性,並提供get/set方法:
// 訂單明細信息
private List<Orderdetail> detailList;
public List<Orderdetail> getDetailList() {
return detailList;
}
public void setDetailList(List<Orderdetail> detailList) {
this.detailList = detailList;
}
(2)編寫mapper接口
// 一對多映射之 resultMap
// 查詢訂單信息,關聯查詢訂單明細信息及用戶信息
public List<OrdersExt> findOrdersAndOrderdetailResultMap();
(3)編寫映射文件
<!-- 聲明/定義一個resultMap -->
<!-- extends:繼承已有的ResultMap,值爲繼承的ResultMap的惟一標示 -->
<resultMap type="com.itheima.mybatis.po.OrdersExt" id="OrdersAndOrderdetailResultMap" extends="OrdersAndUserResultMap">
<!-- 訂單信息映射 -->
<!-- 用戶信息映射(一對一) -->
<!-- 訂單明細信息映射(一對多) -->
<!-- collection標籤:定義一個一對多關係
ofType:指定該集合參數所映射的類型
-->
<collection property="detailList" ofType="com.itheima.mybatis.po.Orderdetail">
<id column="detail_id" property="id"/>
<result column="items_id" property="itemsId"/>
<result column="items_num" property="itemsNum"/>
</collection>
</resultMap>
<!-- 一對多映射之 resultMap -->
<!-- 查詢訂單信息,關聯查詢訂單明細信息及用戶信息 -->
<select id="findOrdersAndOrderdetailResultMap" resultMap="OrdersAndOrderdetailResultMap">
SELECT
orders.id,
orders.user_id,
orders.number,
user.username,
user.sex,
orderdetail.id detail_id,
orderdetail.items_id,
orderdetail.items_num
FROM
orders,
user,
orderdetail
WHERE orders.user_id = user.id
AND orders.id = orderdetail.orders_id
</select>
resultMap的extends屬性:能夠用此屬性來繼承一個已有的resultmap。可是它繼承的resultMap的type和它自己的type要保持一致。
(4)編寫測試代碼
@Test
public void testFindOrdersAndOrderdetailResultMap() {
// 根據SqlSessionFactory建立SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 建立OrdersMapper對象
// 由Mybatis經過sqlSession來建立動態代理對象
OrdersMapper mapper = sqlSession.getMapper(OrdersMapper.class);
List<OrdersExt> list = mapper.findOrdersAndOrderdetailResultMap();
System.out.println(list);
sqlSession.close();
}
sql語句以下:
SELECT
orders.id orders_id,
orders.user_id,
orders.number orders_number,
user.username user_username,
user.sex user_sex,
orderdetail.id detail_id,
orderdetail.items_id,
orderdetail.items_num,
items.name items_name,
items.price items_price
FROM
orders,
user,
orderdetail,
items
WHERE user.id = orders.user_id
AND orders.id = orderdetail.orders_id
AND orderdetail.items_id = items.id;
(1)修改擴展PO類
在UserExt類中添加List<Orders>屬性
// 添加訂單列表
private List<Orders> ordersList;
在OrdersExt類中添加List<Orderdetail>屬性
// 訂單明細信息
private List<Orderdetail> detailList;
在OrderdetailExt類中添加Items屬性
// 添加商品信息
private Items items;
(2)編寫mapper接口
在UserMapper.java中,添加如下內容:
// 多對多映射之 resultMap
// 查詢用戶信息,關聯查詢該用戶購買的商品信息
public List<UserExt> findUserAndItemsResultMap();
(3)編寫映射文件
在UserMapper.xml中,添加如下內容:
<!-- 聲明/定義一個resultMap -->
<resultMap type="com.itheima.mybatis.po.UserExt" id="UserAndItemsResultMap">
<!-- 用戶信息映射-->
<id column="user_id" property="id"/>
<result column="user_username" property="username"/>
<result column="user_sex" property="sex"/>
<!-- 訂單信息映射(一對多) -->
<collection property="ordersList" ofType="com.itheima.mybatis.po.OrdersExt">
<id column="orders_id" property="id"/>
<result column="user_id" property="userId"/>
<result column="orders_number" property="number"/>
<!-- 訂單明細信息映射(一對多) -->
<collection property="detailList" ofType="com.itheima.mybatis.po.OrderdetailExt">
<id column="detail_id" property="id"/>
<result column="items_id" property="itemsId"/>
<result column="items_num" property="itemsNum"/>
<!-- 商品信息映射(一對一) -->
<association property="items" javaType="com.itheima.mybatis.po.Items">
<id column="items_id" property="id"/>
<result column="items_name" property="name"/>
<result column="items_price" property="price"/>
</association>
</collection>
</collection>
</resultMap>
<!-- 多對多映射之 resultMap -->
<!-- 查詢用戶信息,關聯查詢該用戶購買的商品信息 -->
<select id="findUserAndItemsResultMap" resultMap="UserAndItemsResultMap">
SELECT
orders.id orders_id,
orders.user_id,
orders.number orders_number,
user.username user_username,
user.sex user_sex,
orderdetail.id detail_id,
orderdetail.items_id,
orderdetail.items_num,
items.name items_name,
items.price items_price
FROM
orders,
user,
orderdetail,
items
WHERE user.id = orders.user_id
AND orders.id = orderdetail.orders_id
AND orderdetail.items_id = items.id
</select>
(4)編寫測試代碼
在UserMapperTest.java中,添加如下內容:
@Test
public void testFindUserAndItemsResultMap() {
// 根據SqlSessionFactory建立SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 建立UserMapper對象
// 由Mybatis經過sqlSession來建立動態代理對象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<UserExt> list = mapper.findUserAndItemsResultMap();
System.out.println(list);
sqlSession.close();
}
resultType:
做用:
將查詢結果按照sql列名pojo屬性名一致性映射到pojo中。
場合:
常見一些明細記錄的展現,好比用戶購買商品明細,將關聯查詢信息所有展現在頁面時,此時可直接使用resultType將每一條記錄映射到pojo中,在前端頁面遍歷list(list中是pojo)便可。
------------------------------------------------------------
resultMap:
使用association和collection完成一對一和一對多高級映射(對結果有特殊的映射要求)。
------------------------------------------------------------
association:
做用:
將關聯查詢信息映射到一個pojo對象中。
場合:
爲了方便查詢關聯信息可使用association將關聯訂單信息映射爲用戶對象的pojo屬性中,好比:查詢訂單及關聯用戶信息。
使用resultType沒法將查詢結果映射到pojo對象的pojo屬性中,根據對結果集查詢遍歷的須要選擇使用resultType仍是resultMap。
------------------------------------------------------------
collection:
做用:
將關聯查詢信息映射到一個list集合中。
場合:
爲了方便查詢遍歷關聯信息可使用collection將關聯信息映射到list集合中,好比:查詢用戶權限範圍模塊及模塊下的菜單,可以使用collection將模塊映射到模塊list中,將菜單列表映射到模塊對象的菜單list屬性中,這樣的作的目的也是方便對查詢結果集進行遍歷查詢。
若是使用resultType沒法將查詢結果映射到list集合中。
按需加載
關聯信息。這樣會大大提升數據庫性能,由於查詢單表要比關聯查詢多張錶速度要快。標籤中開啓延遲加載
功能。配置圖以下:
查詢訂單而且關聯查詢用戶信息(對用戶信息的加載要求是按需加載)
(1)編寫mapper接口
在OrdersMapper.xml文件中,添加如下內容:
// 延時加載
public List<OrdersExt> findOrderAndUserLazyLoading();
(2)編寫映射文件
編寫查詢訂單信息的映射文件
<!-- 定義一個 resultMap-->
<resultMap type="com.itheima.mybatis.po.OrdersExt" id="OrderAndUserLazyLoading">
<!-- 訂單信息映射 -->
<id column="id" property="id"/>
<result column="user_id" property="userId"/>
<result column="number" property="number"/>
<!-- 用戶信息映射(一對一) -->
<!-- select:指定關聯查詢的查詢statement(即查詢用戶的statement的id),而後將查詢結果,封裝到property屬性指定的變量中 -->
<!-- column:經過column指定的列所查詢出的結果,做爲select指的statement的入參
注意:若是select指定的statement,入參須要多個值,須要在column中{col1=prop1,col2=prop2}
-->
<association property="com.itheima.mybatis.po.User"
select="com.itheima.mybatis.mapper.UserMapper.findUserById"
column="user_id">
</association>
</resultMap>
<!-- 延時加載 -->
<select id="findOrderAndUserLazyLoading" resultMap="OrderAndUserLazyLoading">
SELECT * FROM orders
</select>
編寫查詢用戶信息的映射文件
<!-- 根據用戶ID,查詢用戶信息 -->
<select id="findUserById" parameterType="int" resultType="com.itheima.mybatis.po.User">
SELECT * FROM USER WHERE id = #{id}
</select>
(3)編寫測試代碼
@Test
public void testFindOrdersAndUserLazyLoading() {
// 根據SqlSessionFactory建立SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 建立OrdersMapper對象
// 由Mybatis經過sqlSession來建立動態代理對象
OrdersMapper mapper = sqlSession.getMapper(OrdersMapper.class);
List<OrdersExt> list = mapper.findOrdersAndUserLazyLoading(); // n+1現象,是因爲沒有使用延時加載而致使的
for (OrdersExt order : list) {
System.out.println(order.getUser()); // 按需加載時,須要的時候再去查詢數據庫
}
sqlSession.close();
}
(4)設置延遲加載
在SqlMapConfig.xml中,配置settings標籤,注意該標籤的位置
<settings>
<!-- 開啓延遲加載,默認值爲true,即默認是當即加載 -->
<setting name="lazyLoadingEnabled" value="true"/>
<!-- 設置積極的懶加載,默認值是true,false的是按需加載 -->
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
第一次發起查詢用戶id爲1的用戶信息,先去找緩存中是否有id爲1的用戶信息,若是沒有,從數據庫查詢用戶信息。
獲得用戶信息,將用戶信息存儲到一級緩存中。
若是SqlSession去執行commit操做(執行插入、更新、刪除),會清空SqlSession中的一級緩存,
這樣作的目的爲了讓緩存中存儲的是最新的信息,避免髒讀。
第二次發起查詢用戶id爲1的用戶信息,先去找緩存中是否有id爲1的用戶信息,緩存中有,直接從緩存中獲取用戶信息。
Mybatis默認支持一級緩存。
@Test
public void testOneLevelCache() {
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
// 第一次查詢ID爲1的用戶,去緩存找,找不到就去查找數據庫
User user1 = mapper.findUserById(1);
System.out.println(user1);
// 第二次查詢ID爲1的用戶
User user2 = mapper.findUserById(1);
System.out.println(user2);
sqlSession.close();
}
只輸出一次SQL,以下圖所示:
@Test
public void testOneLevelCache() {
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
// 第一次查詢ID爲1的用戶,去緩存找,找不到就去查找數據庫
User user1 = mapper.findUserById(1);
System.out.println(user1);
User user = new User();
user.setUsername("曉藝");
user.setAddress("物資學院");
// 執行增刪改操做,清空緩存
mapper.insertUser(user);
sqlSession.commit();
// 第二次查詢ID爲1的用戶
User user2 = mapper.findUserById(1);
System.out.println(user2);
sqlSession.close();
}
中間執行了commit操做,一樣的查詢SQL輸出兩次,以下圖所示:
例如:
service {
// 開始執行時,開啓事務,建立SqlSession對象
// 第一次調用mapper的方法findUserById(1)
// 第二次調用mapper的方法findUserById(1),從一級緩存中取數據
// 方法結束,sqlSession關閉
}
若是是執行兩次service調用查詢相同的用戶信息,不走一級緩存,由於session方法結束,SqlSession就關閉,一級緩存就清空了。
上圖詳解以下:
二級緩存是mapper級別的。
第一次調用mapper下的SQL去查詢用戶信息。查詢到的信息會存到該mapper對應的二級緩存區域內。
第二次調用相同namespace下的mapper映射文件中相同的SQL去查詢用戶信息。會去對應的二級緩存內取結果。
若是調用相同namespace下的mapper映射文件中的增刪改SQL,並執行了commit操做。此時會清空該namespace下的二級緩存。
Mybatis默認是沒有開啓二級緩存的。
一、在覈心配置文件SqlMapConfig.xml中加入如下內容(開啓二級緩存總開關):
在settings標籤中添加如下內容:
<!-- 開啓二級緩存總開關 -->
<setting name="cacheEnabled" value="true"/>
二、在UserMapper映射文件中,加入如下內容,開啓二級緩存:
<!-- 開啓本mapper下的namespace的二級緩存,默認使用的是mybatis提供的PerpetualCache -->
<cache></cache>
@Test
public void testTwoLevelCache() {
SqlSession sqlSession1 = sqlSessionFactory.openSession();
SqlSession sqlSession2 = sqlSessionFactory.openSession();
SqlSession sqlSession3 = sqlSessionFactory.openSession();
UserMapper mapper1 = sqlSession1.getMapper(UserMapper.class);
UserMapper mapper2 = sqlSession2.getMapper(UserMapper.class);
UserMapper mapper3 = sqlSession3.getMapper(UserMapper.class);
// 第一次查詢ID爲1的用戶,去緩存找,找不到就去查找數據庫
User user1 = mapper1.findUserById(1);
System.out.println(user1);
// 關閉SqlSession1,在close的時候,纔會將數據寫入到二級緩存中
sqlSession1.close();
// 第二次查詢ID爲1的用戶
User user2 = mapper2.findUserById(1);
System.out.println(user2);
// 關閉SqlSession2
sqlSession2.close();
// 關閉SqlSession3
sqlSession3.close();
}
SQL輸出結果,以下圖所示:
@Test
public void testTwoLevelCache() {
SqlSession sqlSession1 = sqlSessionFactory.openSession();
SqlSession sqlSession2 = sqlSessionFactory.openSession();
SqlSession sqlSession3 = sqlSessionFactory.openSession();
UserMapper mapper1 = sqlSession1.getMapper(UserMapper.class);
UserMapper mapper2 = sqlSession2.getMapper(UserMapper.class);
UserMapper mapper3 = sqlSession3.getMapper(UserMapper.class);
// 第一次查詢ID爲1的用戶,去緩存找,找不到就去查找數據庫
User user1 = mapper1.findUserById(1);
System.out.println(user1);
// 關閉SqlSession1,在close的時候,纔會將數據寫入到二級緩存中
sqlSession1.close();
User user = new User();
user.setUsername("曉藝");
user.setAddress("物資學院");
// 執行增刪改操做,清空緩存
mapper3.insertUser(user);
sqlSession3.commit();
// 第二次查詢ID爲1的用戶
User user2 = mapper2.findUserById(1);
System.out.println(user2);
// 關閉SqlSession2
sqlSession2.close();
// 關閉SqlSession3
sqlSession3.close();
}
SQL輸出結果,以下圖所示:
根據SQL分析,確實是清空了二級緩存了。
userCache=false
,能夠禁用當前select語句的二級緩存,即每次查詢都是去數據庫中查詢,默認狀況下是true,即該statement使用二級緩存。以下代碼所示: <select id="findUserById" parameterType="int" resultType="com.itheima.mybatis.po.User" useCache="true">
SELECT * FROM USER WHERE id = #{id}
</select>
flushCache=true
能夠刷新當前的二級緩存,默認狀況下:flushCache設置以下:
<select id="findUserById" parameterType="int" resultType="com.itheima.mybatis.po.User" useCache="true" flushCache="false">
SELECT * FROM USER WHERE id = #{id}
</select>
(1)什麼是分佈式緩存?
(2)整合思路(重點)
Mybatis提供了一個Cache接口,同時它本身有一個默認的實現類PerpetualCache
。mybatis的特長是sql
,緩存數據管理不是mybatis的特長,爲了提升mybatis的性能,因此須要mybatis和第三方緩存數據庫整合,好比ehcache、memcache、redis等。(3)整合ehcache的步驟
第一步:引入ehcache的jar包,並添加至構建路徑
<!-- 開啓本mapper下的namespace的二級緩存,默認使用的是mybatis提供的PerpetualCache -->
<cache type="org.mybatis.caches.ehcache.EhcacheCache"></cache>
第三步:添加ehcache的配置文件
在classpath下的config目錄下,添加ehcache.xml,內容以下:
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
<!-- 緩存數據要存放的磁盤地址 -->
<diskStore path="e:\others\develop\ehcache" />
<!-- diskStore:指定數據在磁盤中的存儲位置。
defaultCache:當藉助CacheManager.add("demoCache")建立Cache時,EhCache便會採用<defalutCache/>指定的的管理策略
如下屬性是必須的:
maxElementsInMemory - 在內存中緩存的element的最大數目
maxElementsOnDisk - 在磁盤上緩存的element的最大數目,如果0表示無窮大
eternal - 設定緩存的elements是否永遠不過時。若是爲true,則緩存的數據始終有效,若是爲false,那麼還要根據timeToIdleSeconds,timeToLiveSeconds判斷
overflowToDisk - 設定當內存緩存溢出的時候是否將過時的element緩存到磁盤上 如下屬性是可選的:
timeToIdleSeconds - 當緩存在EhCache中的數據先後兩次訪問的時間超過timeToIdleSeconds的屬性取值時,這些數據便會刪除,默認值是0,也就是可閒置時間無窮大
timeToLiveSeconds - 緩存element的有效生命期,默認是0,也就是element存活時間無窮大
diskSpoolBufferSizeMB - 這個參數設置DiskStore(磁盤緩存)的緩存區大小,默認是30MB。每一個Cache都應該有本身的一個緩衝區
diskPersistent - 在VM重啓的時候是否啓用磁盤保存EhCache中的數據,默認是false
diskExpiryThreadIntervalSeconds - 磁盤緩存的清理線程運行間隔,默認是120秒。每隔120s,相應的線程會進行一次EhCache中數據的清理工做
memoryStoreEvictionPolicy - 當內存緩存達到最大,有新的element加入的時候, 移除緩存中element的策略。默認是LRU(最近最少使用),可選的有LFU(最不常使用)和FIFO(先進先出)
-->
<defaultCache maxElementsInMemory="1000"
maxElementsOnDisk="10000000"
eternal="false"
overflowToDisk="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU">
</defaultCache>
</ehcache>
第四步:測試ehcache的二級緩存,經過查看緩存命中率
對於訪問響應速度要求高,可是實時性不高的查詢,能夠採用二級緩存技術
。細粒度的數據級別
的緩存實現很差。由於二級緩存是mapper級別的,當一個商品的信息發送更新,全部的商品信息緩存數據都會清空
。能夠對常常變化的數據操做單獨放到另外一個namespace的mapper中
。Jar包以下(一共28個):
Mybatis3.2.7 的jar包(mybatis核心包、依賴包)
在config下,建立mybatis目錄,而後建立SqlMapConfig.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 自定義別名 -->
<typeAliases>
<!-- 單個定義別名 -->
<!-- <typeAlias type="com.itheima.mybatis.po.User" alias="user"/> -->
<!-- 批量定義別名(推薦) -->
<!-- name:指定批量定義別名的類包,別名爲類名(首字母大小寫均可) -->
<package name="com.itheima.ms.po"/>
</typeAliases>
<!-- 注意:與spring集成後,數據源和事務交給spring來管理 -->
<!-- 加載mapper,即加載映射文件 -->
<mappers>
<!-- 使用相對於類路徑的資源,加載配置文件,後面講課用:爲了驗證原始dao的實現方式 -->
<mapper resource="mybatis/sqlmap/User.xml"/>
<!-- 推薦使用:批量加載mapper文件,須要mapper接口文件和mapper映射文件名稱相同且在同一個包下 -->
<!-- 由spring來管理原始dao的實現類或者mapper代理的代理類,spring代理的時候,會自動將映射文件加載進去 -->
<package name="com.itheima.ms.mapper"/>
</mappers>
</configuration>
將db.properties和log4j.properties拷貝到config目錄下。
在config下,建立spring目錄,而後建立applicationContext.xml,內容以下:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.2.xsd ">
<!-- 引用/加載java配置文件 -->
<context:property-placeholder location="db.properties"/> <!-- java工程不須要指定classpath,web工程須要指定 classpath-->
<!-- 配置數據源,使用dbcp數據庫鏈接池 -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${db.driver}"/>
<property name="url" value="${db.url}"/>
<property name="username" value="${db.username}"/>
<property name="password" value="${db.password}"/>
<property name="maxActive" value="10"/>
<property name="maxIdle" value="5"/>
</bean>
<!-- 配置spring對SqlSessionFactory進行管理 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 指定mybatis的全局配置文件的路徑 -->
<property name="configLocation" value="mybatis/SqlMapConfig.xml"></property>
<!-- SqlSessionFactory須要數據源信息,以前是寫在sqlmapconfig.xml,如今須要從新指定 -->
<property name="dataSource" ref="dataSource"></property>
</bean>
</beans>
(1)編寫dao接口
public interface UserDao {
// 根據用戶ID來查詢用戶信息
public User findUserById(int id);
}
(2)編寫dao實現類(繼承SqlSessionDaoSupport)
經過this.getSqlSession()獲取sqlsession。
public class UserDaoImpl extends SqlSessionDaoSupport implements UserDao {
@Override
public User findUserById(int id) {
return this.getSqlSession().selectOne("test.findUserById", id);
}
}
(3)編寫Mapper映射文件
在config/mybatis下建立sqlmap目錄,而後建立User.xml
<?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="test">
<!-- 根據用戶ID,查詢用戶信息 -->
<select id="findUserById" parameterType="int" resultType="user">
SELECT * FROM USER WHERE id = #{id}
</select>
</mapper>
(4)在spring配置文件中配置UserDao實現類
在applicationContext.xml中配置UserDao的實現類
<!-- 配置spring管理原始dao的實現 -->
<bean id="userDao" class="com.itheima.ms.dao.UserDaoImpl">
<!-- 依賴注入sqlSessionFactory,由於UserDao的實現類繼承 了SqlSessionDaoSupport-->
<property name="sqlSessionFactory" ref="sqlSessionFactory"></property>
</bean>
(5)編寫測試代碼
package com.itheima.ms.dao;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.itheima.ms.po.User;
public class UserDaoTest {
// spring上下文
private ApplicationContext ctx;
@Before
public void setUp() throws Exception {
// 讀取spring的上下文,而後封裝到ctx
ctx = new ClassPathXmlApplicationContext("spring/applicationContext.xml");
}
@Test
public void testFindUserById() {
// 建立UserDao對象
UserDao userDao = (UserDao) ctx.getBean("userDao");
// 調用UserDao對象的方法
User user = userDao.findUserById(30);
System.out.println(user);
}
}
(1)編寫mapper接口
public interface UserMapper {
// 根據用戶ID來查詢用戶信息
public User findUserById(int id);
}
(2)編寫mapper映射文件
將映射文件放到UserMapper接口的同包下
UserMapper.xml
<?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="com.itheima.ms.mapper.UserMapper">
<!-- 根據用戶ID,查詢用戶信息 -->
<select id="findUserById" parameterType="int" resultType="user">
SELECT * FROM USER WHERE id = #{id}
</select>
</mapper>
(3)配置mapper代理類
在spring中定義bean,Mapper代理開發方式有兩種bean的定義方法,一種是MapperFactoryBean
,一種是MapperScannerConfigurer(推薦)
。
<!-- mapper代理開發方式之單個mapper配置 -->
<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
<!-- 設置代理類的接口 -->
<property name="mapperInterface" value="com.itheima.ms.mapper.UserMapper"></property>
<!-- 依賴注入sqlSessionFactory,由於 MapperFactoryBean也繼承了SqlSessionDaoSupport-->
<property name="sqlSessionFactory" ref="sqlSessionFactory"></property>
</bean>
<!-- mapper代理開發方式之批量mapper配置,默認bean的id爲類名首字母小寫 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!-- 指定批量mapper配置的包名 -->
<property name="basePackage" value="com.itheima.ms.mapper"></property>
<!-- 當只有一個SqlSessionFactory時,默認是不須要配置SqlSessionFactory的 -->
<!-- 當有多個SqlSessionFactory時,能夠指定使用的SqlSessionFactory -->
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
</bean>
(4)編寫測試代碼
package com.itheima.ms.mapper;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.itheima.ms.po.User;
public class UserMapperTest {
// spring上下文
private ApplicationContext ctx;
@Before
public void setUp() throws Exception {
// 讀取spring的上下文,而後封裝到ctx
ctx = new ClassPathXmlApplicationContext("spring/applicationContext.xml");
}
@Test
public void testFindUserById() {
// 建立UserMapper對象
UserMapper userMapper = (UserMapper) ctx.getBean("userMapper");
// 調用UserMapper對象的方法
User user = userMapper.findUserById(30);
System.out.println(user);
}
}
單表
,自動生成java代碼。 在config下,建立generatorConfig.xml配置文件:
文件內容能夠從逆向工程的jar包中docs目錄下的index.html中找到相關代碼
文件內容位置:mybatis-generator-core-1.3.2/docs/configreference/xmlconfig.html
<?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="testTables" targetRuntime="MyBatis3">
<commentGenerator>
<!-- 是否去除自動生成的註釋 true:是,false:否 -->
<property name="suppressAllComments" value="true" />
</commentGenerator>
<!--MySql數據庫鏈接的信息:驅動類、鏈接地址、用戶名、密碼 -->
<jdbcConnection
driverClass="com.mysql.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/mybatis"
userId="root"
password="root">
</jdbcConnection>
<!-- Oracle數據庫鏈接的信息:驅動類、鏈接地址、用戶名、密碼 -->
<!--
<jdbcConnection
driverClass="oracle.jdbc.OracleDriver"
connectionURL="jdbc:oracle:thin:@127.0.0.1:1521:yycg"
userId="yycg"
password="yycg">
</jdbcConnection>
-->
<!-- 默認 false時,把JDBC DECIMAL 和 NUMERIC 類型解析爲 Integer
設置爲true時,把JDBC DECIMAL 和 NUMERIC 類型解析爲 java.math.BigDecimal
-->
<javaTypeResolver>
<property name="forceBigDecimals" value="false" />
</javaTypeResolver>
<!-- targetProject:生成PO類的位置 -->
<javaModelGenerator targetPackage="com.itheima.ms.po" targetProject=".\src">
<!-- enableSubPackages:是否讓schema做爲包的後綴 -->
<property name="enableSubPackages" value="false" />
<!-- 從數據庫返回的值被清理先後的空格 -->
<property name="trimStrings" value="true" />
</javaModelGenerator>
<!-- targetProject:mapper映射文件生成的位置 -->
<sqlMapGenerator targetPackage="com.itheima.ms.mapper" targetProject=".\src">
<!-- enableSubPackages:是否讓schema做爲包的後綴 -->
<property name="enableSubPackages" value="false" />
</sqlMapGenerator>
<!-- targetPackage:mapper接口生成的位置 -->
<javaClientGenerator type="XMLMAPPER" targetPackage="com.itheima.ms.mapper" targetProject=".\src">
<!-- enableSubPackages:是否讓schema做爲包的後綴 -->
<property name="enableSubPackages" value="false" />
</javaClientGenerator>
<!-- 指定要生成mybatis代碼的數據庫表 -->
<table tableName="items"></table>
<table tableName="orders"></table>
<table tableName="orderdetail"></table>
<table tableName="user"></table>
</context>
</generatorConfiguration>
文件內容位置:mybatis-generator-core-1.3.2/docs/running/runningWithJava.html
Generator.java
public class Generator {
public static void main(String[] args) throws Exception {
List<String> warnings = new ArrayList<String>();
boolean overwrite = true;
File configFile = new File("config/generatorConfig.xml");
ConfigurationParser cp = new ConfigurationParser(warnings);
Configuration config = cp.parseConfiguration(configFile);
DefaultShellCallback callback = new DefaultShellCallback(overwrite);
MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);
myBatisGenerator.generate(null);
}
}
小問題:經過逆向工程生成的代碼會有一個報錯,是由於缺乏mybatis的jar包致使的,雖然不影響咱們使用,可是爲了好看,咱們導入mybatis-3.2.7.jar,並添加至構建路徑,便可解決問題。
小需求:根據商品名稱查詢商品記錄
public class ItemsMapperTest {
// spring上下文
private ApplicationContext ctx;
@Before
public void setUp() throws Exception {
// 讀取spring的上下文,而後封裝到ctx
ctx = new ClassPathXmlApplicationContext("spring/applicationContext.xml");
}
@Test
public void testSelectByExample() {
// 建立ItemsMapper對象
ItemsMapper itemsMapper = (ItemsMapper) ctx.getBean("itemsMapper");
ItemsExample example = new ItemsExample();
// 使用ItemsExample對象建立離線查詢對象
Criteria criteria = example.createCriteria();
// 使用離線查詢對象Criteria來封裝查詢條件
criteria.andNameLike("%包%"); // 由於模糊查詢的實現和等值查詢的實現式同樣的,用到的都是#{xxx},因此須要咱們手動添加%
// 調用ItemsMapper對象的方法
List<Items> list = itemsMapper.selectByExample(example);
System.out.println(list);
}
}
SQL輸出結果,以下圖所示:
刪除原來已經生成的mapper.xml文件再進行生成。