java之學習記錄 6 - 1 - Mybatis多表查詢、巢狀查詢
阿新 • • 發佈:2021-02-02
技術標籤:java
資料庫表關係介紹
關係型資料庫表關係分為
- * 一對一
- * 一對多
- * 多對多
案例環境準備
DROP TABLE IF EXISTS `orders`; CREATE TABLE `orders` ( `id` INT(11) NOT NULL AUTO_INCREMENT, `ordertime` VARCHAR(255) DEFAULT NULL, `total` DOUBLE DEFAULT NULL, `uid` INT(11) DEFAULT NULL, PRIMARY KEY (`id`), KEY `uid` (`uid`), CONSTRAINT `orders_ibfk_1` FOREIGN KEY (`uid`) REFERENCES `user` (`id`) ) ENGINE=INNODB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of orders -- ---------------------------- INSERT INTO `orders` VALUES ('1', '2020-12-12', '3000', '1'); INSERT INTO `orders` VALUES ('2', '2020-12-12', '4000', '1'); INSERT INTO `orders` VALUES ('3', '2020-12-12', '5000', '2'); -- ---------------------------- -- Table structure for sys_role -- ---------------------------- DROP TABLE IF EXISTS `sys_role`; CREATE TABLE `sys_role` ( `id` INT(11) NOT NULL AUTO_INCREMENT, `rolename` VARCHAR(255) DEFAULT NULL, `roleDesc` VARCHAR(255) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=INNODB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of sys_role -- ---------------------------- INSERT INTO `sys_role` VALUES ('1', 'CTO', 'CTO'); INSERT INTO `sys_role` VALUES ('2', 'CEO', 'CEO'); -- ---------------------------- -- Table structure for sys_user_role -- ---------------------------- DROP TABLE IF EXISTS `sys_user_role`; CREATE TABLE `sys_user_role` ( `userid` INT(11) NOT NULL, `roleid` INT(11) NOT NULL, PRIMARY KEY (`userid`,`roleid`), KEY `roleid` (`roleid`), CONSTRAINT `sys_user_role_ibfk_1` FOREIGN KEY (`userid`) REFERENCES `sys_role` (`id`), CONSTRAINT `sys_user_role_ibfk_2` FOREIGN KEY (`roleid`) REFERENCES `user` (`id`) ) ENGINE=INNODB DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of sys_user_role -- ---------------------------- INSERT INTO `sys_user_role` VALUES ('1', '1'); INSERT INTO `sys_user_role` VALUES ('2', '1'); INSERT INTO `sys_user_role` VALUES ('1', '2'); INSERT INTO `sys_user_role` VALUES ('2', '2');
一對一(多對一)
1 介紹 一對一查詢模型- 使用者表和訂單表的關係為,一個使用者有多個訂單,一個訂單隻從屬於一個使用者
- 一對一查詢的需求:查詢所有訂單,與此同時查詢出每個訂單所屬的使用者
SELECT * FROM orders o LEFT JOIN USER u ON o.`uid`=u.`id`;
2
程式碼實現
1
)
Orders
實體
2 ) OrderMapper 介面public class Orders { private int id; private String ordertime; private Double total; private int uid; // 表示當前訂單屬於哪個使用者 private User user; }
/*
* 一對一關聯查詢:查詢所有訂單,同時還要查詢出每個訂單所屬的使用者資訊
* */
public List<Orders> findAllWithUser();
3
)
OrderMapper.xml
對映
<!-- 一對一查詢:查詢所有訂單,同時還要查詢出每個訂單所屬的使用者資訊 --> <resultMap id="orderMap" type="orders"> <id property="id" column="id"/> <result property="ordertime" column="ordertime"/> <result property="total" column="total"/> <result property="uid" column="uid"/> <!-- association:在進行一對一關聯查詢配置時,使用association標籤進行關聯 property="user":要封裝實體的屬性名 javaType="com.lagou.domain.User" 要封裝實體的屬性型別 --> <association property="user" javaType="com.lagou.domain.User"> <id property="id" column="uid"/> <result property="username" column="username"/> <result property="birthday" column="birthday"/> <result property="sex" column="sex"/> <result property="address" column="address"/> </association> </resultMap> <select id="findAllWithUser" resultMap="orderMap"> SELECT * FROM orders o LEFT JOIN USER u ON o.uid = u.id </select>
4 )測試程式碼
/*
* 一對一查詢:查詢所有訂單,同時還要查詢出每個訂單所屬的使用者資訊
* */
@Test
public void test1() throws IOException {
InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
OrderMapper mapper = sqlSession.getMapper(OrderMapper.class);
List<Orders> ordersList = mapper.findAllWithUser();
for (Orders orders : ordersList) {
System.out.println(orders);
}
sqlSession.close();
}
一對多
1 介紹 一對多查詢模型- 使用者表和訂單表的關係為,一個使用者有多個訂單,一個訂單隻從屬於一個使用者
- 一對多查詢的需求:查詢所有使用者,與此同時查詢出該使用者具有的訂單
SELECT *,o.id oid FROM USER u LEFT JOIN orders o ON u.`id` = o.`uid`;
2
程式碼實現
1
)
User
實體
public class User {
private int id;
private String username;
private Date birthday;
private String sex;
private String address;
// 表示多方關係:集合 代表了當前使用者所具有的訂單列表
private List<Orders> ordersList;
}
2 )UserMapper介面
/*
* 一對多關聯查詢:查詢所有的使用者,同時還要查詢出每個使用者所關聯的訂單資訊
* */
public List<User> findAllWithOrder();
3 )UserMapper.xml對映
<!-- 一對多關聯查詢:查詢所有的使用者,同時還要查詢出每個使用者所關聯的訂單資訊 -->
<resultMap id="userMap" type="com.lagou.domain.User">
<id property="id" column="id"></id>
<result property="username" column="username"></result>
<result property="birthday" column="birthday"></result>
<result property="sex" column="sex"></result>
<result property="address" column="address"></result>
<!--
collection:一對多使用collection標籤進行關聯
-->
<collection property="ordersList" ofType="com.lagou.domain.Orders">
<id property="id" column="oid"></id>
<result property="ordertime" column="ordertime"></result>
<result property="total" column="total"></result>
<result property="uid" column="uid"></result>
</collection>
</resultMap>
<select id="findAllWithOrder" resultMap="userMap">
SELECT u.*,o.id oid,o.ordertime,o.uid,o.total FROM orders o RIGHT JOIN USER u ON o.uid = u.id
</select>
4 )測試程式碼
/*
* 一對多關聯查詢:查詢所有的使用者,同時還要查詢出每個使用者所關聯的訂單資訊
* */
@Test
public void test2() throws IOException {
InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> allWithOrder = mapper.findAllWithOrder();
for (User user : allWithOrder) {
System.out.println(user);
}
sqlSession.close();
}
多對多
1 介紹 多對多查詢的模型- 使用者表和角色表的關係為,一個使用者有多個角色,一個角色被多個使用者使用
- 多對多查詢的需求:查詢所有使用者同時查詢出該使用者的所有角色
SELECT * FROM
USER u -- 使用者表
LEFT JOIN user_role ur -- 左外連線中間表
ON u.`id` = ur.`uid`
LEFT JOIN role r -- 左外連線中間表
ON ur.`rid` = r.`id` ;
2
程式碼實現
1
)
User
和
Role
實體
public class User {
private Integer id;
private String username;
private Date birthday;
private String sex;
private String address;
// 代表當前使用者關聯的角色列表
private List<Role> roleList;
}
public class Role {
private Integer id;
private String roleName;
private String roleDesc;
}
2
)
UserMapper
介面
/*
* 多對多關聯查詢:查詢所有的使用者,同時還要查詢出每個使用者所關聯的角色資訊
* */
public List<User> findAllWithRole();
3
)
UserMapper.xml
對映
<!-- 多對多關聯查詢:查詢所有的使用者,同時還要查詢出每個使用者所關聯的角色資訊 -->
<resultMap id="userRoleMap" type="user">
<id property="id" column="id"></id>
<result property="username" column="username"></result>
<result property="birthday" column="birthday"></result>
<result property="sex" column="sex"></result>
<result property="address" column="address"></result>
<collection property="roleList" ofType="role">
<id property="id" column="rid"></id>
<result property="rolename" column="rolename"></result>
<result property="roleDesc" column="roleDesc"></result>
</collection>
</resultMap>
<select id="findAllWithRole" resultMap="userRoleMap">
SELECT u.*,r.id rid,r.rolename,r.roleDesc FROM USER u
LEFT JOIN sys_user_role ur ON ur.userid = u.id
LEFT JOIN sys_role r ON ur.roleid = r.id
</select>
4
)測試程式碼
/*
* 多對多關聯查詢:查詢所有的使用者,同時還要查詢出每個使用者所關聯的角色資訊
* */
@Test
public void test3() throws IOException {
InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> allWithRole = mapper.findAllWithRole();
for (User user : allWithRole) {
System.out.println(user);
}
sqlSession.close();
}
小結
MyBatis 多表配置方式- * 多對一(一對一)配置:使用<resultMap>+<association>做配置
- * 一對多配置:使用<resultMap>+<collection>做配置
- * 多對多配置:使用<resultMap>+<collection>做配置
- * 多對多的配置跟一對多很相似,難度在於SQL語句的編寫。
MyBatis巢狀查詢
1 什麼是巢狀查詢
- 巢狀查詢就是將原來多表查詢中的聯合查詢語句拆成單個表的查詢,再使用mybatis的語法巢狀在一起。
* 需求:查詢一個訂單,與此同時查詢出該訂單所屬的使用者
1. 聯合查詢
SELECT * FROM orders o LEFT JOIN USER u ON o.`uid`=u.`id`;
2. 巢狀查詢
2.1 先查詢訂單
SELECT * FROM orders
2.2 再根據訂單uid外來鍵,查詢使用者
SELECT * FROM `user` WHERE id = #{根據訂單查詢的uid}
2.3 最後使用mybatis,將以上二步巢狀起來 ...
2 一對一巢狀查詢
2.1 介紹- 需求:查詢一個訂單,與此同時查詢出該訂單所屬的使用者
-- 先查詢訂單
SELECT * FROM orders;
-- 再根據訂單uid外來鍵,查詢使用者
SELECT * FROM `user` WHERE id = #{訂單的uid};
2.2
程式碼實現
1
)
OrderMapper
介面
/*
* 一對一巢狀查詢:查詢所有訂單,同時還要查詢出每個訂單所屬的使用者資訊
* */
public List<Orders> findAllWithUser2();
2
)
OrderMapper.xml
對映
<resultMap id="orderMap2" type="com.lagou.domain.Orders">
<id property="id" column="id"/>
<result property="ordertime" column="ordertime"/>
<result property="total" column="total"/>
<result property="uid" column="uid"/>
<!-- 問題1:怎麼去執行第二條sql .問題二:如何執行第二條sql的時候,把uid作為引數進行傳遞 -->
<association property="user" fetchType="eager" javaType="user" select="com.lagou.com.lagou.mapper.UserMapper.findById" column="uid">
</association>
</resultMap>
<!-- 一對一巢狀查詢 -->
<select id="findAllWithUser2" resultMap="orderMap2">
select * from orders
</select>
3
)
UserMapper
介面
/*
* 根據id查詢使用者
* */
public User findById(int id);
4
)
UserMapper.xml
對映
<!-- 根據id查詢使用者
useCache="true":代表當前這個statement是使用二級快取
-->
<select id="findById" useCache="true" flushCache="true" resultType="user" parameterType="int">
select * from user where id = #{id}
</select>
5
)測試程式碼
/*
* 一對一巢狀查詢:查詢所有訂單,同時還要查詢出每個訂單所屬的使用者資訊
* */
@Test
public void test4() throws IOException {
InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
OrderMapper mapper = sqlSession.getMapper(OrderMapper.class);
List<Orders> ordersList = mapper.findAllWithUser2();
for (Orders orders : ordersList) {
System.out.println(orders);
}
sqlSession.close();
}
3 一對多巢狀查詢
3.1 介紹- 需求:查詢所有使用者,與此同時查詢出該使用者具有的訂單
-- 先查詢使用者
SELECT * FROM `user`;
-- 再根據使用者id主鍵,查詢訂單列表
SELECT * FROM orders where uid = #{使用者id};
3.2
程式碼實現
a
)
UserMapper
介面
/*
* 一對多巢狀查詢:詢所有的使用者,同時還要查詢出每個使用者所關聯的訂單資訊
* */
public List<User> findAllWithOrder2();
b
)
UserMapper.xml
對映
<!-- 一對多巢狀查詢:詢所有的使用者,同時還要查詢出每個使用者所關聯的訂單資訊 -->
<resultMap id="userOrderMap" type="user">
<id property="id" column="id"></id>
<result property="username" column="username"></result>
<result property="birthday" column="birthday"></result>
<result property="sex" column="sex"></result>
<result property="address" column="address"></result>
<collection property="ordersList" ofType="orders" select="com.lagou.mapper.OrderMapper.findByUid" column="id"></collection>
</resultMap>
<select id="findAllWithOrder2" resultMap="userOrderMap">
select * from user
</select>
c
)
OrderMapper
介面
/*
* 根據uid查詢對應訂單
* */
public List<Orders> findByUid(int uid);
d
)
OrderMapper.xml
對映
<select id="findByUid" parameterType="int" resultType="orders">
select * from orders where uid = #{uid}
</select>
e
)測試程式碼
/*
* 一對多巢狀查詢:查詢所有的使用者,同時還要查詢出每個使用者所關聯的訂單資訊
* */
@Test
public void test5() throws IOException {
InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
List<User> allWithOrder2 = userMapper.findAllWithOrder2();
for (User user : allWithOrder2) {
System.out.println(user);
// 要用到該使用者的訂單資訊
System.out.println(user.getOrdersList());
}
sqlSession.close();
}
4 多對多巢狀查詢
4.1 介紹- 需求:查詢使用者 同時查詢出該使用者的所有角色
-- 先查詢使用者
SELECT * FROM `user`;
-- 再根據使用者id主鍵,查詢角色列表
SELECT * FROM role r INNER JOIN user_role ur ON r.`id` = ur.`rid` WHERE ur.`uid` = #{使用者id};
4.2
程式碼實現
a
)
UserMapper
介面
/*
* 多對多巢狀查詢:查詢所有的使用者,同時還要查詢出每個使用者所關聯的角色資訊
* */
public List<User> findAllWithRole2();
b)UserMapper.xml對映
<!-- 多對多巢狀查詢:查詢所有的使用者,同時還要查詢出每個使用者所關聯的角色資訊 -->
<resultMap id="userRoleMap2" type="user">
<id property="id" column="id"></id>
<result property="username" column="username"></result>
<result property="birthday" column="birthday"></result>
<result property="sex" column="sex"></result>
<result property="address" column="address"></result>
<collection property="roleList" ofType="role" column="id" select="com.lagou.mapper.RoleMapper.findByUid"></collection>
</resultMap>
<select id="findAllWithRole2" resultMap="userRoleMap2">
select * from user
</select>
c)RoleMapper介面
/*
* 根據使用者id 查詢對應角色
* */
public List<Role> findByUid(int uid);
d)RoleMapper.xml對映
<select id="findByUid" resultType="role" parameterType="int">
SELECT * FROM sys_role r INNER JOIN sys_user_role ur ON r.id = ur.roleid
WHERE ur.userid = #{uid}
</select>
e)測試程式碼
/*
* 多對多巢狀查詢:查詢所有的使用者,同時還要查詢出每個使用者所關聯的角色資訊
* */
@Test
public void test6() throws IOException {
InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> allWithRole = mapper.findAllWithRole2();
for (User user : allWithRole) {
System.out.println(user);
}
sqlSession.close();
}
5 小結
- 一對一配置:使用<resultMap>+<association>做配置,通過column條件,執行select查詢
- 一對多配置:使用<resultMap>+<collection>做配置,通過column條件,執行select查詢
- 多對多配置:使用<resultMap>+<collection>做配置,通過column條件,執行select查詢
- 優點:簡化多表查詢操作
- 缺點:執行多次sql語句,浪費資料庫效能