溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

MyBatis復(fù)雜Sql查詢?nèi)绾螌崿F(xiàn)

發(fā)布時間:2022-12-28 09:32:14 來源:億速云 閱讀:126 作者:iii 欄目:開發(fā)技術(shù)

這篇文章主要介紹“MyBatis復(fù)雜Sql查詢?nèi)绾螌崿F(xiàn)”,在日常操作中,相信很多人在MyBatis復(fù)雜Sql查詢?nèi)绾螌崿F(xiàn)問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”MyBatis復(fù)雜Sql查詢?nèi)绾螌崿F(xiàn)”的疑惑有所幫助!接下來,請跟著小編一起來學(xué)習(xí)吧!

resultMap 結(jié)果映射

resultMap 元素是 MyBatis 中最重要最強(qiáng)大的元素,之前所寫的 sql 語句,返回值都是簡單的基本數(shù)據(jù)類型或者某一個實體類,比如下面這段 sql 返回的就是最簡單的 User 類型。

<select id="getUserById" resultType="user" parameterType="int">
    select * from user where id=#{id};
</select>

現(xiàn)在思考一下下面這種情況,如果實體類中定義的某一個字段和數(shù)據(jù)庫中的字段不一致怎么辦?

public class User {
    private int id;
    private String lastname;
    //.....
}

比如我定義了一個 User 類,包含 id 和 lastname 兩個屬性,而數(shù)據(jù)庫中這兩個字段的名字為 id 和 name。此時再執(zhí)行查詢時結(jié)果如下:lastname 這個字段直接為 null。

這時候我們就可以使用 resultMap 來解決這個問題,resultMap 可以將數(shù)據(jù)庫中的字段映射到實體類上。column 代表數(shù)據(jù)庫中的字段名,properties 代表實體類中的字段名,通過映射之后 Mybatis 就可以找到對應(yīng)的字段。

<resultMap id="UserMap" type="User">
    <!--column代表數(shù)據(jù)庫中的字段名,properties代表實體類中的字段名-->
    <result column="id" property="id"/>
    <result column="name" property="lastname"/>
</resultMap>
<select id="getUserById" resultMap="UserMap" parameterType="int">
  select * from user where id=#{id};
</select>

準(zhǔn)備數(shù)據(jù)

接下來結(jié)合學(xué)生與教室的案例模擬復(fù)雜場景:

//創(chuàng)建教室表
create table classroom
(
id int not null AUTO_INCREMENT,
classname VARCHAR(40) not null,
PRIMARY KEY (id)
);
//創(chuàng)建學(xué)生表
create table student
(
id int not null AUTO_INCREMENT,
name VARCHAR(40) not null,
classid int not null,
PRIMARY KEY (id),
FOREIGN key (classid) REFERENCES classroom(id)
);
//創(chuàng)建一些數(shù)據(jù)
insert into classroom VALUES (1,'101班');
insert into classroom VALUES (2,'102班');
insert into student VALUES(1,'Amy',1);
insert into student VALUES(2,'Bob',1);
insert into student VALUES(3,'javayz',1);

多對一查詢(association)

現(xiàn)在要實現(xiàn)一個多對一的查詢需求,查詢所有的學(xué)生,并將每個學(xué)生所在的教室包含在內(nèi)。由于現(xiàn)在的情況是多學(xué)生和教室的關(guān)系是多對一,因此在構(gòu)建實體類時在 Student 類上要加上 ClassRoom 變量。

在 Java 的實體類代碼中分別建立 Student 和 ClassRoom 的類:

package com.cn.pojo;
public class ClassRoom {
    private int id;
    private String classname;
    public ClassRoom(){}
    public int getId() {
        return id;
    }
    public String getClassname() {
        return classname;
    }
    public void setId(int id) {
        this.id = id;
    }
    public void setClassname(String classname) {
        this.classname = classname;
    }
    @Override
    public String toString() {
        return "ClassRoom{" +
                "id=" + id +
                ", classname='" + classname + '\'' +
                '}';
    }
}
package com.cn.pojo;
public class Student {
    private int id;
    private String name;
    private ClassRoom classRoom;
    public Student(){}
    public int getId() {
        return id;
    }
    public String getName() {
        return name;
    }
    public ClassRoom getClassRoom() {
        return classRoom;
    }
    public void setId(int id) {
        this.id = id;
    }
    public void setName(String name) {
        this.name = name;
    }
    public void setClassRoom(ClassRoom classRoom) {
        this.classRoom = classRoom;
    }
    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", classRoom=" + classRoom +
                '}';
    }
}

定義一個 StudentMapper 接口:

package com.cn.mapper;
import java.util.List;
import com.cn.pojo.Student;
public interface StudentMapper {
    List<Student> selectAllStudent();
}

編寫 StudentMapper.xml

<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.cn.mapper.StudentMapper">
    <select id="selectAllStudent" resultMap="StudentAndClassRoom">
        select s.id sid,s.name sname,c.id cid,c.classname cname
        from student s,classroom c
        where s.classid=c.id
    </select>
    <resultMap id="StudentAndClassRoom" type="com.cn.pojo.Student">
        <result property="id" column="sid"/>
        <result property="name" column="sname"/>
        <association property="classRoom" javaType="com.cn.pojo.ClassRoom">
            <result property="id" column="cid"/>
            <result property="classname" column="cname"/>
        </association>
    </resultMap>
</mapper>

上面的這種 sql 編寫模式稱為結(jié)果嵌套查詢,首先通過一段 sql 查詢語句將需要的信息查詢出來,接著通過 resultMap 對結(jié)果進(jìn)行拼接。這里使用 association 將 classRoom 的信息拼接到了 classRoom 類中,實現(xiàn)多對一查詢。

別忘了在配置類里把 mapper 映射加上,編寫測試類:

public class StudentMapperTest {
    public static void main(String[] args) {
        // 獲取SqlSession
        SqlSession sqlSession = MyBatisUtils.getSqlSession();
        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
        List<Student> students = mapper.selectAllStudent();
        System.out.println(students);
    }
}

一對多查詢(collection)

一個教室里有多個學(xué)生,如果想要查詢每個教室中的所有學(xué)生,就會用到一對多查詢。

修改兩個實體類,命名為 Student2 和 ClassRoom2,因為一個教室中有多個學(xué)生,因此在教室類中通過 List<Student2> 的方式引入 Student2 類

public class Student2 {
    private int id;
    private String name;
    private int classId;
    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", classId=" + classId +
                '}';
    }
}
import java.util.List;
public class ClassRoom2 {
    private int id;
    private String classname;
    private List<Student2> students;
    @Override
    public String toString() {
        return "ClassRoom{" +
                "id=" + id +
                ", classname='" + classname + '\'' +
                ", students=" + students +
                '}';
    }
}

接著編寫 Mapper 接口和對應(yīng)的 Mapper.xml

import java.util.List;
import com.cn.pojo.ClassRoom2;
public interface ClassRoomMapper {
    List<ClassRoom2> getClassRoomByid( int id);
}
<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.cn.mapper.ClassRoomMapper">
    <select id="getClassRoomByid" resultMap="ClassRoomAndStudent" parameterType="int">
        select c.id cid,c.classname cname,s.id sid,s.name sname,s.classid classid
        from student s,classroom c
        where s.classid=c.id and c.id=#{id}
    </select>
    <resultMap id="ClassRoomAndStudent" type="com.cn.pojo.ClassRoom2">
        <result property="id" column="cid"/>
        <result property="classname" column="cname"/>
        <!--對于集合屬性,需要使用collection來實現(xiàn)-->
        <collection property="students" ofType="com.cn.pojo.Student2">
            <result property="id" column="sid"/>
            <result property="name" column="sname"/>
            <result property="classId" column="classid"/>
        </collection>
    </resultMap>
</mapper>

依舊是通過結(jié)果嵌套查詢的方式,通過 sql 語句查詢出結(jié)果,再通過 resultMap 進(jìn)行組裝,一對多查詢用的是 collection。

在配置文件中增加 mapper 映射器之后,編寫一個測試類:

public class TeacherMapperTest {
    public static void main(String[] args) {
        // 獲取SqlSession
        SqlSession sqlSession = MyBatisUtils.getSqlSession();
        ClassRoomMapper mapper = sqlSession.getMapper(ClassRoomMapper.class);
        List<ClassRoom2> classRoom = mapper.getClassRoomByid(1);
        System.out.println(classRoom);
    }
}

總結(jié)成一點:對象的關(guān)聯(lián)(多對一)使用 association,集合的關(guān)聯(lián)(一對多)使用 collection。

懶加載

在上面的兩個例子中,一次 sql 查詢就將兩個表的數(shù)據(jù)一次性查詢了出來,這種方式就是即時加載。但是在某些業(yè)務(wù)場景下,可能只需要學(xué)生的信息或者教室的信息,而不需要兩者的聯(lián)表數(shù)據(jù),這種時候就可以使用懶加載。

以上邊的 association 案例解釋懶加載的實現(xiàn)。

上邊的例子中,通過聯(lián)表查詢一次性就查詢出了學(xué)生信息和教室信息:

select s.id sid,s.name sname,c.id cid,c.classname cname
from student s,classroom c
where s.classid=c.id

如果想要通過懶加載實現(xiàn),就需要把 sql 語句轉(zhuǎn)換為:

select * from student;
select * from classroom where id = #{classid}

按照這個思路,建立 StudentLazyMapper 類:

package com.cn.mapper;
import java.util.List;
import com.cn.pojo.Student;
public interface StudentLazyMapper {
    List<Student> selectAllStudent();
}

創(chuàng)建對應(yīng)的 StudentLazyMapper.xml 文件,將原先的一條 sql 轉(zhuǎn)換為兩條 sql:

<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.cn.mapper.StudentLazyMapper">
    <select id="selectAllStudent" resultMap="studentAndClassRoom">
        select * from student
    </select>
    <resultMap id="studentAndClassRoom" type="com.cn.pojo.Student">
        <id property="id" column="id"/>
        <result property="name" column="name"/>
        <association property="classRoom" javaType="com.cn.pojo.ClassRoom" column="classid" select="selectClassRoomById">
            <result property="id" column="id"/>
            <result property="classname" column="classname"/>
        </association>
    </resultMap>
    <select id="selectClassRoomById" resultType="com.cn.pojo.ClassRoom">
        select * from classroom where id = #{classid}
    </select>
</mapper>

在 mybatis-config.xml 中增加 mapper 映射,為了更好地看到懶加載效果,開啟控制臺日志輸出,完整 xml 如下:

<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
    <setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&amp;useUnicode=true&amp;characterEncoding=UTF-8"/>
                <property name="username" value="root"/>
                <property name="password" value=""/>
            </dataSource>
        </environment>
    </environments>
    <!--每個mapper.xml都需要在mybatis配置文件中進(jìn)行配置-->
    <mappers>
        <mapper resource="mapper/UserMapper.xml"/>
        <mapper resource="mapper/StudentMapper.xml"/>
        <mapper resource="mapper/StudentLazyMapper.xml"/>
    </mappers>
</configuration>

新建一個測試類 StudentMapperLazyTest:

public class StudentMapperLazyTest {
    public static void main(String[] args) {
        // 獲取SqlSession
    SqlSession sqlSession = MyBatisUtils.getSqlSession();
    StudentLazyMapper mapper = sqlSession.getMapper(StudentLazyMapper.class);
    List<Student> students = mapper.selectAllStudent();
    System.out.println(students.get(0).getId());
    }
}

這個時候是還沒開啟懶加載的,從運行結(jié)果可以看出,雖然代碼中只需要得到 student 的 id,但是卻查詢了兩張表:

MyBatis復(fù)雜Sql查詢?nèi)绾螌崿F(xiàn)

在配置文件的 setting 節(jié)點下開啟懶加載的配置:

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

再次運行測試代碼:

MyBatis復(fù)雜Sql查詢?nèi)绾螌崿F(xiàn)

可以看到,只有 student 一張表被查詢,實現(xiàn)了懶加載

到此,關(guān)于“MyBatis復(fù)雜Sql查詢?nèi)绾螌崿F(xiàn)”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識,請繼續(xù)關(guān)注億速云網(wǎng)站,小編會繼續(xù)努力為大家?guī)砀鄬嵱玫奈恼拢?/p>

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI