mybatis-多表查詢(XML)
阿新 • • 發佈:2021-02-03
多表查詢分一下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 | 馬老師 |
+-----+--------+