Mybatis延遲查詢

ZyyIsPig發表於2020-10-13

一對一延遲查詢

  • 針對的是關聯物件, 使用者和訂單從面相物件的角度來說就是關聯物件,當只需要訂單資料,尚不需要使用者資料的時候,就不應該去查詢使用者表,啥時候用到使用者資料,啥時候查詢

原Mybatis查詢

pojo

User.java

package com.ahu.pojo;

import java.util.Date;
import java.util.List;

/**
 * 一個使用者對應多個訂單
 */
public class User {

    private int id;
    private String username;
    private String sex;
    private Date birthday;
    private String address;
    private List<Orders> ordersList;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public List<Orders> getOrdersList() {
        return ordersList;
    }

    public void setOrdersList(List<Orders> ordersList) {
        this.ordersList = ordersList;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", sex='" + sex + '\'' +
                ", birthday=" + birthday +
                ", address='" + address + '\'' +
                ", ordersList=" + ordersList +
                '}';
    }
}

Orders.java

package com.ahu.pojo;

import java.util.Date;

public class Orders {
    private Integer id;

    private Integer userId;

    private String number;

    private Date createtime;

    private String note;

    private User user;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public Integer getUserId() {
        return userId;
    }

    public void setUserId(Integer userId) {
        this.userId = userId;
    }

    public String getNumber() {
        return number;
    }

    public void setNumber(String number) {
        this.number = number == null ? null : number.trim();
    }

    public Date getCreatetime() {
        return createtime;
    }

    public void setCreatetime(Date createtime) {
        this.createtime = createtime;
    }

	public String getNote() {
        return note;
    }

    public void setNote(String note) {
        this.note = note == null ? null : note.trim();
    }

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    @Override
    public String toString() {
        return "Orders{" +
                "id=" + id +
                ", userId=" + userId +
                ", number='" + number + '\'' +
                ", createtime=" + createtime +
                ", note='" + note + '\'' +
                ", user=" + user +
                '}';
    }
}

配置檔案

OrdersMapper.java

package com.ahu.mapper;

import com.ahu.pojo.Orders;

import java.util.List;

public interface OrdersMapper {
    /**
     *一對一查詢,訂單為基準查詢使用者
     * @return
     */
    List<Orders> queryOrdersUser();
}

OrdersMapper.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">

<!--實現延遲載入,拆分SQL語句-->
<mapper namespace="com.ahu.mapper.OrdersMapper">
    <!--
    一對一查詢,基準是訂單表
    resultMap中寫了返回型別,這裡沒必要寫resultType了
    -->
    <select id="queryOrdersUser" resultMap="queryOrdersUserResultMap">
        select u.id uid,u.username,u.sex,u.birthday,u.address,o.id,o.user_id,o.number,o.
        createtime,o.note
        from orders o left outer join user u on u.id = o.user_id;
    </select>

    <!--手動配置對映,查出來的資料表的列和pojo屬性相對應,對應返回型別或者返回函式的泛型-->
    <resultMap id="queryOrdersUserResultMap" type="Orders">
        <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"/>

        <!--
        配置一對一?
        配置user屬性的值
        association配置對應關係
        property 屬性: 和orders物件的哪個屬性關聯
        javaType 屬性: 屬性資料型別 可以小寫?無所謂大小寫
        -->
        <association property="user" javaType="User">
            <id column="uid" property="id"/>
            <result column="username" property="username"/>
            <result column="sex" property="sex"/>
            <result column="birthday" property="birthday"/>
            <result column="address" property="address"/>
        </association>
    </resultMap>
</mapper>

主配置檔案SqlMapConfig.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">
<!--約束檔案,位置在mybatis的jar包-->
<configuration>
    <settings>
        <!-- 開啟延遲載入-->
        <setting name="lazyLoadingEnabled" value="true" />
        <!-- 關閉立即載入-->
        <setting name="aggressiveLazyLoading" value="false" />
        <!-- 設定tostring等方法延遲載入-->
        <setting name="lazyLoadTriggerMethods" value="true" />
    </settings>


    <!--    別名配置-->
    <typeAliases>
<!--        配置別名,資料型別是pojo物件,簡化為user-->
<!--        <typeAlias type="com.ahu.pojo.User" alias="user"></typeAlias>-->

<!--        定義別名也可以使用包掃描,在xml檔案中直接使用類名小寫即可-->
        <package name="com.ahu.pojo"/>
    </typeAliases>

    <environments default="development">
        <environment id="development">
            <!--
                 transactionManager 事務管理配置
                 type="JDBC"  使用的是最原始的JDBC的事務處理機制
                 type="MANAGERED" 不管理事務
            -->
            <transactionManager type="JDBC" />
            <!--
                dataSource 配置資料來源,連線池
                type="POOLED" 使用連線池
                MyBatis自帶連線池  (type=""UNPOOLED)
            -->
            <dataSource type="POOLED">
<!--                使用自帶的資料庫連線池-->
                <!--配置的是,資料庫連線四大資訊-->
                <property name="driver" value="com.mysql.jdbc.Driver" />
                <property name="url" value="jdbc:mysql://127.0.0.1:3305/mybatis?characterEncoding=utf8" />
                <property name="username" value="root" />
                <property name="password" value="ahulml005" />
            </dataSource>
        </environment>
    </environments>

    <!--
      配置的是對映關係  ORM Java物件和資料表
    -->
    <mappers>
        <!--
        配置檔案不在同一個檔案下,填寫地址應該注意
        -->
<!--        <mapper resource="com/ahu/mapper/UserMapper.xml" />-->

        <!--
        可以使用自動掃描配置,自動掃描xml檔案
        一個資料表對應一個xml

        mapper標籤的屬性 resource="xml路徑"
        package標籤的屬性 name="包名"

        -->
        <package name="com.ahu.mapper"/>

    </mappers>
</configuration>    

業務程式碼

package com.ahu.test;

import com.ahu.mapper.OrdersMapper;
import com.ahu.pojo.Orders;
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.IOException;
import java.io.InputStream;
import java.util.List;

public class MainTest {
    private SqlSessionFactory sqlSessionFactory;

    @Before
    public void before() throws IOException {
        InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml");
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
        sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
    }

    /**
     * SQ查詢了使用者和訂單資訊,但是執行時期只需要訂單資料
     * 沒有使用者資料,對使用者資料的查詢就是浪費資源
     * 延遲查詢:需要的時候就查,不需要就不查
     *
     * 方法:拆分
     * SQL語句
     */
    @Test
    public void testQueryOrdersUser(){
        SqlSession sqlSession = sqlSessionFactory.openSession();
        OrdersMapper ordersMapper = sqlSession.getMapper(OrdersMapper.class);
        List<Orders> orders = ordersMapper.queryOrdersUser();
        for (Orders order : orders) {
            System.out.println(order);
        }
        sqlSession.close();
    }
}

一對一延遲查詢

修改OrdersMapper.xml配置

 * SQ查詢了使用者和訂單資訊,但是執行時期只需要訂單資料
 * 沒有使用者資料,對使用者資料的查詢就是浪費資源
 * 延遲查詢:需要的時候就查,不需要就不查
 * 方法:拆分SQL語句
<?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">

<!--實現延遲載入,拆分SQL語句-->
<mapper namespace="com.ahu.mapper.OrdersMapper">
    <!--
    一對一查詢,基準是訂單表
    resultMap中寫了返回型別,這裡沒必要寫resultType了

    拆分sql
    select u.id uid,u.username,u.sex,u.birthday,u.address,o.id,o.user_id,o.number,o.
        createtime,o.note
        from orders o left outer join user u on u.id = o.user_id;
    -->
    <select id="queryOrdersUser" resultMap="queryOrdersUserResultMap">
        select o.id,o.user_id,o.number,o.createtime,o.note
        from orders o;
    </select>

    <!--手動配置對映,查出來的資料表的列和pojo屬性相對應,對應返回型別或者返回函式的泛型-->
    <resultMap id="queryOrdersUserResultMap" type="Orders">
        <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"/>

        <!--
        配置一對一?
        配置user屬性的值
        association配置對應關係
        property 屬性: 和orders物件的哪個屬性關聯
        javaType 屬性: 屬性資料型別 可以小寫?無所謂大小寫
        column:使用哪個列作為條件進行二次查詢
        select:封裝的第二次查詢的SQL語句
        -->
        <!--因為單獨查詢,所以有沒必要對映-->
        <!--foreach標籤的應用場景是函式傳進來的引數-->
        <association property="user" javaType="User" column="user_id" select="queryUserByUserId">
<!--            <id column="uid" property="id"/>-->
<!--            <result column="username" property="username"/>-->
<!--            <result column="sex" property="sex"/>-->
<!--            <result column="birthday" property="birthday"/>-->
<!--            <result column="address" property="address"/>-->
        </association>

    </resultMap>

    <select id="queryUserByUserId" parameterType="Integer" resultType="User">
        select u.id,u.username,u.sex,u.birthday,u.address
        from user u where u.id = #{id}
    </select>
</mapper>

分情況查詢

不查詢uesr資訊時

    @Test
    public void testQueryOrdersUser(){
        SqlSession sqlSession = sqlSessionFactory.openSession();
        OrdersMapper ordersMapper = sqlSession.getMapper(OrdersMapper.class);
        List<Orders> orders = ordersMapper.queryOrdersUser();
        for (Orders order : orders) {
//            System.out.println(order);
            System.out.println(order.getId() + "::" + order.getUserId()
                    + "::" + order.getNumber());
        }
        sqlSession.close();
    }

查詢user資訊時

    @Test
    public void testQueryOrdersUser(){
        SqlSession sqlSession = sqlSessionFactory.openSession();
        OrdersMapper ordersMapper = sqlSession.getMapper(OrdersMapper.class);
        List<Orders> orders = ordersMapper.queryOrdersUser();
        for (Orders order : orders) {
//            System.out.println(order);
            System.out.println(order.getId() + "::" + order.getUserId()
                    + "::" + order.getNumber() + "::" + order.getUser());
        }
        sqlSession.close();
    }

一對多查詢

原Mybatis查詢

  • 使用者和訂單之間是一對多的關係
  • 只輸出使用者資訊的情況會造成浪費資源

pojo

同一對一的User和Order

配置檔案

UserMapper.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和介面名相同-->
<mapper namespace="com.ahu.mapper.UserMapper">
        <select id="queryUser" resultType="user">
                select <include refid="userColumn"/> from user
        </select>

        <!--
        多條件查詢
        標籤where拼接查詢的條件(自動檢查,不需要加1=1,Mys)
        根據pojo中的物件決定查詢的條件(username和sex)

        標籤if對pojo的屬性進行判斷
        屬性test判斷屬性是否為空


        -->
        <!--
        直接用屬性名就可以如username,如果使用user.username則user是內建的屬性物件,空串用''表示
        SQL語句會自動加where,也會自動刪除第一個and
        -->
        <select id="queryByWhere" resultType="user" parameterType="user">
                select * from user
                <where>
                        <if test="username != null and username != ''">
                        and username like #{username}
                        </if>

                        <if test="sex != null and sex != ''">
                        and sex = #{sex}
                        </if>
                </where>
        </select>

        <!--
        批量刪除
        引數是集合
        使用迭代標籤foreach,標籤屬性parameterType,引數的資料型別,寫的是集合的泛型
        迭代標籤 foreach  遍歷集合,固定的集合list

        屬性: collection 遍歷容器集合
        屬性: open SQL開始的符號
        屬性: close SQL結束符號
        屬性: separator SQL語句引數分隔符
        屬性  item 遍歷的容器的元素
        -->
        <delete id="deleteUserByList" parameterType="list">
            delete from user where id in
            <foreach collection="list" open="(" close=")" separator="," item="id">
            #{id}
--             取出集合元素
            </foreach>
        </delete>

        <!--
        傳入陣列
        collection屬性填array
        -->
        <delete id="deleteUserByArray" parameterType="int[]">
            delete from user where id in
            <foreach collection="array" open="(" close=")" separator="," item="id">
                #{id}
            </foreach>
        </delete>


        <select id="queryUserOrders" resultMap="queryUserOrdersResultMap">
            select u.id uid,u.username,u.sex,u.birthday,u.address,o.id,o.user_id,o.number,o.createtime,o.note
            from user u left outer join orders o on u.id = o.user_id;
            
        </select>

        <!--        type返回型別-->
        <resultMap id="queryUserOrdersResultMap" type="User">
            <id column="uid" property="id"/>
            <result column="username" property="username"/>
            <result column="sex" property="sex"/>
            <result column="birthday" property="birthday"/>
            <result column="address" property="address"/>

            <!--
            配置user物件的屬性,不是單一的物件,是集合容器
            collection配置一對多
            屬性property配置pojo物件的屬性
            屬性ofTyte指定集合泛型
            -->
            <collection property="ordersList" ofType="Orders">
                <id column="id" property="id"/>
                <id column="user_id" property="userId"/>
                <id column="number" property="number"/>
                <id column="createtime" property="createtime"/>
                <id column="note" property="note"/>
            </collection>
        </resultMap>


        <sql id="userColumn">
        id,username,sex,birthday,address
        </sql>
</mapper>

業務程式碼

package com.ahu.test;

import com.ahu.mapper.OrdersMapper;
import com.ahu.mapper.UserMapper;
import com.ahu.pojo.Orders;
import com.ahu.pojo.User;
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.IOException;
import java.io.InputStream;
import java.util.List;

public class MainTest {
    private SqlSessionFactory sqlSessionFactory;

    @Before
    public void before() throws IOException {
        InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml");
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
        sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
    }

    /**
     * SQ查詢了使用者和訂單資訊,但是執行時期只需要訂單資料
     * 沒有使用者資料,對使用者資料的查詢就是浪費資源
     * 延遲查詢:需要的時候就查,不需要就不查
     *
     * 方法:拆分SQL語句
     */
    @Test
    public void testQueryOrdersUser(){
        SqlSession sqlSession = sqlSessionFactory.openSession();
        OrdersMapper ordersMapper = sqlSession.getMapper(OrdersMapper.class);
        List<Orders> orders = ordersMapper.queryOrdersUser();
        for (Orders order : orders) {
//            System.out.println(order);
            System.out.println(order.getId() + "::" + order.getUserId()
                    + "::" + order.getNumber());
        }
        sqlSession.close();
    }

    /**
     * 一對多查詢,以使用者表為基準,不過和上例相同,Orders內建為User屬性,查詢出來Orders的屬性user為空,不能套娃
     */
    @Test
    public void testQueryUserOrders(){
        SqlSession sqlSession = sqlSessionFactory.openSession();
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        List<User> users = userMapper.queryUserOrders();
        for (User user : users) {
            System.out.println(user);
        }
        sqlSession.close();
    }
}

多對多延遲查詢

修改UserMapper.xml的配置(最下方一對多的配置)

 可以傳入重新命名的列名uid(防止重名)
 使用子標籤select的第二次子查詢也是可以使用對映的
 ofType傳入泛型
<?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和介面名相同-->
<mapper namespace="com.ahu.mapper.UserMapper">
        <select id="queryUser" resultType="user">
                select <include refid="userColumn"/> from user
        </select>

        <!--
        多條件查詢
        標籤where拼接查詢的條件(自動檢查,不需要加1=1,Mys)
        根據pojo中的物件決定查詢的條件(username和sex)

        標籤if對pojo的屬性進行判斷
        屬性test判斷屬性是否為空


        -->
        <!--
        直接用屬性名就可以如username,如果使用user.username則user是內建的屬性物件,空串用''表示
        SQL語句會自動加where,也會自動刪除第一個and
        -->
        <select id="queryByWhere" resultType="user" parameterType="user">
                select * from user
                <where>
                        <if test="username != null and username != ''">
                        and username like #{username}
                        </if>

                        <if test="sex != null and sex != ''">
                        and sex = #{sex}
                        </if>
                </where>
        </select>

        <!--
        批量刪除
        引數是集合
        使用迭代標籤foreach,標籤屬性parameterType,引數的資料型別,寫的是集合的泛型
        迭代標籤 foreach  遍歷集合,固定的集合list

        屬性: collection 遍歷容器集合
        屬性: open SQL開始的符號
        屬性: close SQL結束符號
        屬性: separator SQL語句引數分隔符
        屬性  item 遍歷的容器的元素
        -->
        <delete id="deleteUserByList" parameterType="list">
            delete from user where id in
            <foreach collection="list" open="(" close=")" separator="," item="id">
            #{id}
--             取出集合元素
            </foreach>
        </delete>

        <!--
        傳入陣列
        collection屬性填array
        -->
        <delete id="deleteUserByArray" parameterType="int[]">
            delete from user where id in
            <foreach collection="array" open="(" close=")" separator="," item="id">
                #{id}
            </foreach>
        </delete>


        <!--
        拆分sql語句
        select u.id uid,u.username,u.sex,u.birthday,u.address,o.id,o.user_id,o.number,o.createtime,o.note
            from user u left outer join orders o on u.id = o.user_id;
        -->
        <select id="queryUserOrders" resultMap="queryUserOrdersResultMap">
            select u.id uid,u.username,u.sex,u.birthday,u.address
            from user u;
            
        </select>

        <!--        type返回型別-->
        <resultMap id="queryUserOrdersResultMap" type="User">
            <id column="uid" property="id"/>
            <result column="username" property="username"/>
            <result column="sex" property="sex"/>
            <result column="birthday" property="birthday"/>
            <result column="address" property="address"/>

            <!--
            配置user物件的屬性,不是單一的物件,是集合容器
            collection配置一對多
            屬性property配置pojo物件的屬性
            屬性ofTyte指定集合泛型
            -->
            
            <!--            
            可以傳入重新命名的列名uid(防止重名)
            使用子標籤select的第二次子查詢也是可以使用對映的
            ofType傳入泛型
            -->
            <collection property="ordersList" ofType="Orders" column="uid" select="queryOrdersByUserId">
                <id column="id" property="id"/>
                <id column="user_id" property="userId"/>
                <id column="number" property="number"/>
                <id column="createtime" property="createtime"/>
                <id column="note" property="note"/>
            </collection>
        </resultMap>

        <select id="queryOrdersByUserId" parameterType="Integer" resultType="Orders">
            select o.id,o.user_id,o.number,o.createtime,o.note
            from orders o where o.user_id = #{id};
        </select>


        <sql id="userColumn">
        id,username,sex,birthday,address
        </sql>
</mapper>

業務程式碼

不查詢訂單資訊就不會出現

    /**
     * 一對多查詢,以使用者表為基準,不過和上例相同,Orders內建為User屬性,查詢出來Orders的屬性user為空,不能套娃
     */
    @Test
    public void testQueryUserOrders(){
        SqlSession sqlSession = sqlSessionFactory.openSession();
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        List<User> users = userMapper.queryUserOrders();
        for (User user : users) {
            System.out.println(user.getUsername());
        }
        sqlSession.close();
    }

在這裡插入圖片描述

查詢了訂單資訊就會呼叫

    /**
     * 一對多查詢,以使用者表為基準,不過和上例相同,Orders內建為User屬性,查詢出來Orders的屬性user為空,不能套娃
     */
    @Test
    public void testQueryUserOrders(){
        SqlSession sqlSession = sqlSessionFactory.openSession();
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        List<User> users = userMapper.queryUserOrders();
        for (User user : users) {
            System.out.println(user.getUsername() + "::" + user.getOrdersList());
        }
        sqlSession.close();
    }

在這裡插入圖片描述

相關文章