JavaWeb筆記(23)-mybatis緩存與註解

  1. mybatis中的延遲加載
1. 問題出現:
    a. 在一對多關聯中:用戶表與賬戶表
        1. 如果一個用戶含有數量龐大的賬戶,則查詢用戶信息時,是否需要將其List<Account>查詢出來?
            * 我們希望不使用賬戶信息時,查詢用戶信息則僅不在內存中查詢存儲List<Accout>
            * 只有在使用賬戶信息時,才查詢List<Account>信息
        2. 如果查詢一個賬戶信息時,是否需要將其所屬的用戶信息查詢出來?
            * 我們希望在顯示賬戶信息時,同時顯示用戶的部分信息,如姓名,年齡等
2. mybatis中的延遲加載:
    a. 延遲加載:
        只有在真正使用數據時才發起查詢,不使用時不查詢。按需加載
    b. 立即加載:
        不管是否使用信息,只要有關聯,則立即查詢所有信息
    c. 表間關係與適用場景:
        1. 一對多/多對多:
            通常採用延遲加載
        2. 多對一/一對一:
            通常採用立即加載
  1. 一對一的延遲加載
1. 設置開啓延遲加載功能:
    修改配置文件SqlMapConfig.xml:
        在標籤<configuration>中添加:
            <settings>
                <setting name="lazyLoadingEnabled" value="true"/>
                <setting name="aggressiveLazyLoading" vaule="false"/>
            </settings>
2. 查詢賬戶信息,延遲查找其所屬的用戶信息
    a. 配置IAccountDao.xml文件:
        1. 配置findAll的抽象方法的select
            * 由於延遲查詢所屬用戶信息,因此當前select標籤中sql語句僅查詢account信息
            <select id="findAll" resultMap="accountUserMap">
                select * from account 
            </select>
        2. 配置IAccountDao.xml中的resultMap標籤
            * 由於延遲查詢所屬用戶信息,因此在association標籤中不再配置數據的封裝
                <!--最外層的type依舊爲賬戶類的類型(用戶類引用封裝在該類中),此處使用了別名-->
                <resultMap id="accountUserMap" type="accout">
                    <!--賬戶表主鍵-->
                    <id property="id" column="id"></id>
                    <!--賬戶表非主鍵-->
                    <result property="uid" column="uid"></result>
                    <result property="money" column="money"></result>
                    <!--配置賬戶表中一對一映射關係,使用association標籤,封裝user的內容-->
                    <!--其中property爲賬戶類中用戶類成員變量的屬性名,column屬性爲關聯的對對應的外鍵列-->
                    <!--javaType表示association標籤內的數據封裝爲的實體類全限定類名(可以使用別名)-->
                    <association property="user" column="uid" javaType="user" select="cn.mysilent.dao.IUserDao.findUserById">
                        <!--內部不再需要封裝數據-->
                        <!--延遲查詢添加select屬性,表示調用IUserDao中的id爲findUserById的select標籤查詢-->
                        <!--findUserById中傳入的id參數爲column屬性的值,即使用賬戶表中uid去查-->
                    </association>
                </resultMap>
        3. 配置IUserDao.xml中的select標籤:
            * 延遲查詢,當需要用戶信息時,則會調用id爲findUserById的select標籤
            * 因此,在IUserDao.java中需要提供該抽象方法,在IUserDao.xml中配置該查詢語句
                <!--此處根據id查詢用戶信息,返回的參數類型爲user類型(resultType屬性值)-->
                <select id="findUserById" parameterType="Integer" resultType="user">
                    <!--每次調用該標籤時,傳入查詢的id值-->
                    select * from user where id=#{id}
                </select>
            * 添加抽象方法:
                User findUserById(Integer id);
3. 當僅查詢賬戶信息時,並不會查詢用戶信息,只有當需要用戶信息時,纔會調用相應的IUserDao中的方法進行延遲查詢
  1. 一對多的延遲加載
1. 設置開啓延遲加載功能:
    修改配置文件SqlMapConfig.xml:
        在標籤<configuration>中添加:
            <settings>
                <setting name="lazyLoadingEnabled" value="true"/>
                <setting name="aggressiveLazyLoading" vaule="false"/>
            </settings>
2. 查詢用戶信息,延遲查找其所包含的所有賬戶信息
    a. 配置IUserDao.xml文件:
        1. 配置findAll的抽象方法的select
            * 由於延遲查詢所包含賬戶信息,因此當前select標籤中sql語句僅查詢user信息
            <select id="findAll" resultMap="userAccountMap">
                select * from user 
            </select>
        2. 配置IUserDao.xml中的resultMap標籤
            * 由於延遲查詢所包含賬戶信息,因此在collection標籤中不再配置數據的封裝
                <!--最外層的type依舊爲賬戶類的類型(用戶類引用封裝在該類中),此處使用了別名-->
                <resultMap id="userAccountMap" type="accout">
                    <!--用戶表主鍵-->
                    <id property="id" column="id"></id>
                    <!--用戶表非主鍵-->
                    <result property="username" column="username"></result>
                    <result property="address" column="address"></result>
                    <result property="sex" column="sex"></result>
                    <result property="birthday" column="birthday"></result>
                    <!--配置用戶表中一對多映射關係,使用collection標籤,表示封裝的是一個集合-->
                    <!--其中property爲用戶類中賬戶類列表成員變量的屬性名-->
                    <!--ofType表示集合內的數據封裝爲的實體類全限定類名(可以使用別名)-->
                    <collection property="accounts" ofType="account" select="cn.mysilent.dao.IAccountDao.findAccountByUid" column="id">
                        <!--
                        內部不再需要封裝數據
                        延遲查詢添加select屬性,表示調用IAccountDao中的id爲findAccountByUid的select標籤查詢
                        findAccountByUid中傳入的uid參數爲column屬性的值,即使用用戶表中的id去查
                        -->
                    </collection>
                </resultMap>
        3. 配置IAccountDao.xml中的select標籤:
            * 延遲查詢,當需要賬戶信息時,則會調用id爲findAccountByUid的select標籤
            * 因此,在IAccountDao.java中需要提供該抽象方法,在IAccountDao.xml中配置該查詢語句
                <!--此處根據uid查詢賬戶信息,返回的參數類型爲user類型(resultType屬性值)-->
                <select id="findAccountByUid" parameterType="Integer" resultType="account">
                    <!--每次調用該標籤時,傳入查詢的id值-->
                    select * from account where uid=#{uid}
                </select>
            * 添加抽象方法:
                List<Account> findAccountByUid(Integer uid);
3. 當僅查詢用戶信息時,並不會查詢所含賬戶信息
    只有當需要賬戶信息時,纔會調用相應的IAccountDao中的方法進行延遲查詢
  1. mybatis中的緩存
1. 緩存使用:
    a. 減少數據庫的交互,提高執行效率
    b. 數據經常查詢且不經常改變
    c. 數據的正確性與否對最終結果影響不大
2. mybatis中的緩存:
    a. 一級緩存:
        * 指的是mybatis中SqlSession對象的緩存:
            當執行查詢後,查詢結果會同時存儲到SqlSession對象的一個map區域中
            當再次查詢相同的數據,有現在SqlSession對象中查詢是否含有該數據,有則直接取出
            當SqlSession對象銷燬時,一級緩存釋放
        * 發起兩次相同的查詢時,可以通過日誌發現僅向數據庫發起第一次查詢
            可以使用SqlSession對象的clearCache()方法清空緩存
        * SqlSession對象調用更新,插入,刪除,commit,close方法時,會清空一級緩存
    b. 二級緩存:
        * 指的是mybatis中SqlSessionFactory對象的緩存:
            由同一個SqlSessionFactory創建的SqlSession對象共享該緩存
        * 二級緩存使用步驟:
            1. 讓mybatis框架支持二級緩存    --  在SqlMapConfig.xml中配置
                添加setting配置標籤
                <settings>
                    <setting name="cacheEnabled" value="true"/>
                </settings>
            2. 讓當前的映射文件支持二級緩存 --  在IUserDao.xml中配置
                添加cache配置標籤
                <cache/>
            3. 讓當前的操作支持二級緩存     --  在select標籤中配置
                在select屬性中添加useCache="true"
        * 二級緩存中存放的是數據,而非對象
            對象是在SqlSession對象中封裝,儘管不同的SqlSession對象進行相同查詢在日誌中僅查詢了一次數據庫
            但是查詢的結果的地址值是不相等的
            而一級緩存由於是同一個SqlSession對象內封裝的對象,因此多次重複查詢的對象地址值相同
  1. mybatis註解開發:
1. 原始配置文件有SqlMapConfig.xml和對應mappers的xml配置文件
2. 使用註解開發即使用註解來配置關於mappers的xml配置文件中的內容,SqlMapConfig.xml仍然需要配置
3. 使用步驟:
    a. 創建SqlMapConfig.xml配置文件,填寫相關配置信息
    b. 在SqlMapConfig.xml的mappers中使用package標籤配置帶有註解的包
    c. mybatis中針對CRUD提供了4中註解@SELECT@UPDATE@INSERT@DELETE
    d. 在每個註解中寫入sql語句
4. 在mybatis開發中,如果使用了註解,還配置了映射的xml文件,則會報錯。
    解決方案:刪除映射的xml配置文件
5. @Results@Result註解:
    解決表列名和實體類的屬性名稱對應不上問題
    @Select("select * from user ")
    @Results(value={
        @Result(id=true, property="實體類屬性名", column="數據庫表列名"),
        @Result(id=false, property="實體類屬性名", column="數據庫表列名"),
        @Result(id=false, property="實體類屬性名", column="數據庫表列名"),
        ...
    })
    List<User> findAll();
6. 在Results註解中還包含有一個id屬性,用於爲該Results起一個別名
    這樣其他方法可以引用該Results配置,引用使用ResulMap註解,參數傳入Results註解id屬性值
    @Select("select * from user ")
    @Results(id="resultMap1", value={
        @Result(id=true, property="實體類屬性名", column="數據庫表列名"),
        //idw爲true表示爲主鍵
        ...
    })
    List<User> findAll();
    
    @Select("select * from user where id=#{id} ")
    @ResultMap(value={"resultMap1"})
    User findUserById(Integer id);
    
    //當插入語句中的參數和形參列表中的參數具有多個時,使用@Param註解標註該參數對應語句中哪個參數
    @Insert("insert into users_role(userId,roleId) values(#{uid}, #{rId})")
    void addRoleToUser(@Param("uid") String userId, @Param("rId") String roleId);
  1. mybatis多表查詢註解開發
1. 一對一(多對一)關聯:
    示例:查詢賬戶信息,同時獲取該賬戶所屬的用戶信息
    使用查詢的註解配置:
        * 類似IAccountDao.xml中配置一樣,在註解@Results中配置一個結果集
        *@Result註解中定義有One類型的註解@One和Many類型的註解@Many
        * 在一對一的@Result註解中,使用@One配置,@One註解中定義了select()
        * select()與IAccountDao.xml中select屬性的作用一致,用於調用所指向的唯一查詢方法
        * @One註解中還定義了一個FetchType類型的數值,用於標識是否延遲LAZY(延遲)EAGER(立即),DEFAULT
        * 一對一應該使用立即而非延遲,一對多使用延遲查詢
        IAccountDao.java文件:
        @Select("select * from account ")
        @Results(value={
            @Result(id=true, property="id", column="id"),//設置id屬性爲true表示爲主鍵,默認爲false
            @Result(property="uid", column="uid"),
            @Result(property="money", column="money"),
            //接下來配置賬戶信息與用戶信息的一對一關係
            //property爲Account類中的User對象的引用名稱
            //column爲通過Account表中哪個值來關聯查詢
            //one表示這是一對一的關聯關係
            @Result(property="user", column="uid", 
                //定義關聯查詢時該調用的方法
                one=@One(select="cn.mysilent.dao.IUserDao.findById", fetchType=FetchType.EAGER))
        })
        在IUserDao.java文件中需要提供對應的findById查詢方法:
        @Select("select * from user where id=#{id} ")
        User findById(Integer id);
2. 一對多(多對多)關聯:
    示例:查詢用戶信息,同時獲取該用戶所包含的所有賬戶信息
    使用查詢的註解配置:
        * 類似IUserDao.xml中配置一樣,在註解@Results中配置一個結果集
        *@Result註解中定義有One類型的註解@One和Many類型的註解@Many
        * 在一對多的@Result註解中,使用@Many配置,@Many註解中定義了select()
        * select()與IUserDao.xml中select屬性的作用一致,用於調用所指向的唯一查詢方法
        * @Many註解中還定義了一個FetchType類型的數值,用於標識是否延遲LAZY(延遲)EAGER(立即),DEFAULT
        * 一對一應該使用立即而非延遲,一對多使用延遲查詢
        IUserDao.java文件中:
        @Select("select * from user ")
        @Results(value={
            @Result(id=true, property="id", column="id"),//設置id屬性爲true表示爲主鍵,默認爲false
            @Result(property="name", column="name"),
            @Result(property="address", column="address"),
            @Result(property="sex", column="sex"),
            @Result(property="birthday", column="birthday"),
            //接下來配置用戶信息與賬戶信息的一對多關係
            //property爲User對象中Account對象引用集合名稱
            //column爲通過User表中哪個值來關聯查詢
            //many表示這是一對多的關聯關係
            @Result(property="accounts", column="id", 
                //定義關聯查詢時該調用的方法
                many=@Many(select="cn.mysilent.dao.IAccountDao.findAccountByUid", fetchType=FetchType.LAZY))
        })
        在IAccountDao.java文件中需要提供對應的findAccountByUid查詢方法:
        @Select("select * from account where uid=#{uid} ")
        List<Account> findAccountByUid(Integer uid);
  1. 使用註解時開啓二級緩存使用:
1. 在xml配置中使用二級緩存步驟爲:
    a. 讓mybatis框架支持二級緩存    --  在SqlMapConfig.xml中配置
        添加setting配置標籤
        <settings>
            <setting name="cacheEnabled" value="true"/>
        </settings>
    b. 讓當前的映射文件支持二級緩存 --  在IUserDao.xml中配置
        添加cache配置標籤
        <cache/>
    c. 讓當前的操作支持二級緩存     --  在select標籤中配置
        在select屬性中添加useCache="true"
2. 當使用註解配置使用二級緩存時步驟爲:
    a. 讓mybatis框架支持二級緩存    --  在SqlMapConfig.xml中配置
        添加setting配置標籤
        <settings>
            <setting name="cacheEnabled" value="true"/>
        </settings>
    b. 在需要使用二級緩存的接口定義上方添加註解@CacheNamespace,設置blocking屬性爲true
        @CacheNamespace(blocking=true)
        public Interface IUserDao {
            //...
        }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章