mybatis 框架 resultMap 的延迟加载功能的实现

为什么需要延迟加载?


在我们的实际开发中,如果单表查询能满足业务需求。尽量用单表查询,因为单表查询的效率比多表关联查询快。那么当业务需求需要用到多表查询,我们应该怎么办呢?Mybatis 引入了延迟加载的概念


什么叫延迟加载?


为了满足业务需求,必须进行多表查询时,可以先进行单表查询 ,在业务信息中需要用到关联表信息的时候,再进行关联表的单表查询。resultMap可以实现高级映射(使用association、collection实现一对一及其一对多),association、collection具有延迟加载的功能。

在SqlMapConfgi.xml中配置延迟加载开关:

<!--开启延迟加载的总开关  -->

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

<!--开启按需加载的开关  -->

<setting name="aggressiveLazyLoading" value="false"/>


需求:如果查询订单并且关联查询用户信息。如果先查询订单信息即可满足要求,当我们需要查询用户信息时候,把对用户信息的按需去查询就叫做延迟加载。

延迟加载:先从单表查询,需要时再从关联表去查询,大大提高数据库的性能,因为单表查询要比多表关联查询速度要快。

使用association实现延迟加载

需求:

查询订单并且关联查询用户信息

延迟加载的resultMap的配置

使用association中的select指定延迟加载执行的statementid

   <!-- 延迟加载的resultMap -->

   <resultMap type="com.wbs.domain.Orders"id="findOrdersUserLazyLoading">

      <!-- 对订单信息进行映射配置 -->

      <id column="id" property="id"/>

      <result column="user_id"property="user_id" />

      <result column="numbers"property="number" />

      <result column="createtime"property="createtime" />

      <result column="note"property="note" />

      <!-- 实现对用户信息延迟加载

      要使用mapper.xmlfindUserById完成用户的iduser_id)完成用户信息的查询,如果

      它不在本mapper中,前边需要加namespace

      select:指定延迟加载所需要执行的statementid(是根据user_id查询用户信息的statement

      column:订单信息中关联用户信息查询的列,是user_id    

      关联查询的SQL可以理解为select orders.*, (select username

      fromusers where users.id=orders.user_id)username ,

      (selectsex from users where users.id=orders.user_id)sex

      fromorders

      -->

      <association property="user"javaType="com.wbs.domain.User"

      select="com.wbs.mapper.UserMapper.findUserById"column="user_id">

        

      </association>

   </resultMap>

Mapper.xml

需要定义两个mapper的方法定义statement

1.     只查询订单信息

Select * from orders

2.     在查询订单的statement中使用association去延迟加载(执行)下边的statement(关联查询用户信息)

<!-- 查询订单,关联查询用户信息,用户信息通过延迟加载 -->

   <select id="findOrdersUserLazyLoading"resultMap="findOrdersUserLazyLoading">

      select* from orders

   </select>

3.     关联查询用户信息

a)      通过上边查询到的订单信息中的user_id去关联查询用户信息。

 <select id="findUserById"parameterType="int" resultType="user">

         select * from users where id=#{value}

      </select>

上边先去执行findOrdersUserLazyLoading当需要去查询用户的时候,再执行findUserById通过resultMap的定义将延迟加载执行配置起来。

Mapper.java

//查询订单,关联查询用户,用户信息是延迟加载

   public List<Orders>findOrdersUserLazyLoading() throwsException;

测试:

1.    执行上边mapperde的findOrderUserLazyLoading方法,内部调用com.wbs.mapper.OrdersMapperCustomer的findOrderUserLazyLoading方法只查询orders信息(单表)

2.    在程序中遍历上一步查询出的List<Orders>,当我们调用orders中的getUser方法时候,开始进行延迟加载,去调用usermapper.xml中调用findUserById这个方法获取用户信息

延迟加载的配置

Mybatis默认没有开启延迟加载,需要在SqlMapConfig.xml中配置

lazyLoadingEnabled

aggressiveLazyLoading

注意上边两个单词的拼写,首字母都是小写的

      <settings>

      <!-- 打开延迟加载的开关 -->

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

      <!-- 将积极加载改为消极加载 -->

      <setting name="aggressiveLazyLoading"value="false"/>

      </settings>

测试代码:

publicclass Demo9 {

      //查询订单,关联查询用户信息,用户信息延迟加载

      @Test

      publicvoid findOrderUser() throwsException{

         Stringresource="SqlMapConfig.xml";

         InputStreamis=Resources.getResourceAsStream(resource);

         SqlSessionFactorysqlSessionFactory=new SqlSessionFactoryBuilder().build(is);

         SqlSessionsqlsession=sqlSessionFactory.openSession();

         OrdersMapperCustomerordersmappercustomer=sqlsession.getMapper(OrdersMapperCustomer.class);

         List<Orders>list=ordersmappercustomer.findOrdersUserLazyLoading();

         //遍历上边的订单列表

         for(Orders orders :list){

            //执行getUser()查询用户信息,实现延迟加载

            Useruser=orders.getUser();

            System.out.println(user);

         }

         sqlsession.close();

      }

}

当执行了List<Orders> list=

ordersmappercustomer.findOrdersUserLazyLoading();后,只执行了select * from orders这条语句

当执行了getUser()的时候,才开始查询用户的信息。

当第二次循环查询改用户的时候,还是执行该语句。

上边的这个只发出了一条sql语句,而查找到了两个用户,因为一级缓存的原因,在后边学习。

延迟加载思考

不适用mybatis的association及其collection中的延迟加载的功能,如何实现延迟加载?

实现方法如下:

定义两个mapper方法:

1.     查询订单列表

2.     查询用户的信息

实现思路是先查询第一个mapper的方法,得到订单列表

在程序中(service层)中,按需去调用第二个mapper的方法查询用户信息。

总之:使用延迟加载方法,先去查询简单的SQL(最好单表,也可以关联查询),再去按需加载其他的信息。


猜你喜欢

转载自blog.csdn.net/ITxiaobaibai/article/details/80640413