MyBatis學(xué)習(xí)筆記

最近學(xué)習(xí)MyBatis這個(gè)輕量型持久層框架幔崖,感覺入門很簡(jiǎn)單,但是深層次細(xì)節(jié)配置很多。本篇筆記從 配置文件->例子入門->MyBatis傳參和取參->查詢結(jié)果返回類型->關(guān)聯(lián)數(shù)據(jù)查詢->關(guān)聯(lián)數(shù)據(jù)查詢策略(是否啟用懶加載)->動(dòng)態(tài)SQL->一級(jí)緩存和二級(jí)緩存來進(jìn)行一次MyBatis探尋穆端。

一、概念簡(jiǎn)介

MyBatis 是一款優(yōu)秀的持久層框架传惠,它支持定制化 SQL迄沫、存儲(chǔ)過程以及高級(jí)映射。MyBatis 避免了幾乎所有的 JDBC 代碼和手動(dòng)設(shè)置參數(shù)以及獲取結(jié)果集卦方。MyBatis 可以使用簡(jiǎn)單的 XML 或注解來配置和映射原生信息羊瘩,將接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java對(duì)象)映射成數(shù)據(jù)庫(kù)中的記錄。

下載地址:https://github.com/mybatis/mybatis-3
MyBatis 文檔:http://www.mybatis.org/mybatis-3/zh/index.html
mybatis-spring 文檔:http://www.mybatis.org/spring/zh/index.html

開始總結(jié)前先導(dǎo)入Maven依賴

<dependencies>
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.4.6</version>
    </dependency>

    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.47</version>
    </dependency>

    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.17</version>
    </dependency>
</dependencies>

二盼砍、總配置文件

在classpath目錄下面建立一個(gè)MyBatis配置文件困后,配置文件可以分為兩個(gè)部分,第一部分?jǐn)?shù)據(jù)庫(kù)環(huán)境配置衬廷,第二部分加載映射文件摇予。
文件名mybatis-config.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>
    <!-- 加載外部 properties 文件 -->
    <properties resource="jdbc.properties"></properties>
    
    <environments default="debug">
        <environment id="debug">
            <transactionManager type="JDBC"></transactionManager>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver" />
                <property name="url"
                    value="jdbc:mysql://10.22.70.2:3306/database_chao?useUnicode=true&amp;characterEncoding=utf8" />
                <property name="username" value="xxx" />
                <property name="password" value="xxx" />
            </dataSource>
        </environment>

        <environment id="release">
            <transactionManager type="JDBC"></transactionManager>
            <dataSource type="POOLED">
                <property name="driver" value="${driver}" />
                <property name="url" value="${url}" />
                <property name="username" value="${username}" />
                <property name="password" value="${password}" />
            </dataSource>
        </environment>

    </environments>

    <mappers>
        
    </mappers>
</configuration>

MyBatis 的配置文件包含了會(huì)深深影響 MyBatis 行為的設(shè)置(settings)和屬性(properties)信息吗跋。文檔的頂層結(jié)構(gòu)如下:
---configuration 配置
-------properties 屬性
-------settings 設(shè)置
-------typeAliases 類型別名
-------typeHandlers 類型處理器
-------plugins 插件
-------environments 環(huán)境
----------environment 環(huán)境變量
-------------transactionManager 事務(wù)管理器
-------------dataSource 數(shù)據(jù)源
-------------databaseIdProvider 數(shù)據(jù)庫(kù)廠商標(biāo)識(shí)
-------mappers 映射器

有關(guān) properties侧戴、settings、typeAliases跌宛、typeHandlers和plugins的配置及相關(guān)功能請(qǐng)參考MyBatis的官方文檔 http://www.mybatis.org/mybatis-3/zh/configuration.html


三酗宋、例子入門

1. 簡(jiǎn)單例子入門

① 建立POJO類

public class Grade {
    private int gid;
    private String gname;
}

② 創(chuàng)建POJO對(duì)象和Mysql數(shù)據(jù)的表之間的映射配置
[在POJO同在包下]創(chuàng)建名字為 GradeMapper.xml 的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="primary">
    <select id="selectGrade" resultType="primary.Grade">
        select * from grade where gid=#{id}
    </select>
</mapper>

namespace 可以自己隨便定,不要重復(fù)
<select> 標(biāo)簽里面的 id 也可以自己隨便定疆拘,不要重復(fù)

③ 將映射配置加載到總配置文件中
mybatis-config.xml文件中的<mappers> 標(biāo)簽下加入如下代碼

<mappers>
    <mapper resource="primary/GradeMapper.xml" />
</mappers>

④ 代碼測(cè)試

@Test
public void testSelectById() throws Exception {
    //加載 配置文件
    InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
    //初始化session工廠
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    
    SqlSession sqlSession = sqlSessionFactory.openSession();
    //1. 執(zhí)行SQL語句標(biāo)簽里面的 id為 映射配置里面的 namespace + 標(biāo)簽的id
    //2. 參數(shù)為映射文件里面執(zhí)行sql語句需要的參數(shù), 這里是id
    Object selectOne = sqlSession.selectOne("primary.selectGrade", 1);
    //3. MyBatis將查詢數(shù)封裝成要求的結(jié)果返回類型后再返回
    System.out.println(selectOne);
    
    sqlSession.close();
    inputStream.close();
}
2. 正規(guī)寫法 實(shí)現(xiàn)簡(jiǎn)單增刪改查功能

開發(fā)跟數(shù)據(jù)交互都是通過 Dao層蜕猫,MyBatis為我們Dao層開發(fā)做了很好的兼容,我們直接寫接口哎迄,然后用Mapper映射文件充當(dāng)實(shí)現(xiàn)類回右。

① 先寫接口

public interface GradeDao {
    public int insertGrade(Grade grade);
    public int updateGrade(Grade grade);
    public int deleteGrade(int id);
    public List<Grade> selectAll();
}

② 創(chuàng)建POJO對(duì)象和Mysql數(shù)據(jù)的表之間的映射配置
為了方便查看和加載配置文件,我們一般Mapper文件和對(duì)應(yīng)的Dao接口放在同一個(gè)包下漱挚。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "mybatis-3-mapper.dtd" >
<mapper namespace="com.ogemray.dao.GradeDao">

    <insert id="insertGrade">
        insert into grade (gname) value (#{gname})
    </insert>
    
    <update id="updateGrade">
        update grade set gname=#{gname} where gid=#{gid}
    </update>
    
    <delete id="deleteGrade">
        delete from grade where gid=#{id}
    </delete>
    
    <select id="selectAll" resultType="com.ogemray.entity.Grade">
        select * from grade
    </select>
</mapper>

配置文件有些要注意的地方
mapper 的 namespace 要是 對(duì)應(yīng) Dao接口的全名
SQL語句標(biāo)簽里面的 id 要是 Dao里面對(duì)應(yīng)方法的名字

③ 測(cè)試代碼

public class UpgradeTest {
    private InputStream inputStream;
    private SqlSession sqlSession;
    
    @Before
    public void beforeAction() throws Exception {
        inputStream = Resources.getResourceAsStream("mybatis-config.xml");
        SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        sqlSession = sessionFactory.openSession();
    }
    
    @After
    public void afterAction() throws Exception {
        sqlSession.commit();
        sqlSession.close();
        inputStream.close();
    }
    
    @Test
    public void testSimpleInsert() {
        Grade grade = new Grade("理科四班");
        GradeDao mapper = sqlSession.getMapper(GradeDao.class);
        int count = mapper.insertGrade(grade);
        System.out.println(count);
    }
    
    @Test
    public void testSimpleUpdate() {
        GradeDao mapper = sqlSession.getMapper(GradeDao.class);
        Grade grade = mapper.selectOneById(5);
        int count = grade.setGname("理科二班");
        mapper.updateGrade(grade);
    }
    
    @Test
    public void testSimpleDelete() {
        GradeDao mapper = sqlSession.getMapper(GradeDao.class);
        int count = mapper.deleteGrade(5);
    }

    @Test
    public void testSimpleSelectAll() {
        GradeDao mapper = sqlSession.getMapper(GradeDao.class);
        List<Grade> list = mapper.selectAll();
        for (Grade grade : list) { System.out.println(grade); }
    }
}
3. 得到新插入對(duì)象的id值

對(duì)于上面的 增 刪 更新后面返回的都是影響行數(shù)翔烁,很多時(shí)候數(shù)據(jù)庫(kù)主鍵自增長(zhǎng),但是我們要知道新插入對(duì)象對(duì)應(yīng)數(shù)據(jù)庫(kù)里面的id值旨涝,這個(gè)時(shí)候需要用到下面這兩個(gè)屬性蹬屹。

屬性 描述
useGeneratedKeys (僅對(duì) insert 和 update 有用)這會(huì)令 MyBatis 使用 JDBC 的 getGeneratedKeys 方法來取出由數(shù)據(jù)庫(kù)內(nèi)部生成的主鍵(比如:像 MySQL 和 SQL Server 這樣的關(guān)系數(shù)據(jù)庫(kù)管理系統(tǒng)的自動(dòng)遞增字段),默認(rèn)值:false白华。
keyProperty (僅對(duì) insert 和 update 有用)唯一標(biāo)記一個(gè)屬性慨默,MyBatis 會(huì)通過 getGeneratedKeys 的返回值或者通過 insert 語句的 selectKey 子元素設(shè)置它的鍵值,默認(rèn):unset弧腥。如果希望得到多個(gè)生成的列厦取,也可以是逗號(hào)分隔的屬性名稱列表。

Mapper文件里面的標(biāo)簽做如下更改

<insert id="insertGrade" 
        parameterType="com.ogemray.entity.Grade"
        useGeneratedKeys="true" 
        keyProperty="gid">
    insert into grade (gname) value (#{gname})
</insert>

測(cè)試代碼

@Test
public void testSimpleInsert() {
    Grade grade = new Grade("理科五班");
    GradeDao mapper = sqlSession.getMapper(GradeDao.class);
    int count = mapper.insertGrade(grade);
    System.out.println("影響行數(shù): " + count + "  更新后對(duì)象: " + grade);
}

控制臺(tái)輸出

影響行數(shù): 1  更新后對(duì)象: Grade [gid=8, gname=理科五班]

四鸟赫、參數(shù)傳遞 (多參傳遞)

1. 使用 arg 取參 arg0蒜胖、arg1 ...

Dao接口

public interface GradeDao {
    public List<Grade> selectPartGradeByUseArg(int startId, int endId);
}

Mapper文件

<mapper namespace="com.ogemray.dao.GradeDao">
    <select id="selectPartGradeByUseArg" resultType="com.ogemray.entity.Grade">
        select * from grade where gid &gt;= #{arg0} and gid &lt;= #{arg1}
    </select>
</mapper>

測(cè)試代碼

@Test
public void testMultiParam1() {
    GradeDao mapper = sqlSession.getMapper(GradeDao.class);
    List<Grade> list = mapper.selectPartGradeByUseArg(1, 2);
    for (Grade grade : list) { System.out.println(grade); }
}
2. 使用 param 取參 param1消别、param2 ...

Dao接口

public interface GradeDao {
    public List<Grade> selectPartGradeByUseParam(int startId, int endId);
}

Mapper文件

<mapper namespace="com.ogemray.dao.GradeDao">
    <select id="selectPartGradeByUseParam" resultType="com.ogemray.entity.Grade">
        select * from grade where gid &gt;= #{param1} and gid &lt;= #{param2}
    </select>
</mapper>

測(cè)試代碼

@Test
public void testMultiParam2() {
    GradeDao mapper = sqlSession.getMapper(GradeDao.class);
    List<Grade> list = mapper.selectPartGradeByUseParam(1, 2);
    for (Grade grade : list) { System.out.println(grade); }
}
3. 使用 @Param 注解傳參

這種方式比較常用,標(biāo)明參數(shù)名字台谢,代碼閱讀性強(qiáng)

Dao接口

public interface GradeDao {
    public List<Grade> selectPartGradeUseAnno(@Param("startId") int startId,@Param("endId") int endId);
}

Mapper文件

<mapper namespace="com.ogemray.dao.GradeDao">
    <select id="selectPartGradeUseAnno" resultType="com.ogemray.entity.Grade">
        select * from grade where gid &gt;= #{startId} and gid &lt;= #{endId}
    </select>
</mapper>

測(cè)試代碼

@Test
public void testMultiParam3() {
    GradeDao mapper = sqlSession.getMapper(GradeDao.class);
    List<Grade> list = mapper.selectPartGradeUseAnno(1, 2);
    for (Grade grade : list) { System.out.println(grade); }
}
4. 使用 Map 傳參

Dao接口

public interface GradeDao {
    public List<Grade> selectPartGradeUseMap(Map<String, Integer> map);
}

Mapper文件

<mapper namespace="com.ogemray.dao.GradeDao">
    <select id="selectPartGradeUseMap" resultType="com.ogemray.entity.Grade">
        select * from grade where gid &gt;= #{startId} and gid &lt;= #{endId}
    </select>
</mapper>

測(cè)試代碼

@Test
public void testMultiParam4() {
    GradeDao mapper = sqlSession.getMapper(GradeDao.class);
    HashMap<String,Integer> map = new HashMap<String, Integer>();
    map.put("startId", 1);
    map.put("endId", 2);
    List<Grade> list = mapper.selectPartGradeUseMap(map);
    for (Grade grade : list) { System.out.println(grade); }
}
5. 使用集合傳參

Dao接口

public interface GradeDao {
    public List<Grade> selectPartGradeUseCollection(List<Integer> gids);
}

Mapper文件

<mapper namespace="com.ogemray.dao.GradeDao">
    <select id="selectPartGradeUseCollection" resultType="com.ogemray.entity.Grade">
        <!-- select * from grade where gid &gt;= #{collection[0]} and gid &lt;= #{collection[1]} -->
        select * from grade where gid &gt;= #{list[0]} and gid &lt;= #{list[1]}
    </select>
</mapper>

測(cè)試代碼

@Test
public void testMultiParam5() {
    GradeDao mapper = sqlSession.getMapper(GradeDao.class);
    List<Integer> gids = new ArrayList<Integer>();
    gids.add(1);
    gids.add(2);
    List<Grade> list = mapper.selectPartGradeUseCollection(gids);
    for (Grade grade : list) { System.out.println(grade); }
}

最后說下映射文件中獲取參數(shù)的符號(hào)#{}和${}的區(qū)別

#{}對(duì)應(yīng)的是 PreparedStatementd 對(duì)象來執(zhí)行 sql 語句
${}對(duì)應(yīng)的是 Statement 對(duì)象來執(zhí)行 sql 語句

public interface GradeDao {
    public List<Grade> selectPartGradeUse(@Param("tableName") String tableName,@Param("startId") int startId, @Param("endId") int endId);
}
<mapper namespace="com.ogemray.dao.GradeDao">
    <select id="selectPartGradeUse" resultType="com.ogemray.entity.Grade">
        select * from ${tableName} where gid &gt;= ${startId} and gid &lt;= #{endId}
    </select>
</mapper>

最后執(zhí)行的 SQL語句可以看出區(qū)別寻狂,也可以看出兩者的使用場(chǎng)景

select * from grade where gid >= 1 and gid <= ? 

五、結(jié)果類型 resultType 和 resultMap

屬性 描述
resultType 從這條語句中返回的期望類型的類的完全限定名或別名朋沮。注意如果是集合情形蛇券,那應(yīng)該是集合可以包含的類型,而不能是集合本身樊拓。使用 resultType 或 resultMap纠亚,但不能同時(shí)使用。
resultMap 外部 resultMap 的命名引用筋夏。結(jié)果集的映射是 MyBatis 最強(qiáng)大的特性蒂胞,對(duì)其有一個(gè)很好的理解的話,許多復(fù)雜映射的情形都能迎刃而解条篷。使用 resultMap 或 resultType骗随,但不能同時(shí)使用。
1. resultType 指定返回封裝好的Java對(duì)象
<mapper namespace="com.ogemray.dao.GradeDao">
    <select id="selectOneById_returnGrade" resultType="com.ogemray.entity.Grade">
        select * from grade where gid = #{id}
    </select>
</mapper>

//測(cè)試控制臺(tái)輸出
Grade [gid=1, gname=文科一班]
2. resultType 指定返回封裝Java對(duì)象的集合
<mapper namespace="com.ogemray.dao.GradeDao">
    <select id="selectAll_retuenList" resultType="com.ogemray.entity.Grade">
        select * from grade
    </select>
</mapper>

//測(cè)試控制臺(tái)輸出
[Grade [gid=1, gname=文科一班], Grade [gid=2, gname=文科二班]]
3. resultType 指定返回 Map 對(duì)象赴叹,key查詢出來的 column name value對(duì)應(yīng)值
<mapper namespace="com.ogemray.dao.GradeDao">
    <select id="selectOneById_returnMap" resultType="map">
        select * from grade where gid = #{id}
    </select>
</mapper>

//測(cè)試控制臺(tái)輸出
{gid=1, gname=文科一班}
4. resultType 指定返回 Map 對(duì)象鸿染,key值隨便指定,value為封裝好的java對(duì)象
//接口類, 需要用 @MapKey注解指定用哪個(gè)column字段作為key
public interface GradeDao {
    @MapKey("gid")
    public Map<Integer, Grade> selectAll_retuenMap();
}

//映射文件配置
<mapper namespace="com.ogemray.dao.GradeDao">
    <select id="selectAll_retuenMap" resultType="map">
        select * from grade
    </select>
</mapper>

//測(cè)試控制臺(tái)輸出
{1={gid=1, gname=文科一班}, 2={gid=2, gname=文科二班}}
5. resultMap 指定返回類型

當(dāng)在類里面屬性名和數(shù)據(jù)庫(kù)里面的column名字對(duì)不上的時(shí)候乞巧,可以用resultMap來指定字段匹配涨椒。

resultMap 子元素

  • id – 一個(gè) ID 結(jié)果,標(biāo)記出作為 ID 的結(jié)果可以幫助提高整體性能
  • result – 注入到字段或 JavaBean 屬性的普通結(jié)果
  • association – 一個(gè)復(fù)雜類型的關(guān)聯(lián)绽媒,許多結(jié)果將包裝成這種類型
    • 嵌套結(jié)果映射 – 關(guān)聯(lián)可以指定為一個(gè) resultMap 元素蚕冬,或者引用一個(gè)
  • collection – 一個(gè)復(fù)雜類型的集合
    • 嵌套結(jié)果映射 – 集合可以指定為一個(gè) resultMap 元素,或者引用一個(gè)

resultMap 屬性

屬性 描述
id 當(dāng)前命名空間中的一個(gè)唯一標(biāo)識(shí)些椒,用于標(biāo)識(shí)一個(gè)result map
type 類的完全限定名, 或者一個(gè)類型別名
autoMapping 如果設(shè)置這個(gè)屬性播瞳,MyBatis將會(huì)為這個(gè)ResultMap開啟或者關(guān)閉自動(dòng)映射。這個(gè)屬性會(huì)覆蓋全局的屬性 autoMappingBehavior免糕。默認(rèn)值為:unset。

例如下面實(shí)體類和實(shí)體類在數(shù)據(jù)庫(kù)映射字段對(duì)比

Java類和數(shù)據(jù)庫(kù)表字段對(duì)比.png
//映射配置文件中
<mapper namespace="com.ogemray.dao.StudentDao">
    <select id="selectAll" resultMap="studentMap">
        select * from student
    </select>

    <resultMap type="com.ogemray.entity.Student" id="studentMap">
        <id property="id" column="sid"/>
        <result property="name" column="sname"/>
        <result property="birthday" column="birthday"/>
    </resultMap>
</mapper>

如上面代碼忧侧,通過 <resultMap> 標(biāo)簽來指定實(shí)體類里面的屬性和映射數(shù)據(jù)表里面字段一一對(duì)應(yīng)關(guān)系石窑,兩者一樣的可以省略指定。然后通過 <select> 標(biāo)簽里面的 resultMap 屬性來引用提前設(shè)置好的 <resultMap> 標(biāo)簽蚓炬。


六松逊、resultMap 實(shí)現(xiàn)關(guān)聯(lián)查詢

MyBatis框架也可以實(shí)現(xiàn)像Hibernate那樣的關(guān)聯(lián)查詢,只不過是需要自己手動(dòng)去配置肯夏。

在開始之前经宏,先介紹下涉及到關(guān)聯(lián)查詢的兩個(gè)標(biāo)簽 <association><collection> 里面的屬性字段

屬性 描述
property 映射到列結(jié)果的字段或?qū)傩?/td>
javaType 一個(gè) Java 類的完全限定名犀暑,或一個(gè)類型別名
column 數(shù)據(jù)庫(kù)的列名,注意: 要處理復(fù)合主鍵烁兰,你可以指定多個(gè)列名通過 column="{prop1=col1,prop2=col2}" 這種語法來傳遞給嵌套查詢語句耐亏。這會(huì)引起 prop1 和 prop2 以參數(shù)對(duì)象形式來設(shè)置給目標(biāo)嵌套查詢語句。
select 另外一個(gè)映射語句的 ID沪斟,可以加載這個(gè)屬性映射需要的復(fù)雜類型广辰。獲取的在列屬性中指定的列的值將被傳遞給目標(biāo) select 語句作為參數(shù)。 select 注 意 : 要處理復(fù)合主鍵主之,你可以指定多個(gè)列名通過 column= " {prop1=col1,prop2=col2} " 這種語法來傳遞給嵌套查詢語句择吊,這會(huì)引起 prop1 和 prop2 以參數(shù)對(duì)象形式來設(shè)置給目標(biāo)嵌套查詢語句。

下面通過Student類和Grade類來建立關(guān)系進(jìn)行關(guān)聯(lián)查詢示例

Student類和實(shí)體表映射.png
Grade類和實(shí)體表映射.png
1. 通過連級(jí)方式實(shí)現(xiàn)關(guān)聯(lián)查詢
<mapper namespace="com.ogemray.dao.StudentDao">
    <select id="primaryCorrelationQueryById" resultMap="studentMap2">
        select
            s.sid sid, 
            s.sname sname,
            s.birthday birthday,
            g.gid gid,
            g.gname gname
        from 
            student s, grade g 
        where 
            s.sid = #{id} and s.sid = g.gid
    </select>
    
    <resultMap type="com.ogemray.entity.Student" id="studentMap2">
        <id property="id" column="sid"/>
        <result property="name" column="sname"/>
        <result property="birthday" column="birthday"/>
        <!-- 通過級(jí)聯(lián)方法, 實(shí)現(xiàn)關(guān)聯(lián)查詢 -->
        <result property="grade.gid" column="gid"/>
        <result property="grade.gname" column="gname"/>
    </resultMap>
</mapper>
2. 使用 <association> 標(biāo)簽實(shí)現(xiàn)關(guān)聯(lián)查詢
<mapper namespace="com.ogemray.dao.StudentDao">
    <select id="correlationQueryById" resultMap="studentMap3">
        select
            s.sid sid, 
            s.sname sname,
            s.birthday birthday,
            g.gid gid,
            g.gname gname
        from 
            student s, grade g 
        where 
            s.sid = #{id} and s.sid = g.gid
    </select>
    
    <resultMap type="com.ogemray.entity.Student" id="studentMap3">
        <id property="id" column="sid"/>
        <result property="name" column="sname"/>
        <result property="birthday" column="birthday"/>
        <!-- 通過子標(biāo)簽 association, 實(shí)現(xiàn)關(guān)聯(lián)查詢 -->
        <association property="grade" javaType="com.ogemray.entity.Grade">
            <id property="gid" column="grade_id"/>
            <result property="gname" column="gname"/>
        </association>
    </resultMap>
</mapper>
3. 使用 <association> 標(biāo)簽實(shí)現(xiàn)分步關(guān)聯(lián)查詢

GradeMapper.xml

<mapper namespace="com.ogemray.dao.GradeDao">
    <select id="selectOneById" resultType="com.ogemray.entity.Grade">
        select * from grade where gid = #{id}
    </select>
</mapper>

StudentMapper.xml

<mapper namespace="com.ogemray.dao.StudentDao">
    <select id="substepCorrelationQueryById" resultMap="studentMap4">
        select * from student where sid = #{id}
    </select>
    
    <resultMap type="com.ogemray.entity.Student" id="studentMap4">
        <id property="id" column="sid"/>
        <result property="name" column="sname"/>
        <result property="birthday" column="birthday"/>
        <association property="grade" 
                     select="com.ogemray.dao.GradeDao.selectOneById"
                     column="grade_Id">
        </association>
    </resultMap>
</mapper>
//分別執(zhí)行SQL語句
DEBUG ==>  Preparing: select * from student where sid = ? 
DEBUG ==> Parameters: 1(Integer)
DEBUG ====>  Preparing: select * from grade where gid = ? 
DEBUG ====> Parameters: 1(Integer)
4. 使用 <collection> 標(biāo)簽實(shí)現(xiàn) 集合關(guān)聯(lián)查詢
<collection> 里屬性 描述
property 集合對(duì)應(yīng)屬性名
ofType 集合包含元素類型

GradeMapper.xml

<mapper namespace="com.ogemray.dao.GradeDao">
    <select id="correlationQueryById" resultMap="gradeMap1">
        select 
            g.gid gid,
            g.gname gname,
            s.sid sid,
            s.sname sname,
            s.birthday birthday
        from
            grade g, student s
        where 
            g.gid = #{id} and g.gid = s.grade_id
    </select>
    
    <resultMap type="com.ogemray.entity.Grade" id="gradeMap1">
        <id property="gid" column="gid"/>
        <result property="gname" column="gname"/>
        
        <collection property="students" ofType="com.ogemray.entity.Student">
            <id property="id" column="sid"/>
            <result property="name" column="sname"/>
            <result property="birthday" column="birthday"/>
        </collection>
    </resultMap>
</mapper>
5. 使用 <collection> 標(biāo)簽實(shí)現(xiàn) 分步 集合關(guān)聯(lián)查詢

StudentMapper.xml

<mapper namespace="com.ogemray.dao.StudentDao">
    <select id="selectStudentsByGradeId" resultMap="resultMap1">
        select * from student where grade_id = #{gid}
    </select>

    <resultMap type="com.ogemray.entity.Student" id="resultMap1">
        <id property="id" column="sid"/>
        <result property="name" column="sname"/>
        <result property="birthday" column="birthday"/>
    </resultMap>
</mapper>

GradeMapper.xml

<mapper namespace="com.ogemray.dao.GradeDao">
    <select id="substepCorrelationQueryById" resultMap="gradeMap2">
        select * from grade where gid = #{id}
    </select>
    
    <resultMap type="com.ogemray.entity.Grade" id="gradeMap2">
        <id property="gid" column="gid"/>
        <result property="gname" column="gname"/>
        
        <collection property="students" 
                    select="com.ogemray.dao.StudentDao.selectStudentsByGradeId"
                    column="gid">
            <id property="id" column="sid" />
            <result property="name" column="sname" />
            <result property="birthday" column="birthday" />
        </collection>
    </resultMap>
</mapper>
//分別執(zhí)行SQL語句
DEBUG ==>  Preparing: select * from grade where gid = ? 
DEBUG ==> Parameters: 1(Integer)
DEBUG ====>  Preparing: select * from student where grade_id = ? 
DEBUG ====> Parameters: 1(Integer)

七槽奕、在分步查詢的基礎(chǔ)上配置懶加載

懶加載的概念几睛,了解過Hibernate的肯定都不陌生,Hibernate中涉及到關(guān)聯(lián)查詢的時(shí)候粤攒,懶加載是默認(rèn)就開啟著的枉长,懶加載就是在關(guān)聯(lián)查詢中,真正需要用到關(guān)聯(lián)對(duì)象的時(shí)候琼讽,才發(fā)起sql語句從數(shù)據(jù)庫(kù)中查詢數(shù)據(jù)必峰,從而實(shí)現(xiàn)提升數(shù)據(jù)庫(kù)性能的目的。
Mybatis作為一個(gè)優(yōu)秀的ORM框架當(dāng)然也支持懶加載钻蹬,和Hibernate不同是吼蚁,它默認(rèn)情況下是禁止了懶加載的,要使用懶加載需要手動(dòng)的開啟问欠,開啟的方法就是配置兩個(gè)全局變量:lazyLoadingEnabled設(shè)置為true肝匆,aggressiveLazyLoading設(shè)置為false

設(shè)置參數(shù) 描述 有效值 默認(rèn)值
lazyLoadingEnabled 延遲加載的全局開關(guān)。當(dāng)開啟時(shí)顺献,所有關(guān)聯(lián)對(duì)象都會(huì)延遲加載旗国。 特定關(guān)聯(lián)關(guān)系中可通過設(shè)置fetchType屬性來覆蓋該項(xiàng)的開關(guān)狀態(tài) true/false false
aggressiveLazyLoading 當(dāng)開啟時(shí),任何方法的調(diào)用都會(huì)加載該對(duì)象的所有屬性注整。否則能曾,每個(gè)屬性會(huì)按需加載 true/false false (true in ≤3.4.1)
<?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>
    <settings>
        <setting name="lazyLoadingEnabled" value="true"/>
        <setting name="aggressiveLazyLoading" value="false"/>
    </settings>
    ...
</configuration>

拿上面第六部分的 3 和 5分別用 <association> 標(biāo)簽和 <collection> 標(biāo)簽實(shí)現(xiàn)的分步查詢來做實(shí)驗(yàn)

1. 在 <association> 標(biāo)簽中實(shí)現(xiàn)懶加載

StudentMapper.xml

<mapper namespace="com.ogemray.dao.StudentDao">
    ...
    <resultMap type="com.ogemray.entity.Student" id="studentMap4">
        ...
        <association property="grade" 
                     select="com.ogemray.dao.GradeDao.selectOneById"
                     column="grade_Id">
        </association>
    </resultMap>
</mapper>

執(zhí)行測(cè)試代碼

StudentDao mapper = sqlSession.getMapper(StudentDao.class);
Student student = mapper.substepCorrelationQueryById(1);
System.out.println(student.getName());
System.out.println(student.getGrade().toString());

控制臺(tái)輸出

DEBUG ==>  Preparing: select * from student where sid = ? 
DEBUG ==> Parameters: 1(Integer)
DEBUG <==      Total: 1
Mike
DEBUG ==>  Preparing: select * from grade where gid = ? 
DEBUG ==> Parameters: 1(Integer)
DEBUG <==      Total: 1
Grade [gid=1, gname=文科一班]
2. 在 <collection> 標(biāo)簽中實(shí)現(xiàn)懶加載

GradeMapper.xml

<mapper namespace="com.ogemray.dao.GradeDao">
    ...
    <resultMap type="com.ogemray.entity.Grade" id="gradeMap2">
        ...
        <collection property="students" 
                    select="com.ogemray.dao.StudentDao.selectStudentsByGradeId"
                    column="gid">
            ...
        </collection>
    </resultMap>
</mapper>

執(zhí)行測(cè)試代碼

GradeDao mapper = sqlSession.getMapper(GradeDao.class);
Grade grade = mapper.substepCorrelationQueryById(1);
System.out.println(grade.getGname());
System.out.println(grade.getStudents().size());

控制臺(tái)輸出

DEBUG ==>  Preparing: select * from grade where gid = ? 
DEBUG ==> Parameters: 1(Integer)
DEBUG <==      Total: 1
文科一班
DEBUG ==>  Preparing: select * from student where grade_id = ? 
DEBUG ==> Parameters: 1(Integer)
DEBUG <==      Total: 2
2
3. 設(shè)置 fetchType 屬性來配置單個(gè)關(guān)聯(lián)查詢的加載策略

<association> 標(biāo)簽和 <collection> 標(biāo)簽都都有 fetchType 這么個(gè)屬性,他是用來指定該關(guān)聯(lián)在查詢時(shí)是否啟用懶加載肿轨,本身是可選值寿冕,但是設(shè)定了之后將會(huì)取代全局的 lazyLoadingEnabled 設(shè)置。
有效值為 lazyeager


八椒袍、MyBatis 動(dòng)態(tài) SQL

MyBatis 的強(qiáng)大特性之一便是它的動(dòng)態(tài) SQL驼唱。如果你有使用 JDBC 或其它類似框架的經(jīng)驗(yàn),你就能體會(huì)到根據(jù)不同條件拼接 SQL 語句的痛苦驹暑。例如拼接時(shí)要確保不能忘記添加必要的空格玫恳,還要注意去掉列表最后一個(gè)列名的逗號(hào)辨赐。利用動(dòng)態(tài) SQL 這一特性可以徹底擺脫這種痛苦。

動(dòng)態(tài) SQL 元素和 JSTL 或基于類似 XML 的文本處理器相似京办。在 MyBatis 之前的版本中掀序,有很多元素需要花時(shí)間了解。MyBatis 3 大大精簡(jiǎn)了元素種類臂港,現(xiàn)在只需學(xué)習(xí)原來一半的元素便可森枪。MyBatis 采用功能強(qiáng)大的基于 OGNL 的表達(dá)式來淘汰其它大部分元素。

1. if
public interface StudentDao {
    public List<Student> selectStudentsByName(@Param("name") String name);
}
<mapper namespace="com.ogemray.dao.StudentDao">
    <select id="selectStudentsByName" resultMap="resultMap1">
        select * from student where 1=1
        <if test="name != null">
            and sname like #{name}
        </if>
    </select> 
</mapper>

需要注意以下兩點(diǎn)
① 在接口中加@Param注解审孽,以防止以下異常 ReflectionException: There is no getter for property named...
② if標(biāo)簽里的test屬性里是用的OGNL表達(dá)式县袱,這是apache下的一個(gè)標(biāo)簽,用法類似jstl佑力,但有些小差別式散,具體的內(nèi)容可以在ognl官網(wǎng)上查詢,這里強(qiáng)調(diào)一點(diǎn)打颤,有些符號(hào)在xml文件里寫的時(shí)候暴拄,屬于特殊符號(hào),不能直接使用编饺,我們可以在w3cschool里查http://www.w3school.com.cn/tags/html_ref_entities.html

2. choose, when, otherwise
<select id="selectStudentsByName" resultMap="resultMap1">
    select * from student where 1=1
    <choose>
        <when test="name != null">
            and sname like #{name}
        </when>
        <otherwise>
            and sid = 1
        </otherwise>
    </choose>
</select> 

相當(dāng)于平時(shí)用到的 if (condition) { } else { } 判斷語句

3. where
<select id="selectStudentsByName" resultMap="resultMap1">
    select * from student
    <where>
        <if test="name != null">
            sname like #{name}
        </if>
    </where>
</select>

容易實(shí)現(xiàn)動(dòng)態(tài)添加 where 語句
但是遇到 where 標(biāo)簽里面有多個(gè)條件語句該怎么辦呢? 下面來看看 tirm 標(biāo)簽

4. trim
<select id="selectStudentsByName" resultMap="resultMap1">
    select * from student
    <where>
        <trim prefixOverrides="and">
            <if test="name != null">
                and sname like #{name}
            </if>
            <if test="name != null">
                and sid = 1
            </if>
        </trim>
    </where>
</select>

最終生成的 SQL語句
select * from student WHERE sname like ? and sid = 1 

trim 標(biāo)簽可以動(dòng)態(tài)對(duì)一段語句的首尾進(jìn)行操作乖篷,下面來看下 trim標(biāo)簽里面的其他屬性:

prefix:加前綴
prefixOverrides:匹配的前綴去掉
suffix:加后綴
suffixOverrides:匹配的后綴去掉

5. set
public interface StudentDao {
    public int updateStudent(@Param("student") Student student);
}
<update id="updateStudent">
    update student
    <set>
        <if test="student.name != null">sname = #{student.name}</if>
    </set>
    <where>
        <if test="student.id != 0">sid = #{student.id}</if>
    </where>
</update>

利用 set 標(biāo)簽可以實(shí)現(xiàn)動(dòng)態(tài)更新

6. foreach

平時(shí)開發(fā)中我們會(huì)遇到下面這樣的查詢語句

 select * from student where sid in (1, 2, 3)

這個(gè)時(shí)候可以用 foreach 標(biāo)簽做到這樣的效果

public interface StudentDao {
    public List<Student> selectPartStudent(@Param("sids") Integer[] sids);
}
<select id="selectPartStudent" resultMap="resultMap1">
    select * from student where sid in
    <foreach collection="sids" 
             item="id" 
             separator="," 
             open="("
             close=")">
        #{id}
    </foreach>
</select>

最終生成的 SQL 語句
select * from student where sid in ( ? , ? , ? ) 

對(duì)上面 foreach 標(biāo)簽里面的幾個(gè)屬性做下解釋
collection="ids":接口上傳過來的數(shù)值或list集合或者map集合都可以
item="id":設(shè)定遍歷集合或數(shù)組里的每一個(gè)值的迭代變量
separator=",": 因?yàn)橐獦?gòu)造出 (1,2,3)這種樣子的字符串,設(shè)定中間的分隔符
open="(": 因?yàn)橐獦?gòu)造出 (1,2,3)這種樣子的字符串透且,設(shè)定前綴的符號(hào)(
close=")":因?yàn)橐獦?gòu)造出 (1,2,3)這種樣子的字符串撕蔼,設(shè)計(jì)結(jié)尾的后綴)
index:還有這個(gè)屬性,數(shù)組或list集合的時(shí)候秽誊,設(shè)置索引變量鲸沮,如果是Map集合就是map的key的迭代變量,這里的例子用不著這個(gè)锅论。

7. bind

這個(gè)標(biāo)簽作用就是將OGNL標(biāo)簽里的值讼溺,進(jìn)行二次加工,在綁定到另一個(gè)變量里最易,供其他標(biāo)簽使用怒坯。

例如在用到模糊查詢時(shí)
方案一

public interface StudentDao {
    public List<Student> selectStudentsByName(@Param("name") String name);
}
<select id="selectStudentsByName" resultMap="resultMap1">
    select * from student where sname like #{name}
</select>

這時(shí)在調(diào)用的時(shí)候需要這么來寫

mapper.selectStudentsByName("%m%");

方案二
用 bind 標(biāo)簽來實(shí)現(xiàn)就簡(jiǎn)單多了

<select id="selectStudentsByName" resultMap="resultMap1">
    <bind name="_name" value="'%' + name + '%'"></bind>
    select * from student where sname like #{_name}
</select>

這個(gè)時(shí)候調(diào)用就方便多了,模糊查詢的效果同上面第一種方案一樣

mapper.selectStudentsByName("m");

九耘纱、MyBatis一級(jí)緩存

MyBatis 包含一個(gè)非常強(qiáng)大的查詢緩存特性敬肚,它可以非常方便地配置和定制。MyBatis 3 中的緩存實(shí)現(xiàn)的很多改進(jìn)都已經(jīng)實(shí)現(xiàn)了束析,使得它更加強(qiáng)大而且易于配置。
Mybatis 和 Hibernate一樣憎亚,也有一級(jí)和二級(jí)緩存员寇,同樣默認(rèn)開啟的只有一級(jí)緩存弄慰,二級(jí)緩存也需要手動(dòng)配置開啟,我們先看看一級(jí)緩存蝶锋。

一級(jí)緩存又被稱為 session 級(jí)別的緩存陆爽,mybatis一直默認(rèn)是開啟的,每個(gè)與數(shù)據(jù)庫(kù)的連接會(huì)話都有各自自己的緩存扳缕,這些一級(jí)緩存之間是不能通信的慌闭,是相互獨(dú)立的緩存空間!

總結(jié): 一級(jí)緩存其實(shí)就是一個(gè) Map躯舔,一個(gè) session 對(duì)應(yīng)一個(gè) Map驴剔,所以說兩個(gè)不同的 session 之間的一級(jí)緩存不共享,Map 里的 key 就是主鍵 id粥庄。所以查詢對(duì)象的時(shí)候丧失,先查緩存,緩存的 Map 對(duì)象中找不到時(shí)才會(huì)發(fā)送SQL語句惜互,查詢出來后會(huì)放到對(duì)應(yīng)的緩存 Map 里布讹。通過調(diào)用 session.clearCache() 可以用來清空緩存,同時(shí)增刪改也會(huì)刷新緩存训堆。


十描验、MyBatis二級(jí)緩存

Mybatis默認(rèn)情況下二級(jí)緩存是關(guān)閉的,需要手工的配置開啟坑鱼,在開啟之前膘流,我們先說說二級(jí)緩存的基本知識(shí)點(diǎn):

    1. 二級(jí)緩存又稱為全局緩存,它是基于 namespace 級(jí)別的緩存姑躲,一個(gè)名稱空間對(duì)應(yīng)一個(gè)二級(jí)緩存睡扬,也就是說一般情況下同一個(gè)映射文件中的查詢都共享一個(gè)共同的二級(jí)緩存空間。
    1. 一級(jí)緩存的生命周期隨著一次會(huì)話 session 的關(guān)閉而清空黍析,開啟二級(jí)緩存的情況下卖怜,一級(jí)緩存里的數(shù)據(jù),在清空或者提交之前會(huì)轉(zhuǎn)存到二級(jí)緩存的空間中繼續(xù)存在阐枣。
    1. 當(dāng)一次會(huì)話 sqlsession 的緩存里如果存放著兩個(gè)不同類型的對(duì)象马靠,比如 Grade 和 Student 對(duì)象,當(dāng)一級(jí)緩存清空之前蔼两,開起二級(jí)緩存的情況下甩鳄,它們兩個(gè)對(duì)象會(huì)分別存入各自的名稱空間的二級(jí)緩存空間中。直白的說就是一級(jí)緩存中兩個(gè)對(duì)象是放在同一Map對(duì)象(緩存就是Map對(duì)象)额划,在二級(jí)緩存中兩個(gè)對(duì)象是分別放在兩個(gè)獨(dú)立的Map對(duì)象里的(各自的緩存空間里)妙啃。

開啟二級(jí)緩存步驟

① 設(shè)置全局變量 cacheEnabled 設(shè)置為 true

設(shè)置參數(shù) 描述 有效值 默認(rèn)值
cacheEnabled 全局地開啟或關(guān)閉配置文件中的所有映射器已經(jīng)配置的任何緩存 true/false true
<?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>
    <settings>
        ...
        <!-- 開啟二級(jí)緩存 -->
        <setting name="cacheEnabled" value="true"/>
    </settings>
    ...
</configuration>

② 在映射文件中添加一個(gè)標(biāo)簽<cache/>

<?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.ogemray.dao.StudentDao">
    <cache />
    ...
</mapper>

<cache/>這個(gè)簡(jiǎn)單語句的效果如下:

  • 映射語句文件中的所有 select 語句將會(huì)被緩存。
  • 映射語句文件中的所有 insert,update 和 delete 語句會(huì)刷新緩存揖赴。
  • 緩存會(huì)使用 Least Recently Used(LRU馆匿,最近最少使用的)算法來收回。
  • 根據(jù)時(shí)間表(比如 no Flush Interval燥滑,沒有刷新間隔)渐北,緩存不會(huì)以任何時(shí)間順序來刷新。
  • 緩存會(huì)存儲(chǔ)列表集合或?qū)ο?無論查詢方法返回什么)的 1024 個(gè)引用铭拧。
  • 緩存會(huì)被視為是 read/write(可讀/可寫)的緩存赃蛛,意味著對(duì)象檢索不是共享的,而且可以安全地被調(diào)用者修改搀菩,而不干擾其他調(diào)用者或線程所做的潛在修改呕臂。

<cache/>這個(gè)標(biāo)簽中還有很多與緩存有關(guān)的屬性:
eviction:可用的收回策略有:

  • LRU – 最近最少使用的,移除最長(zhǎng)時(shí)間不被使用的對(duì)象秕磷。
  • FIFO – 先進(jìn)先出诵闭,按對(duì)象進(jìn)入緩存的順序來移除它們。
  • SOFT – 軟引用澎嚣,移除基于垃圾回收器狀態(tài)和軟引用規(guī)則的對(duì)象疏尿。
  • WEAK – 弱引用,更積極地移除基于垃圾收集器狀態(tài)和弱引用規(guī)則的對(duì)象易桃。

默認(rèn)的是 LRU褥琐。

flushInterval:刷新間隔,可以被設(shè)置為任意的正整數(shù)晤郑,而且它們代表一個(gè)合理的毫秒形式的時(shí)間段敌呈。默認(rèn)情況是不設(shè)置,也就是沒有刷新間隔造寝,緩存僅僅調(diào)用語句時(shí)刷新磕洪。
size:引用數(shù)目,可以被設(shè)置為任意正整數(shù)诫龙,要記住你緩存的對(duì)象數(shù)目和你運(yùn)行環(huán)境的可用內(nèi)存資源數(shù)目析显。默認(rèn)值是 1024。
readOnly:(只讀)屬性可以被設(shè)置為 true 或 false签赃。只讀的緩存會(huì)給所有調(diào)用者返回緩存對(duì)象的相同實(shí)例谷异,因此這些對(duì)象不能被修改,這提供了很重要的性能優(yōu)勢(shì)锦聊〈踵冢可讀寫的緩存會(huì)返回緩存對(duì)象的拷貝(通過序列化) 。這會(huì)慢一些孔庭,但是安全尺上,因此默認(rèn)是 false。

<cache
  eviction="FIFO"
  flushInterval="60000"
  size="512"
  readOnly="true"/>

這個(gè)更高級(jí)的配置創(chuàng)建了一個(gè) FIFO 緩存,并每隔 60 秒刷新尖昏,存數(shù)結(jié)果對(duì)象或列表的 512 個(gè)引用仰税,而且返回的對(duì)象被認(rèn)為是只讀的构资,因此在不同線程中的調(diào)用者之間修改它們會(huì)導(dǎo)致沖突抽诉。

③ Mybatis的二級(jí)緩存使用的序列化接口,所以吐绵,我們要使用二級(jí)緩存迹淌,我們的JavaBean就必須實(shí)現(xiàn)序列化接口

public class Student implements Serializable {
    private static final long serialVersionUID = 1L;
    ...
}

代碼測(cè)試

SqlSession sqlSession1 = sqlSessionFactory.openSession();
StudentDao mapper1 = sqlSession1.getMapper(StudentDao.class);
Student student1 = mapper1.selectOneById(1);
System.out.println(student1);
sqlSession1.close();

SqlSession sqlSession2 = sqlSessionFactory.openSession();
StudentDao mapper2 = sqlSession2.getMapper(StudentDao.class);
Student student2 = mapper2.selectOneById(1);
System.out.println(student2);
sqlSession2.close();
DEBUG ==>  Preparing: select * from student where sid = ? 
DEBUG ==> Parameters: 1(Integer)
DEBUG <==      Total: 1
Student [id=1, name=Mike, birthday=Mon Nov 05 00:00:00 CST 2018, grade=null]

DEBUG Cache Hit Ratio [com.ogemray.dao.StudentDao]: 0.5
Student [id=1, name=Mike, birthday=Mon Nov 05 00:00:00 CST 2018, grade=null]

從上面可以看出,用兩個(gè)不同的 session 查詢同個(gè)對(duì)象只發(fā)送一次 SQL語句己单。注意唉窃,在用另一個(gè) session 查詢前先將上個(gè) session 關(guān)閉,這樣才會(huì)將一級(jí)緩存里面的數(shù)據(jù)放到二級(jí)緩存里面纹笼。

注意
① 設(shè)置 useCache=false 可以禁用當(dāng)前 select 語句的二級(jí)緩存纹份,即每次查詢都會(huì)發(fā)出 sql 去查詢,默認(rèn)情況是 true廷痘,即該sql使用二級(jí)緩存蔓涧。

<select id="selectOneById" resultMap="resultMap1" useCache="false">
    select * from student where sid = #{id}
</select>

② 清空緩存 flushCache 屬性

  • flushCache默認(rèn)為false,表示任何時(shí)候語句被調(diào)用笋额,都不會(huì)去清空本地緩存和二級(jí)緩存元暴。
  • useCache默認(rèn)為true,表示會(huì)將本條語句的結(jié)果進(jìn)行二級(jí)緩存兄猩。
  • 在insert茉盏、update、delete語句時(shí): flushCache默認(rèn)為true枢冤,表示任何時(shí)候語句被調(diào)用鸠姨,都會(huì)導(dǎo)致本地緩存和二級(jí)緩存被清空。 useCache屬性在該情況下沒有淹真。例如如果 update 的時(shí)候如果 flushCache="false"讶迁,則當(dāng)你更新后,查詢的數(shù)據(jù)數(shù)據(jù)還是老的數(shù)據(jù)趟咆。

如果沒有去配置flushCache添瓷、useCache踏幻,那么默認(rèn)是啟用緩存的

<select id="selectOneById" 
        resultMap="resultMap1" 
        useCache="true"
        flushCache="false">
    select * from student where sid = #{id}
</select>
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末陷寝,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子怠蹂,更是在濱河造成了極大的恐慌虐唠,老刑警劉巖搀愧,帶你破解...
    沈念sama閱讀 222,590評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡咱筛,警方通過查閱死者的電腦和手機(jī)搓幌,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,157評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來迅箩,“玉大人溉愁,你說我怎么就攤上這事∷乔鳎” “怎么了拐揭?”我有些...
    開封第一講書人閱讀 169,301評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)奕塑。 經(jīng)常有香客問我堂污,道長(zhǎng),這世上最難降的妖魔是什么龄砰? 我笑而不...
    開封第一講書人閱讀 60,078評(píng)論 1 300
  • 正文 為了忘掉前任盟猖,我火速辦了婚禮,結(jié)果婚禮上换棚,老公的妹妹穿的比我還像新娘式镐。我一直安慰自己,他們只是感情好圃泡,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,082評(píng)論 6 398
  • 文/花漫 我一把揭開白布碟案。 她就那樣靜靜地躺著,像睡著了一般颇蜡。 火紅的嫁衣襯著肌膚如雪价说。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,682評(píng)論 1 312
  • 那天风秤,我揣著相機(jī)與錄音鳖目,去河邊找鬼。 笑死缤弦,一個(gè)胖子當(dāng)著我的面吹牛领迈,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播碍沐,決...
    沈念sama閱讀 41,155評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼狸捅,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了累提?” 一聲冷哼從身側(cè)響起尘喝,我...
    開封第一講書人閱讀 40,098評(píng)論 0 277
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎斋陪,沒想到半個(gè)月后朽褪,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體置吓,經(jīng)...
    沈念sama閱讀 46,638評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,701評(píng)論 3 342
  • 正文 我和宋清朗相戀三年缔赠,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了衍锚。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,852評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡嗤堰,死狀恐怖戴质,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情梁棠,我是刑警寧澤置森,帶...
    沈念sama閱讀 36,520評(píng)論 5 351
  • 正文 年R本政府宣布,位于F島的核電站符糊,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏呛凶。R本人自食惡果不足惜男娄,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,181評(píng)論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望漾稀。 院中可真熱鬧模闲,春花似錦、人聲如沸崭捍。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,674評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽殷蛇。三九已至实夹,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間粒梦,已是汗流浹背亮航。 一陣腳步聲響...
    開封第一講書人閱讀 33,788評(píng)論 1 274
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留匀们,地道東北人缴淋。 一個(gè)月前我還...
    沈念sama閱讀 49,279評(píng)論 3 379
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像泄朴,于是被迫代替她去往敵國(guó)和親重抖。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,851評(píng)論 2 361

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

  • 1. 簡(jiǎn)介 1.1 什么是 MyBatis 祖灰? MyBatis 是支持定制化 SQL钟沛、存儲(chǔ)過程以及高級(jí)映射的優(yōu)秀的...
    笨鳥慢飛閱讀 5,532評(píng)論 0 4
  • 1 Mybatis入門 1.1 單獨(dú)使用jdbc編程問題總結(jié) 1.1.1 jdbc程序 上邊使...
    哇哈哈E閱讀 3,312評(píng)論 0 38
  • 官方文檔 簡(jiǎn)介 入門 XML配置 XML映射文件 動(dòng)態(tài)SQL Java API SQL語句構(gòu)建器 日志 一、 JD...
    拾壹北閱讀 3,548評(píng)論 0 52
  • 簡(jiǎn)介 MyBatis 的真正強(qiáng)大在于它的映射語句夫植,也是它的魔力所在讹剔。由于它的異常強(qiáng)大油讯,映射器的 XML 文件就顯得...
    coderLumia閱讀 808評(píng)論 0 0
  • 《深入淺出MyBatis技術(shù)原理與實(shí)戰(zhàn)》2016年版本 讀書筆記 第一章 MyBatis簡(jiǎn)介 1.ORM模型:對(duì)象...
    GunnerAha閱讀 557評(píng)論 0 3