Mybatis--day02

非本人總結(jié)的筆記,抄點(diǎn)筆記復(fù)習(xí)復(fù)習(xí)岁疼。感謝傳智博客及黑馬程序猿
成長(zhǎng)

關(guān)聯(lián)查詢

數(shù)據(jù)中的表結(jié)構(gòu)

數(shù)據(jù)庫(kù)的分析方法

第一步:確定單表存儲(chǔ)的是什么內(nèi)容。
第二步:確定每個(gè)表中的關(guān)鍵字段缆娃。不能為null的字段捷绒。
第三步:確定表和表之間數(shù)據(jù)庫(kù)層面的關(guān)系。外鍵關(guān)系贯要。
第四步:從業(yè)務(wù)層面分析表和表之間的關(guān)系暖侨。

訂單--商品模型分析

第一步:

User:客戶表。存儲(chǔ)的是購(gòu)買商品的用戶信息崇渗。

Orders:訂單表字逗。存儲(chǔ)的就是用戶生成的訂單。

OrderDetail:訂單明細(xì)表宅广。保存的是每個(gè)訂單的明細(xì)葫掉。

Items:商品表。保存的是商品信息跟狱。

第二步:

User:id:主鍵俭厚。Username:用戶名

Orders:id主鍵。user_id:用戶id(外鍵)

Orderdetail:id主鍵驶臊。orders_id:訂單的id(外鍵)挪挤。items_id:商品id(外鍵)

Items:id主鍵。Name商品名稱关翎。Price商品價(jià)格扛门。Createtime生成日期。

第三步:

關(guān)系

第四步:從業(yè)務(wù)層面分析表和表之間的關(guān)系

用戶→訂單:一個(gè)用戶可以下多個(gè)訂單笤休。一對(duì)多

訂單→用戶:一個(gè)訂單只屬于一個(gè)用戶尖飞。一對(duì)一

訂單→訂單明細(xì):一個(gè)訂單包含多個(gè)明細(xì)。一對(duì)多

訂單明細(xì)→訂單:一個(gè)訂單明細(xì)只屬于一個(gè)訂單。

訂單明細(xì)→商品:一個(gè)訂單明細(xì)對(duì)應(yīng)一個(gè)商品政基。一對(duì)一

商品→訂單明細(xì):一個(gè)商品可以被多個(gè)明細(xì)對(duì)應(yīng)贞铣。一對(duì)多

用戶→商品:一對(duì)多

商品→用戶:一對(duì)多

一對(duì)一查詢

Sql語(yǔ)句

SELECT o.id, user_id, number, createtime, note, username, birthday, sex, address FROM orderso JOIN USER u ON o.user_id = u.id

使用resultType實(shí)現(xiàn)

定義一個(gè)POJO

和sql語(yǔ)句的結(jié)果集對(duì)應(yīng)

public class OrderUser extends Orders {
    //用戶相關(guān)的字段
    private String username;
    private String sex;
    private Date birthday;
    private String address;
    //set和get方法省略
}

Mapper文件

<?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.itcast.mapper.OrderMapper">
    <select id="getOrderWithUser" resultType="orderuser">
        SELECT
            o.id,
            user_id,
            number,
            createtime,
            note,
            username,
            birthday,
            sex,
            address
        FROM
            orders o
        JOIN USER u ON o.user_id = u.id
    </select>
</mapper>

接口定義

public interface OrderMapper{
    List<OrderUser> getOrderWithUser();
}

測(cè)試方法

@Test
public void testGetOrderWithUser() {
    SqlSession sqlSession = sessionFactory.openSession();
    OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class);
    List<OrderUser> orderUserList = orderMapper.getOrderWithUser();
    System.out.println(orderUserList);
    sqlSession.close();
}

使用ResultMap實(shí)現(xiàn)

定義一個(gè)POJO

在orders POJO中添加一個(gè)User屬性,保存用戶信息

public class Orders {
    private Integer id;
    private Integer userId;
    private String number;
    private Date createtime;
    private User user;
    //省略get和set方法
}

Mapper文件

<!-- 使用resultMap實(shí)現(xiàn)一對(duì)一映射 -->
<resultMap type="orders" id="orderUserResultMap">
    <!-- order表的主鍵 -->
    <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"/>
    <!-- 用戶表的映射關(guān)系 -->
    <!-- 使用association做一對(duì)一關(guān)聯(lián)映射 -->
    <!-- property屬性就是pojo中要進(jìn)行一對(duì)一關(guān)聯(lián)的屬性
     javaType:指定一對(duì)一關(guān)聯(lián)屬性的類型沮明,可以使用別名辕坝。
     -->
    <association property="user" javaType="cn.itcast.pojo.User">
      <!-- user表的主鍵 -->
      <id column="user_id" property="id"/>
      <!-- 普通列 -->
      <result column="username" property="username"/>
      <result column="birthday" property="birthday"/>
      <result column="sex" property="sex"/>
      <result column="address" property="address"/>
    </association>
</resultMap>
<select id="getOrderWithUserResultMap" resultMap="orderUserResultMap">
      SELECT
      o.id,
      user_id,
      number,
      createtime,
      note,
      username,
      birthday,
      sex,
      address
      FROM
      orders o
      JOIN USER u ON o.user_id = u.id
</select>

接口定義

public interface OrderMapper{
    List<Orders> getOrderWithUserResultMap();
}

測(cè)試方法

@Test
public void testGetOrderWithUserResultMap() throws Exception {
    SqlSession sqlSession = sessionFactory.openSession();
    OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class);
    List<Orders> list = orderMapper.getOrderWithUserResultMap();
    System.out.println(list);
    sqlSession.close();
}

小結(jié)

一對(duì)一映射可以有兩種方法,一種是使用resultType荐健,根據(jù)sql語(yǔ)句返回的結(jié)果集創(chuàng)建一pojo類來接收結(jié)果集酱畅。

使用resultMap實(shí)現(xiàn),需要配置一個(gè)resultmap使用association 來配置映射關(guān)系江场。

實(shí)際開發(fā)中resultType用的多纺酸。

一對(duì)多查詢

訂單到訂單明細(xì)是一對(duì)多的關(guān)系。

Sql語(yǔ)句

SELECT o.id, user_id, number, createtime, note, username, birthday, sex, address, od.iddetail_id, od.items_id, od.items_num FROM orderso JOIN USER u ON o.user_id = u.id JOIN orderdetail od ON o.id = od.orders_id

定義一個(gè)POJO

在orders中添加List<OrderDetail>屬性址否,保存訂單明細(xì)列表

public class Orders{
    private Integer id;
    private Integer userId;
    private String number;
    private Date createtime;
    private String note;
    private List<OrderDetail> detailList;
    //省略set和get方法
}

Mapper文件

<!-- 一對(duì)多管理映射使用ResultMap實(shí)現(xiàn) -->
<!-- resultMap定義 -->
<!-- resultMap之間可以使用extends繼承 -->
<resultMap type="orders" id="orderDetailResultMap" extends="orderUserResultMap">
     <!-- 配置一對(duì)多映射關(guān)系 -->
     <!-- property一對(duì)多關(guān)系映射的屬性 -->
     <!-- ofType:指定列表中元素的數(shù)據(jù)類型 -->
     <collection property="detailList" ofType="cn.itcast.pojo.Orderdetail">
        <!-- 訂單明細(xì)表的id -->
        <id column="detail_id" property="id"/>
        <!-- 普通列 -->
        <result column="items_id" property="itemsId"/>
        <result column="items_num" property="itemsNum"/>
        <result column="id" property="ordersId"/>
     </collection>
</resultMap>
<select id="getOrderWithDetail" resultMap="orderDetailResultMap">
    SELECT
    o.id,
    user_id,
    number,
    createtime,
    note,
    username,
    birthday,
    sex,
    address,
    od.id detail_id,
    od.items_id,
    od.items_num
    FROM
    orders o
    JOIN USER u ON o.user_id = u.id
    JOIN orderdetail od ON o.id = od.orders_id
</select>

接口定義

public interface OrderMapper{
    List<Orders> getOrderWithDetail();
}

測(cè)試方法

@Test
public void testGetOrderWithDetail() throws Exception {
    SqlSession sqlSession = sessionFactory.openSession();
    OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class);
    List<Orders> list = orderMapper.getOrderWithDetail();       System.out.println(list);
    sqlSession.close();
}

一對(duì)多復(fù)雜

需求

查詢訂單關(guān)聯(lián)訂單明細(xì)餐蔬,商品明細(xì)要關(guān)聯(lián)商品信息。

Sql語(yǔ)句

SELECT o.id, o.user_id, o.number, o.createtime, o.note, u.username, u.birthday, u.sex, u.address, od.iddetail_id, od.items_id, od.items_num, i.name, i.pic, i.price, i.createtimectime FROM orderso JOIN USER u ON o.user_id = u.id JOIN orderdetail od ON o.id = od.orders_id JOINitems i ON od.items_id = i.id

定義一個(gè)POJO

在Orderdetail中添加一個(gè)Items屬性佑附,保存商品信息樊诺。

public class Orderdetail{
    private Integer id;
    private Integer ordersId;
    private Integer itemsId;
    private Integer itemNum;
    private Items items;
    //省略set和get方法
}

Mapper文件

<!-- 一對(duì)多復(fù)雜 -->
<!-- 定義一個(gè)ResultMap -->
<resultMap type="Orders" id="orderWithDetailWithItemsResultMap" extends="orderUserResultMap">
    <!-- 配置一對(duì)多映射關(guān)系 -->
    <!-- property一對(duì)多關(guān)系映射的屬性 -->
    <!-- ofType:指定列表中元素的數(shù)據(jù)類型 -->
    <collection property="detailList" ofType="cn.itcast.pojo.Orderdetail">
        <!-- 訂單明細(xì)表的id -->
        <id column="detail_id" property="id"/>
        <!-- 普通列 -->
        <result column="items_id" property="itemsId"/>
        <result column="items_num" property="itemsNum"/>
        <result column="id" property="ordersId"/>
        <!-- 訂單明細(xì)一對(duì)一關(guān)聯(lián)商品信息 -->
        <association property="items" javaType="cn.itcast.pojo.Items">
            <!-- 商品表的主鍵 -->
            <id column="items_id" property="id"/>
            <!-- 普通列 -->
            <result column="name" property="name"/>
            <result column="pic" property="pic"/>
            <result column="price" property="price"/>
            <result column="ctime" property="createtime"/>
        </association>
    </collection>
</resultMap>
<select id="getOrderWithDetailWithItems" resultMap="orderWithDetailWithItemsResultMap">
    SELECT
        o.id,
        o.user_id,
        o.number,
        o.createtime,
        o.note,
        u.username,
        u.birthday,
        u.sex,
        u.address,
        od.id detail_id,
        od.items_id,
        od.items_num,
        i.`name`,
        i.pic,
        i.price,
        i.createtime ctime
    FROM
        orders o
    JOIN USER u ON o.user_id = u.id
    JOIN orderdetail od ON o.id = od.orders_id
    JOIN items i ON od.items_id = i.id
</select>

接口方法定義

public interface OrderMapper{
    List<Orders> getOrderWithDetailWithItems();
}

測(cè)試方法

@Test
public void testGetOrderWithDetailWithItems() throws Exception {
    SqlSession sqlSession = sessionFactory.openSession();
    OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class);
    List<Orders> list = orderMapper.getOrderWithDetailWithItems();
    System.out.println(list);
    sqlSession.close();
}

多對(duì)多關(guān)聯(lián)映射

如下需求:

查詢用戶購(gòu)買的商品信息,用戶和商品的關(guān)系是多對(duì)多關(guān)系音同。

需求1:

查詢顯示字段:用戶賬號(hào)词爬、用戶名稱、用戶性別权均、商品名稱顿膨、商品價(jià)格(最常見)

企業(yè)開發(fā)中常見明細(xì)列表,用戶購(gòu)買商品明細(xì)列表螺句,

使用resultType將上邊查詢列映射到pojo輸出虽惭。

需求2:

查詢顯示字段:用戶賬號(hào)、用戶名稱蛇尚、購(gòu)買商品數(shù)量芽唇、商品明細(xì)(鼠標(biāo)移上顯示明細(xì))

使用resultMap將用戶購(gòu)買的商品明細(xì)列表映射到user對(duì)象中。

其實(shí)是一個(gè)一對(duì)多的映射關(guān)系

延遲加載

需要查詢關(guān)聯(lián)信息時(shí)取劫,使用mybatis延遲加載特性可有效的減少數(shù)據(jù)庫(kù)壓力匆笤,首次查詢只查詢主要信息,關(guān)聯(lián)信息等用戶獲取時(shí)再加載谱邪。
在mybatis中默認(rèn)沒有開啟延遲加載

配置方法

需要配置SqlMapConfig.xml炮捧,中有一個(gè)setting節(jié)點(diǎn),需要在setting節(jié)點(diǎn)中配置開啟延遲加載惦银。

<!-- 全局參數(shù)配置 -->
<settings>
    <!-- 配置開啟延遲加載 -->
    <setting name="lazyLoadingEnabled" value="true"/>
    <!-- 設(shè)置按需加載 -->
    <setting name="aggressiveLazyLoading" value="false" />
</settings>

Mapper文件

<!-- 懶加載 -->
<!-- 配置一個(gè)resultMap咆课,懶加載user -->
<resultMap type="orders" id="ordersLazyLoading">
    <!-- order表的主鍵 -->
    <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指定一個(gè)statementID查詢用戶末誓,延遲加載的查詢 -->
    <!-- column指定查詢條件的列 -->
    <association property="user" select="getUserById" column="user_id">
      <!-- user表的主鍵 -->
      <id column="user_id" property="id"/>
      <!-- 普通列 -->
      <result column="username" property="username"/>
      <result column="birthday" property="birthday"/>
      <result column="sex" property="sex"/>
      <result column="address" property="address"/>
    </association>
</resultMap>
<select id="getOrderLazyLoading" resultMap="ordersLazyLoading">
    select * from orders
</select>

<select id="getUserById" parameterType="int" resultType="cn.itcast.pojo.User">
    SELECT * from user where id = #{id}
</select>

接口定義

public interface OrderMapper{
    List<Orders> getOrderLazyLoading();
}

測(cè)試方法

@Test
public void testgetOrderLazyLoading() throws Exception {
    SqlSession sqlSession = sessionFactory.openSession();
    OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class);
    List<Orders> list = orderMapper.getOrderLazyLoading();
    Orders orders = list.get(0);
    System.out.println(orders.getId());
    //懶加載
    System.out.println(orders.getUser().getUsername());
    System.out.println(list);
    sqlSession.close();
}

Mybatis的緩存

一級(jí)緩存、二級(jí)緩存书蚪。

Mybatis緩存介紹

如下圖喇澡,是mybatis一級(jí)緩存和二級(jí)緩存的區(qū)別圖解:

緩存

Mybatis一級(jí)緩存的作用域是同一個(gè)SqlSession,在同一個(gè)sqlSession中兩次執(zhí)行相同的sql語(yǔ)句殊校,第一次執(zhí)行完畢會(huì)將數(shù)據(jù)庫(kù)中查詢的數(shù)據(jù)寫到緩存(內(nèi)存)晴玖,第二次會(huì)從緩存中獲取數(shù)據(jù)將不再?gòu)臄?shù)據(jù)庫(kù)查詢,從而提高查詢效率为流。當(dāng)一個(gè)sqlSession結(jié)束后該sqlSession中的一級(jí)緩存也就不存在了呕屎。Mybatis默認(rèn)開啟一級(jí)緩存。

Mybatis二級(jí)緩存是多個(gè)SqlSession共享的敬察,其作用域是mapper的同一個(gè)namespace秀睛,不同的sqlSession兩次執(zhí)行相同namespace下的sql語(yǔ)句且向sql中傳遞參數(shù)也相同即最終執(zhí)行相同的sql語(yǔ)句,第一次執(zhí)行完畢會(huì)將數(shù)據(jù)庫(kù)中查詢的數(shù)據(jù)寫到緩存(內(nèi)存)莲祸,第二次會(huì)從緩存中獲取數(shù)據(jù)將不再?gòu)臄?shù)據(jù)庫(kù)查詢琅催,從而提高查詢效率。Mybatis默認(rèn)沒有開啟二級(jí)緩存需要在setting全局參數(shù)中配置開啟二級(jí)緩存虫给。

一級(jí)緩存

原理

下圖是根據(jù)id查詢用戶的一級(jí)緩存圖解:

一級(jí)緩存

一級(jí)緩存區(qū)域是根據(jù)SqlSession為單位劃分的。
每次查詢會(huì)先從緩存區(qū)域找侠碧,如果找不到從數(shù)據(jù)庫(kù)查詢抹估,查詢到數(shù)據(jù)將數(shù)據(jù)寫入緩存。Mybatis內(nèi)部存儲(chǔ)緩存使用一個(gè)HashMap弄兜,key為hashCode+sqlId+Sql語(yǔ)句药蜻。value為從查詢出來映射生成的java對(duì)象。
sqlSession執(zhí)行insert替饿、update语泽、delete等操作commit提交后會(huì)清空緩存區(qū)域。

測(cè)試一級(jí)緩存

@Test
public void testlevel1cache() throws Exception {
    SqlSession sqlSession = sessionFactory.openSession();
    OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class);
    //第一次查詢视卢,從數(shù)據(jù)庫(kù)中查詢數(shù)據(jù)
    List<OrderUser> list = orderMapper.getOrderWithUser();
    System.out.println(list);
    //更新orders表踱卵,會(huì)清空一級(jí)緩存
    OrderUser orderUser = list.get(0);
    orderUser.setNote("修改數(shù)據(jù)庫(kù)清空一級(jí)緩存");
    orderMapper.updateOrders(orderUser);
    sqlSession.commit();
    //第二次查詢從一級(jí)緩存中命中
    List<OrderUser> list2 = orderMapper.getOrderWithUser();
    System.out.println(list2);
    //關(guān)閉sqlsession
    sqlSession.close();
}

二級(jí)緩存

原理

下圖是多個(gè)sqlSession請(qǐng)求UserMapper的二級(jí)緩存圖解。

二級(jí)緩存

二級(jí)緩存區(qū)域是根據(jù)mapper的namespace劃分的据过,相同namespace的mapper查詢數(shù)據(jù)放在同一個(gè)區(qū)域惋砂,如果使用mapper代理方法每個(gè)mapper的namespace都不同,此時(shí)可以理解為二級(jí)緩存區(qū)域是根據(jù)mapper劃分绳锅。

每次查詢會(huì)先從緩存區(qū)域找西饵,如果找不到從數(shù)據(jù)庫(kù)查詢,查詢到數(shù)據(jù)將數(shù)據(jù)寫入緩存鳞芙。

Mybatis內(nèi)部存儲(chǔ)緩存使用一個(gè)HashMap眷柔,key為hashCode+sqlId+Sql語(yǔ)句期虾。value為從查詢出來映射生成的java對(duì)象

sqlSession執(zhí)行insert、update驯嘱、delete等操作commit提交后會(huì)清空緩存區(qū)域镶苞。

開啟二級(jí)緩存

第一步:在核心配置文件SqlMapConfig.xml中加入

<setting name="cacheEnabled"value="true"/>

描述 允許值 默認(rèn)值
cacheEnabled 對(duì)在此配置文件下的所有cache 進(jìn)行全局性開/關(guān)設(shè)置。 true | false true

第二步:在需要開啟二級(jí)緩存的mapper文件中加入<cache/>節(jié)點(diǎn)宙拉。

第三步:在開啟二級(jí)緩存的mapper中使用的pojo類需要實(shí)現(xiàn)序列化接口宾尚。

測(cè)試二級(jí)緩存

@Test
public void testLevel2Cache() throws Exception {
    //第一次查詢從數(shù)據(jù)庫(kù)中查詢
    SqlSession sqlSession = sessionFactory.openSession();
    OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class);
    List<OrderUser> list = orderMapper.getOrderWithUser();
    System.out.println(list);
    sqlSession.close();

    //更新數(shù)據(jù)庫(kù)清空二級(jí)緩存
    SqlSession sqlSession1 = sessionFactory.openSession();
    OrderMapper orderMapper1 = sqlSession1.getMapper(OrderMapper.class);
    OrderUser orderUser = list.get(0);
    orderUser.setNote("測(cè)試二級(jí)緩存");
    orderMapper1.updateOrders(orderUser);
    sqlSession1.commit();
    sqlSession1.close();
        
    //第二次查詢從二級(jí)緩存中取數(shù)據(jù)
    SqlSession sqlSession2 = sessionFactory.openSession();
    OrderMapper orderMapper2 = sqlSession2.getMapper(OrderMapper.class);
    List<OrderUser> list2 = orderMapper2.getOrderWithUser();
    System.out.println(list2);
    sqlSession2.close();        
}

設(shè)置某方法不使用二級(jí)緩存

不使用二級(jí)緩存

更新數(shù)據(jù)庫(kù)不刷新二級(jí)緩存

不刷新二級(jí)緩存

Mybatis集成第三方緩存工具ehcache

Ehcache是一個(gè)分布式的緩存框架

整合環(huán)境

需要用到ehcache的jar包mybatis+ehcache的整合包。

整合包

整合步驟

第一步:把ehcache的jar包和整合包放到工程中谢澈。

第二步:創(chuàng)建一個(gè)ehcache的配置文件煌贴。配置了ehcache的相關(guān)設(shè)置。

第三步:需要在mapper文件中指定使用ehcache做緩存锥忿。

整合的原理

Mybatis-ehcache整合包中實(shí)現(xiàn)了mybatis的Cache接口牛郑。只要實(shí)現(xiàn)這個(gè)接口就可以整合。

原理
Cache接口

創(chuàng)建ehcache的配置文件

classpath下名稱為:ehcache.xml

<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
    <!-- 數(shù)據(jù)緩存要存放的磁盤地址 -->
    <diskStore path="d:\temp\ehcache" />
    <defaultCache 
        maxElementsInMemory="1000" 
        maxElementsOnDisk="10000000"
        eternal="false" 
        overflowToDisk="false" 
        timeToIdleSeconds="120"
        timeToLiveSeconds="120" 
        diskExpiryThreadIntervalSeconds="120"
        memoryStoreEvictionPolicy="LRU">
    </defaultCache>
</ehcache>

制定使用ehcache做緩存

配置

應(yīng)用場(chǎng)景

使用場(chǎng)景:對(duì)于訪問響應(yīng)速度要求高敬鬓,但是時(shí)效性不高的查詢淹朋,可以采用二級(jí)緩存技術(shù)。

注意:在使用二級(jí)緩存的時(shí)候钉答,要設(shè)置一下刷新間隔(cache標(biāo)簽中有一個(gè)flashInterval屬性)來定時(shí)刷新二級(jí)緩存础芍,這個(gè)刷新間隔根據(jù)具體需求來設(shè)置,比如設(shè)置30分鐘数尿、60分鐘等仑性,單位為毫秒。

局限性

Mybatis的二級(jí)緩存對(duì)細(xì)粒度的數(shù)據(jù)右蹦,緩存實(shí)現(xiàn)不好诊杆。

場(chǎng)景:對(duì)商品信息進(jìn)行緩存招狸,由于商品信息查詢?cè)L問量大官套,但是要求用戶每次查詢都是最新的商品信息咒钟,此時(shí)如果使用二級(jí)緩存偶惠,就無法實(shí)現(xiàn)當(dāng)一個(gè)商品發(fā)送變化只刷新該商品的緩存信息而不刷新其他商品緩存信息葛作,因?yàn)槎?jí)緩存是Mapper級(jí)別的队塘,當(dāng)一個(gè)商品的信息發(fā)送更新穴张,所有的商品信息緩存數(shù)據(jù)都會(huì)被清空撬统。

解決此類問題晃洒,需要在業(yè)務(wù)層根據(jù)需要對(duì)數(shù)據(jù)有針對(duì)性的緩存

比如可以對(duì)經(jīng)常變化的數(shù)據(jù)操作單獨(dú)放到另一個(gè)namespace的Mapper中

Mybatis整合Spring

整合思路

Dao層:

1慨灭、數(shù)據(jù)庫(kù)連接池配置在spring中。

2球及、sqlsessionFactory對(duì)象放到spring容器中氧骤,以單例形式存在。

3吃引、把mapper的代理對(duì)象都放到spring容器筹陵。如果使用傳統(tǒng)的dao開發(fā)方式刽锤,sqlsession應(yīng)用從spring容器中獲得。

Service層:

1朦佩、所有的service實(shí)現(xiàn)類對(duì)象都放到spring容器中并思。

2、事務(wù)配置也應(yīng)該放到service層语稠,交給spring管理宋彼。

整合需要的環(huán)境

1、Mybatis的jar包
2仙畦、Mybatis依賴的jar包
3输涕、Spring的jar包
4、Mybatis和spring的整合包慨畸。
5莱坎、Mysql的數(shù)據(jù)庫(kù)驅(qū)動(dòng)
6、數(shù)據(jù)庫(kù)連接池的jar包寸士。

jar包

工程搭建步驟

第一步:創(chuàng)建一個(gè)java工程

第二步:導(dǎo)入jar包(上面提到的jar包)

第三步:創(chuàng)建mybatis的核心配置文件SqlmapConfig.xml

第四步:spring的配置文件

? 1檐什、數(shù)據(jù)庫(kù)連接池

? 2、SqlsessionFactory配置弱卡,應(yīng)該是整合包中的乃正。

第五步:開發(fā)dao

? 1、傳統(tǒng)dao開發(fā)(接口+實(shí)現(xiàn)類)

? 2婶博、Mapper代理的形式

第六步:

? 1烫葬、如果是傳統(tǒng)dao需要把實(shí)現(xiàn)類配置到spring容器中

? 2、Mapper代理形式凡蜻,也需要把代理對(duì)象配置spring容器中。

第七步:測(cè)試垢箕。

Sql mapConfig.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>
        <package name="cn.itcast.pojo"/>
    </typeAliases>

    <!-- 加載Mapper映射文件 -->
    <mappers>
        <package name="cn.itcast.mapper"/>
    </mappers>
    
</configuration>

applicationContext. xml(Spring的配置文件)

<?xml version="1.0" encoding="UTF-8"?>
<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 ">
    <!-- 加載配置文件 -->
    <context:property-placeholder location="classpath:db.properties"/>  
    <!-- 數(shù)據(jù)庫(kù)連接池 -->
    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
       <property name="driverClassName" value="${JDBC_DRIVER}"/>
        <property name="url" value="${JDBC_URL}"/>
        <property name="username" value="${JDBC_USER}"/>
        <property name="password" value="${JDBC_PASSWORD}"/>
        <property name="maxActive" value="10"/>
        <property name="maxIdle" value="5"/>
    </bean>
    <!-- sqlsessionFactory配置 -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!-- 加載mybatis的配置文件 -->
        <property name="configLocation" value="classpath:SqlMapConfig.xml"/>
        <!-- 數(shù)據(jù)庫(kù)連接池 -->
        <property name="dataSource" ref="dataSource"/>
    </bean>
    
</beans>

傳統(tǒng)dao的開發(fā)方式

接口+實(shí)現(xiàn)類

Mapper文件

創(chuàng)建mapper文件划栓。在SqlmapConfig.xml中加載。

Mapper文件

接口

public interface OrderDao {
    List<OrderUser> getOrderWithUser();
    List<Orders> getOrderWithUserResultMap();
}

實(shí)現(xiàn)類

如果想從spring容器中獲得sqlsession需要繼承SqlSessionDaoSupport類条获。

SqlSessionDaoSupport類
public class OrderDaoImpl extends SqlSessionDaoSupport implements OrderDao {

    @Override
    public List<OrderUser> getOrderWithUser() {
        //從spring容器中獲得sqlsession對(duì)象
        SqlSession sqlSession = this.getSqlSession();
        List<OrderUser> list = sqlSession.selectList("test.getOrderWithUser");
        //不能調(diào)用close方法忠荞,交給spring完成
        //sqlSession.close();
        return list;
    }

    @Override
    public List<Orders> getOrderWithUserResultMap() {
        SqlSession sqlSession = this.getSqlSession();
        List<Orders> list = sqlSession.selectList("test.getOrderWithUserResultMap");
        return list;
    }

}

把實(shí)現(xiàn)類配置到spring容器中

spring容器

測(cè)試方法

public class OrderDaoTest {

    private ApplicationContext applicationContext;
    
    @Before
    public void setUp() throws Exception {
        //初始化spring容器
        applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
    }

    @Test
    public void testGetOrderWithUser() {
        OrderDao orderDao = (OrderDao) applicationContext.getBean("orderDao");
        List<OrderUser> orderWithUser = orderDao.getOrderWithUser();
        System.out.println(orderWithUser);
    }

    @Test
    public void testGetOrderWithUserResultMap() {
        OrderDao orderDao = (OrderDao) applicationContext.getBean("orderDao");
        List<Orders> list = orderDao.getOrderWithUserResultMap();
        System.out.println(list);
    }

}

Mapper代理形式的dao

Mapper文件+接口的開發(fā)

Mappwer文件+接口

Mapper代理對(duì)象配置到spring容器中

使用Mapper的代理類

Mapper代理類
<!-- mapper的代理對(duì)象 -->
<bean id="orderMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
    <!-- mapperInterface這個(gè)屬性就是指定要為哪個(gè)接口做代理 -->
    <property name="mapperInterface" value="cn.itcast.mapper.OrderMapper"/>
    <property name="sqlSessionFactory" ref="sqlSessionFactory"/>
</bean>

使用包掃描器創(chuàng)建代理對(duì)象

包掃描器
<!-- 配置包掃描器 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    <!-- 指定要掃描的包,如果有多個(gè)包帅掘,使用半角逗號(hào)分隔 -->
    <!-- 掃描后bean的id就是類名委煤,首字母小寫 -->
    <property name="basePackage" value="cn.itcast.mapper"/>
    <!-- 不需要指定sqlsessionFactory,掃描器會(huì)自動(dòng)找 -->
</bean>

掃描器是應(yīng)用廣泛的修档。

sqlmapConfig.xml:

sqlmapConfig.xml
結(jié)果

逆向工程

什么是逆向工程

根據(jù)數(shù)據(jù)庫(kù)中的表生成java代碼碧绞。

1、pojo類吱窝。根據(jù)數(shù)據(jù)庫(kù)中表的字段生成讥邻。

2迫靖、Mapper接口。

3兴使、Mapper映射文件系宜。都是基于單表的操作。

官方提供工具

官方工具
逆向工程

需要配置的信息

在generatorConfig.xml中配置

1发魄、數(shù)據(jù)庫(kù)連接

數(shù)據(jù)庫(kù)連接

2盹牧、指定POJO生成的包名及生成的位置

指定包名及位置

3、指定Mapper文件励幼、映射文件生成的包及位置

包及位置
接口位置

4汰寓、指定需要逆向的表

指定表

指定逆向工程

執(zhí)行GeneratorSqlmap.java中的main方法。

工程

注意:如果發(fā)現(xiàn)生成的代碼有問題需要?jiǎng)h除后重新生成赏淌,否則會(huì)在原文件中追加內(nèi)容踩寇。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市六水,隨后出現(xiàn)的幾起案子俺孙,更是在濱河造成了極大的恐慌,老刑警劉巖掷贾,帶你破解...
    沈念sama閱讀 219,366評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件睛榄,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡想帅,警方通過查閱死者的電腦和手機(jī)场靴,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,521評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來港准,“玉大人旨剥,你說我怎么就攤上這事∏掣祝” “怎么了轨帜?”我有些...
    開封第一講書人閱讀 165,689評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)衩椒。 經(jīng)常有香客問我蚌父,道長(zhǎng),這世上最難降的妖魔是什么毛萌? 我笑而不...
    開封第一講書人閱讀 58,925評(píng)論 1 295
  • 正文 為了忘掉前任苟弛,我火速辦了婚禮,結(jié)果婚禮上阁将,老公的妹妹穿的比我還像新娘膏秫。我一直安慰自己,他們只是感情好做盅,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,942評(píng)論 6 392
  • 文/花漫 我一把揭開白布荔睹。 她就那樣靜靜地躺著狸演,像睡著了一般。 火紅的嫁衣襯著肌膚如雪僻他。 梳的紋絲不亂的頭發(fā)上宵距,一...
    開封第一講書人閱讀 51,727評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音吨拗,去河邊找鬼满哪。 笑死,一個(gè)胖子當(dāng)著我的面吹牛劝篷,可吹牛的內(nèi)容都是我干的哨鸭。 我是一名探鬼主播,決...
    沈念sama閱讀 40,447評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼娇妓,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼像鸡!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起哈恰,我...
    開封第一講書人閱讀 39,349評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤只估,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后着绷,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蛔钙,經(jīng)...
    沈念sama閱讀 45,820評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,990評(píng)論 3 337
  • 正文 我和宋清朗相戀三年荠医,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了吁脱。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,127評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡彬向,死狀恐怖兼贡,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情娃胆,我是刑警寧澤紧显,帶...
    沈念sama閱讀 35,812評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站缕棵,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏涉兽。R本人自食惡果不足惜招驴,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,471評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望枷畏。 院中可真熱鬧别厘,春花似錦、人聲如沸拥诡。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,017評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至冗懦,卻和暖如春爽冕,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背披蕉。 一陣腳步聲響...
    開封第一講書人閱讀 33,142評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工颈畸, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人没讲。 一個(gè)月前我還...
    沈念sama閱讀 48,388評(píng)論 3 373
  • 正文 我出身青樓眯娱,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親爬凑。 傳聞我的和親對(duì)象是個(gè)殘疾皇子徙缴,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,066評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容