1. 程式人生 > 其它 >mybatis-多表查詢(XML)

mybatis-多表查詢(XML)

技術標籤:mybatis筆記mybatisjava資料庫

多表查詢分一下4種。

一對一,一對多,多對一(mybatis對映為一對一),多對多。

要求:資料庫操作熟練,會寫多表查詢。

mybatis主要的操作方式:

1,SQL語句直接查詢封裝

2,呼叫介面方法查詢。

一對多對映:

例如,一個使用者(人)有多個賬號。根據關係可得類屬性:

public class User implements Serializable {
    private Integer id;
    private String name;
    private List<Account> accounts;
}
public class Account implements Serializable {
    private Integer id;
    private Integer uid;
    private Double money;
    private User user;
}

介面方法:

public interface IAccountDao {
    List<Account> findAll();
    Account findById(Integer id);
    List<Account>findAccountsByUid(Integer uid);
}
public interface IUserDao {
    List<User> findAll();
    User findById(Integer id);
    List<Account> findAccountsByUid(Integer id);
}

我們想要在查詢某一個使用者的時候,順便把該使用者的賬號都查一遍。Mapper對映檔案如下

<?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="dao.IUserDao">
<!--    id唯一名稱,方便引用,type指的是Java型別-->
    <resultMap id="userMap" type="user">
<!--        資料庫主鍵欄位-->
        <id property="id" column="id"></id>
<!--        資料庫非主鍵欄位-->
        <result property="name" column="name"></result>
<!--        select="dao.IAccountDao.findAccountsByUid"-->
<!--        Java類中的屬性-->
<!--     property指定屬性,column指定根據欄位聯查,ofType指定集合泛型型別   -->
        <collection property="accounts" column="id"  ofType="account" >
            <id column="aid" property="id"></id>
            <result column="uid" property="uid"></result>
            <result column="money" property="money"></result>
        </collection>
    </resultMap>
    <select id="findAll" resultMap="userMap">
   select * from users;
    </select>
    <select id="findById" resultMap="userMap" parameterType="int">
    select u.*,a.id aid,a.uid,a.money
    from users u
    left join account a
    on u.id = a.uid
    where u.id=#{uid};
    </select>
</mapper>

test程式碼:


        IUserDao userDao= session.getMapper(IUserDao.class);       
        User u = userDao.findById(1);
        System.out.println(u);
        for (Account account : u.getAccounts()) {
            System.out.println(account);
        }
    }

執行結果:

可以看到,的確是成功了。但是我們也可以看到缺點。該查詢的select語句過長,幾乎就是通過查詢SQL,將資料庫的列和屬性封裝成的。有點麻煩。但是,作為主流的dao框架,自然有結局方案。

解決:引用其他介面的方法。

<?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="dao.IUserDao">
<!--    id唯一名稱,方便引用,type指的是Java型別-->
    <resultMap id="userMap" type="user">
<!--        資料庫主鍵欄位-->
        <id property="id" column="id"></id>
<!--        資料庫非主鍵欄位-->
        <result property="name" column="name"></result>
<!--        select="dao.IAccountDao.findAccountsByUid"-->
<!--        Java類中的屬性-->
<!--     property指定屬性,column指定根據欄位聯查,ofType指定集合泛型型別   -->
        <collection property="accounts" column="id"  ofType="account" select="dao.IAccountDao.findAccountsByUid">
<!--            <id column="aid" property="id"></id>-->
<!--            <result column="uid" property="uid"></result>-->
<!--            <result column="money" property="money"></result>-->
        </collection>
    </resultMap>
    <select id="findAll" resultMap="userMap">
   select * from users;
    </select>
    <select id="findById" resultMap="userMap" parameterType="int">
    select * from users where id=#{id}
    </select>
</mapper>

執行結果:

我們可以看到這是一樣的。所以有這麼簡單的方法我們為什麼不用?我們觀察不同,其Collection標籤中添加了select屬性標籤。引用了namespace+id。

一對一對映。

例如一個賬戶對應一個使用者。賬戶的Mapper為

<?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="dao.IAccountDao">
    <resultMap id="accountMap" type="account">
        <id property="id" column="id"></id>
        <result property="uid" column="uid"></result>
        <result property="money" column="money"/>
        <association column="uid" property="user" javaType="user" select="dao.IUserDao.findById">
<!--            <id property="id" column="id"></id>-->
<!--            <result property="name" column="name"></result>-->
        </association>
    </resultMap>

    <select id="findAll" resultMap="accountMap">
    select *from account;
    </select>
    <select id="findById" resultType="account" parameterType="int">
        select * from account where id = #{id}
    </select>

    <select id="findAccountsByUid" resultType="account" parameterType="int">
        select * from account where uid = #{uid}
    </select>

</mapper>

我們可以看到與一對多的差別。1,association和collection差別。2,JavaType和ofType。同樣都是使用select語句。

多對多查詢

例如:student與teacher。一個學生對應多個老師,一個老師對應多個學生。

實體類:

public class Teacher implements Serializable {
    private Integer tid;
    private String tname;
    private List<Student> students;
}
public class User implements Serializable {
    private Integer id;
    private String name;
    private List<Account> accounts;
}

介面方法:

public interface IStudentDao {
    List<Student> findAll();
//    通過sid來查詢老師們
    List<Teacher>findBySid(Integer sid);
}
public interface ITeacherDao {
    List<Teacher> findAll();
//    通過tid來查詢學生們
    List<Student> findByTid(Integer tid);
}

Mapper檔案:

學生:

<?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="dao.IStudentDao">

    <resultMap id="studentMap" type="student">
        <id property="sid" column="sid"></id>
        <result property="sname" column="sname"></result>
        <collection property="teachers" column="sid" ofType="teacher" select="dao.IStudentDao.findBySid"></collection>
    </resultMap>
    <select id="findAll" resultMap="studentMap">
        select * from student;
    </select>

    <select id="findBySid" resultType="teacher" parameterType="int">
        select *
    from teacher
    where tid in
    (select st.tid
    from stu_tea st
    where st.sid=#{sid});
    </select>
</mapper>

老師:

<?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="dao.ITeacherDao">
    <resultMap id="teacherMap" type="teacher">
        <id column="tid" property="tid"></id>
        <result column="tname" property="tname"></result>
        <collection property="students" column="tid" ofType="student" select="dao.ITeacherDao.findByTid"></collection>
    </resultMap>
    <select id="findAll" resultMap="teacherMap" >
        select * from teacher;
    </select>
    <select id="findByTid" resultType="student" parameterType="int">
    select * from student s
    where s.sid in(select st.sid
    from stu_tea st
    where st.tid = #{tid}) ;
    </select>
</mapper>

我們可以看到,兩個resultMap中型別都是Collection,ofType。明顯變化的就是多對多的SQL語句變長了。原因是3張表聯查。兩張表之間沒有關係,要藉助中間表。

測試程式碼:

 @org.junit.Test
    public void test(){
        IStudentDao studentDao = session.getMapper(IStudentDao.class);
        List<Teacher> teacherList = studentDao.findBySid(1);
        for (Teacher teacher : teacherList) {
            System.out.println(teacher);
        }

    }

結果:

備註:三張表資料如下

mysql> select * from student;
+-----+--------+
| sid | sname  |
+-----+--------+
|   1 | 劉德華 |
|   2 | 梁朝偉 |
|   3 | 黃日華 |
|   4 | 湯鎮業 |
|   5 | 周杰倫 |
+-----+--------+
5 rows in set (0.00 sec)

mysql> select * from stu_tea;
+------+------+
| sid  | tid  |
+------+------+
|    1 |    1 |
|    2 |    1 |
|    3 |    1 |
|    4 |    1 |
|    5 |    1 |
|    2 |    2 |
|    3 |    3 |
|    4 |    3 |
|    1 |    3 |
|    5 |    3 |
+------+------+
10 rows in set (0.01 sec)
mysql> select * from teacher;
+-----+--------+
| tid | tname  |
+-----+--------+
|   1 | 王老師 |
|   2 | 劉老師 |
|   3 | 張老師 |
|   4 | 馬老師 |
+-----+--------+