1. 程式人生 > >ssm框架學習---mybatis中延遲載入實現

ssm框架學習---mybatis中延遲載入實現

在處理查詢結果中,如果需要延遲載入,即屬於對查詢結果有要求的那種,需要使用resultMap來實現,並結合association或者collection,

引入延遲載入的目的:單表或者簡單聯合查詢速度較快,通過延遲載入可以按需載入,減輕資料庫的壓力。

假設需求時查詢訂單時延遲載入所關聯的使用者資訊,定義mapper.xml檔案如下;

    <!--需求:實現延遲載入,先查詢出訂單資訊,然後再延遲載入訂單所對應的使用者資訊-->
    <!--定義延遲載入的resultmap,因為只有resultMap有延遲載入的功能,因此這裡不能夠使用resultType-->
    <resultMap id="OrdersCustomerLazyLoadingMap" type="com.ajin.mybatis.model.OrdersCustomerMap">
        <!--配置訂單的基本資訊-->
        <id column="ono" property="ono"></id>
        <result column="otime" property="otime"></result>
        <result column="gno" property="gno"></result>
        <result column="cno" property="cno"></result>
        <!--配置關聯的使用者資訊,使用association實現延遲載入
        select:用來指定延遲載入查詢語句的sql,這裡引用了CustomerMapper中的statement,因此需要新增完整名稱空間
        column:用來指定關聯的用來關聯查詢的屬性
        -->
        <association property="customer" javaType="com.ajin.mybatis.model.Customer" select="com.ajin.mybatis.mapper.CustomerMapper.selectCustomerById" column="cno">
            <!--需要注意這裡和普通的一對一關聯查詢不一樣,這裡面不需要寫任何東西-->
        </association>
    </resultMap>
    <!--這裡面只需要編寫單表查詢訂單的sql語句-->
    <select id="selectOrdersCustomerLazyLoading" resultMap="OrdersCustomerLazyLoadingMap">
       select * from orders;
    </select>
其中在association中引用了一個依據id查詢Customer的statement,它的定義如下:
<?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.ajin.mybatis.mapper.CustomerMapper">
   <select id="selectCustomerById" parameterType="int" resultType="com.ajin.mybatis.model.Customer">
       select * from customer where cno=#{value}
   </select>
</mapper>
至於這個statement對應的介面定義這裡就不列出來了,很簡單。

接下來是上述mapper.xml對應的介面定義如下:

package com.ajin.mybatis.mapper;

import com.ajin.mybatis.model.OrdersCustomerMap;
import com.ajin.mybatis.model.OrdersCustomer;

import java.util.List;

/**
 * Created by ajin on 16-12-19.
 */
public interface OrdersCustomerMapper {
    //基於resultType方式一對一查詢
    public OrdersCustomer selectOrdersCustomerById(int id);
    //基於resultMap方式一對一查詢
    public OrdersCustomerMap selectOrdersCustomerMapById(int id);
    //延遲載入介面方法定義
    public List<OrdersCustomerMap> selectOrdersCustomerLazyLoading();
}
在編寫測試用例之前,需要將上述的xml檔案新增到sqlMapConfig.xml的mybatis配置檔案中,同時因為需要用到延遲載入功能,但是預設沒有開啟,需要如下設定
  <!--配置延遲載入屬性,首先開啟延遲載入,然後關閉積極載入-->
    <settings>
        <setting name="lazyLoadingEnabled" value="true"/>
        <setting name="aggressiveLazyLoading" value="false"/>
    </settings>
最後編寫我們的測試用例:
package com.ajin.mybatis.mapper;

import com.ajin.mybatis.model.Customer;
import com.ajin.mybatis.model.OrdersCustomerMap;
import com.ajin.mybatis.model.OrdersCustomer;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Before;
import org.junit.Test;

import java.io.InputStream;
import java.util.List;

import static org.junit.Assert.*;

/**
 * Created by ajin on 16-12-19.
 */
public class OrdersCustomerMapperTest {
    private SqlSessionFactory sqlSessionFactory;
    @Before
    public void setUp() throws Exception {
        String resource = "config/SqlMapConfig.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    }


    @Test
    public void selectOrdersCustomerById() throws Exception {
        SqlSession sqlSession = sqlSessionFactory.openSession();
        try{
            OrdersCustomerMapper ordersCustomerMapper = sqlSession.getMapper(OrdersCustomerMapper.class);
            OrdersCustomer ordersCustomer=ordersCustomerMapper.selectOrdersCustomerById(5);
            System.out.println(ordersCustomer);
        }finally {
           sqlSession.close();
        }
    }

    @Test
    public void selectOrdersCustomerMapById() throws Exception {
        SqlSession sqlSession = sqlSessionFactory.openSession();
        try{
            OrdersCustomerMapper ordersCustomerMapper = sqlSession.getMapper(OrdersCustomerMapper.class);
            OrdersCustomerMap ordersCustomer=ordersCustomerMapper.selectOrdersCustomerMapById(5);
            System.out.println(ordersCustomer);
        }finally {
            sqlSession.close();
        }
    }

    @Test
    public void selectOrdersCustomerLazyLoading() throws Exception {
        SqlSession sqlSession = sqlSessionFactory.openSession();
        try{
            OrdersCustomerMapper ordersCustomerMapper = sqlSession.getMapper(OrdersCustomerMapper.class);
            //在執行下面這句的時候,只是會執行對於訂單表的單表查詢
//            日誌輸出如下:
//            DEBUG [main] - ==>  Preparing: select * from orders;
//            DEBUG [main] - ==> Parameters:
//            DEBUG [main] - <==      Total: 7
            List<OrdersCustomerMap> lists=ordersCustomerMapper.selectOrdersCustomerLazyLoading();
            for(OrdersCustomerMap list:lists){
                //在執行這一句話時才會延遲載入去獲得所關聯的使用者資訊
//                日誌輸出如下:
//                DEBUG [main] - ==>  Preparing: select * from customer where cno=?
//                DEBUG [main] - ==> Parameters: 1(Integer)
//                        DEBUG [main] - <==      Total: 1
//                Customer{cno=1, cname='zcj', csex='male', cphone='13036144569', caddress='wuhan'}
                //並且在查詢相同的id時,並不會從新生成sql語句,這就涉及到一級快取了
                Customer customer =list.getCustomer();
                System.out.println(customer);
            }
        }finally {
            sqlSession.close();
        }
    }


}
使用collection的方法類似,當然如果框架沒有提供,我們可以採用二次呼叫不同mapper的介面方法來實現延遲載入,框架只是將這一層給封裝到了一起,內部原理仍然如此