
回顧
1. 創(chuàng)建java工程,導入相關(guān)jar包
2. 根據(jù)user表編寫User實體類
3. 編寫UserMapper接口
4. 編寫UserMapper.xml映射文件
5. 復制SqlMapConfig.xml (mybatis-config.xml)
6. 測試查詢...

優(yōu)化測試方法
public class UserMapperTest {
private SqlSession sqlSession = null;
// 此方法在測試方法執(zhí)行之前,執(zhí)行
@Before
public void before() {
// 獲取sqlSession對象
sqlSession = MyBatisUtils.openSession();// 此方法必須線程內(nèi)獨享....
}
// 此方法在測試地方法執(zhí)行之后,執(zhí)行
@After
public void after() {
// 關(guān)閉sqlSession
MyBatisUtils.close(sqlSession);
}
@Test
public void testFindAll() throws Exception {
// 執(zhí)行sql
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
List<User> list = userMapper.findAll();
System.out.println(list);
}
}
mybatis查詢和多表
1. 單表查詢【重點】
2. mapper映射文件深入講解【重點】
3. 回顧表關(guān)系【重點】
4. 多表查詢【重點】
一 Mybatis單表查詢
1.1 resultMap標簽
如果數(shù)據(jù)庫返回結(jié)果的列名和要封裝的實體的屬性名完全一致的話用 resultType 屬性
-
如果數(shù)據(jù)庫返回結(jié)果的列名和要封裝的實體的屬性名有不一致的情況用 resultMap 屬性
- 使用resultMap==手動建立對象關(guān)系映射==。
① UserMapper接口
// ResultMap標簽
public List<User> findAllResultMap();
② UserMapper.xml
<!--
resultMap 手動建立映射
id="userResultMap"
type="cn.itcast.domain.User" 建立映射的java類型
id 標簽 主鍵
column="uid" 列名
property="id" 實體屬性名
result 標簽 普通字段
column="name" 列名
property="username" 實體屬性名
-->
<resultMap id="userResultMap" type="cn.itcast.domain.User">
<id column="uid" property="id"></id>
<result column="name" property="username"></result>
<result column="bir" property="birthday"></result>
<result column="gender" property="sex"></result>
<result column="address" property="address"></result>
</resultMap>
<!--
模擬表與實體的屬性名不一致情況
-->
<select id="findAllResultMap" resultMap="userResultMap">
SELECT id AS uid, username AS `name`,birthday AS bir ,sex AS gender ,address FROM `user`
</select>
③ 測試
// resultMap標簽
@Test
public void testFindAllResultMap() throws Exception {
// 獲取代理對象
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
// 執(zhí)行sql
List<User> list = userMapper.findAllResultMap();
for (User user : list) {
System.out.println(user);
}
}
1.2 多條件查詢(二種)
需求
根據(jù)id和username查詢user表
① UserMapper接口
// 多條件查詢,方式一
public List<User> findByIdAndUsername1(@Param("id") Integer id, @Param("username") String username);
// 多條件查詢,方式二
public List<User> findByIdAndUsername2(User user);
② UserMapper.xml
<!--
多條件查詢方式一
如果傳遞多個參數(shù) parameterType屬性省略不寫...
-->
<select id="findByIdAndUsername1" resultType="cn.itcast.domain.User">
select * from user where id = #{id} and username = #{username}
</select>
<!--
多條件查詢方式二
其實mybatis這哥們傳遞一個參數(shù) parameterType也可以省略【不太建議...】
-->
<select id="findByIdAndUsername2" parameterType="cn.itcast.domain.User" resultType="cn.itcast.domain.User">
select * from user where id = #{id} and username = #{username}
</select>
③ 測試
// 多條件查詢
@Test
public void test01()throws Exception{
// 獲取代理對象
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
// 方式一
/*List<User> list = userMapper.findByIdAndUsername1(41, "老王");
System.out.println(list);*/
// 方式二
User user = new User();
user.setId(41);
user.setUsername("老王");
List<User> list = userMapper.findByIdAndUsername2(user);
System.out.println(list);
}
1.3 模糊查詢(四種)
需求
根據(jù)username模糊查詢user表
① UserMapper接口
// 模糊查詢,方式一
public List<User> findByUsername1(String username);
// 模糊查詢,方式二
public List<User> findByUsername2(String username);
// 模糊查詢,方式三
public List<User> findByUsername3(String username);
// 模糊查詢,方式四
public List<User> findByUsername4(String username);
② UserMapper.xml
<!--
模糊查詢,方式一
java代碼與sql語句有耦合
-->
<select id="findByUsername1" parameterType="string" resultType="User">
select * from user where username like #{username}
</select>
<!--
模糊查詢,方式二【了解】
mysql5.5版本之前,此拼接不支持多個單引號
oracle數(shù)據(jù)庫,除了別名的位置,其余位置都不能使用雙引號
-->
<select id="findByUsername2" parameterType="string" resultType="User">
select * from user where username like "%" #{username} "%"
</select>
<!--
模糊查詢,方式三【此方式,會出現(xiàn)sql注入...】
${} 字符串拼接,如果接收的簡單數(shù)據(jù)類型,表達式名稱必須是value
-->
<select id="findByUsername3" parameterType="string" resultType="User">
select * from user where username like '%${value}%'
</select>
<!--
模糊查詢,方式四【掌握】
使用concat()函數(shù)拼接
注意:oracle數(shù)據(jù)庫 concat()函數(shù)只能傳遞二個參數(shù)... 可以使用函數(shù)嵌套來解決
-->
<select id="findByUsername4" parameterType="string" resultType="User">
select * from user where username like concat(concat('%',#{username}),'%')
</select>
③ 測試
// 模糊查詢
@Test
public void test02()throws Exception{
// 獲取代理對象
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
// 方式一
// List<User> list = userMapper.findByUsername1("%王%");
// 方式二
// List<User> list = userMapper.findByUsername2("王");
// 方式三
// List<User> list = userMapper.findByUsername3("王");
// 方式四
List<User> list = userMapper.findByUsername4("王");
System.out.println(list);
}
1.4 ${} 與 #{} 區(qū)別【面試題】
${}:底層 Statement
- sql與參數(shù)拼接在一起,會出現(xiàn)sql注入問題
- 每次執(zhí)行sql語句都會編譯一次
- 接收簡單數(shù)據(jù)類型,命名:${value}
- 接收引用數(shù)據(jù)類型,命名: ${屬性名}
- 字符串類型需要加 '${value}'
org.apache.ibatis.scripting.xmltags.TextSqlNode
#{}:底層 PreparedStatement
- sql與參數(shù)分離,不會出現(xiàn)sql注入問題
- sql只需要編譯一次
- 接收簡單數(shù)據(jù)類型,命名:#{隨便寫}
- 接收引用數(shù)據(jù)類型,命名:#{屬性名}
二 Mybatis映射文件深入
環(huán)境搭建

2.1 返回主鍵
應(yīng)用場景
向數(shù)據(jù)庫保存一個user對象后, 然后在控制臺記錄下此新增user的主鍵值(id)
① UserMapper接口
public interface UserMapper {
// 返回主鍵,方式一
public void save1(User user);
// 返回主鍵,方式二
public void save2(User user);
}
② 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="cn.itcast.dao.UserMapper">
<!--
返回主鍵,方式一 useGeneratedKeys屬性
useGeneratedKeys="true" 開啟新增主鍵返回功能
keyColumn="id" user表中主鍵列
keyProperty="id" user實體主鍵屬性
注意:僅支持主鍵自增類型的數(shù)據(jù)庫 MySQL 和 SqlServer , oracle不支持
-->
<insert id="save1" parameterType="User" useGeneratedKeys="true" keyColumn="id" keyProperty="id">
insert into user(username,birthday,sex,address)
values(#{username},#{birthday},#{sex},#{address})
</insert>
<!--
返回主鍵,方式二 <selectKey>
keyColumn="id" user表中主鍵列
keyProperty="id" user實體主鍵屬性
resultType="int" user實體主鍵屬性類型
order="AFTER" 表示此標簽內(nèi)部sql語句在insert執(zhí)行之前(執(zhí)行),還是之后執(zhí)行(執(zhí)行)
AFTER 之后執(zhí)行【在自增主鍵時】
BEFORE 之前執(zhí)行【使用指定主鍵時】
-->
<insert id="save2" parameterType="User" >
<selectKey keyColumn="id" keyProperty="id" resultType="int" order="AFTER">
SELECT LAST_INSERT_ID()
</selectKey>
insert into user(username,birthday,sex,address)
values(#{username},#{birthday},#{sex},#{address})
</insert>
</mapper>
③ 測試
public class UserMapperTest {
private SqlSession sqlSession = null;
// 此方法在測試方法執(zhí)行之前,執(zhí)行
@Before
public void before() {
// 獲取sqlSession對象
sqlSession = MyBatisUtils.openSession();// 此方法必須線程內(nèi)獨享....
}
// 此方法在測試地方法執(zhí)行之后,執(zhí)行
@After
public void after() {
// 關(guān)閉sqlSession
MyBatisUtils.close(sqlSession);
}
// 返回主鍵
@Test
public void test01() throws Exception {
// 獲取代理對象
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
User user = new User();
user.setUsername("xiao六");
user.setBirthday(new Date());
user.setAddress("中國");
user.setSex("男");
// 方式一
// userMapper.save1(user);
userMapper.save2(user);
System.out.println("新增時,主鍵返回:" + user.getId());
}
}
2.2 動態(tài)SQL
2.2.1 什么是動態(tài)SQL
需求
把id和username封裝到user對象中,將user對象中不為空的屬性作為查詢條件

這個時候我們執(zhí)行的sql就有多種可能
-- 如果id和用戶名不為空
select * from user where id= #{id} and username = #{username}
-- 如果只有id
select * from user where id= #{id}
-- 如果只有用戶名
select * from user where username = #{username}
-- 如果id和用戶名都為空
select * from user
像上面這樣, 根據(jù)傳入的參數(shù)不同, 需要執(zhí)行的SQL的結(jié)構(gòu)就會不同,這就是動態(tài)SQL
2.2.2 if 條件判斷
需求
把id和username封裝到user對象中,將user對象中不為空的屬性作為查詢條件
① UserMapper接口
// if 條件判斷
public List<User> findByIdAndUsernameIf(User user);
② UserMapper.xml
<!--
if標簽 條件判斷
where標簽 相當于 where 1=1 功能,如果沒有條件情況下 where語句不在sql語句拼接
可以去掉第一個 and 或者 or
-->
<select id="findByIdAndUsernameIf" parameterType="User" resultType="User">
select * from user
<where>
<if test="id != null">
and id= #{id}
</if>
<if test="username !=null">
and username = #{username}
</if>
</where>
</select>
③ 測試
// if判斷
@Test
public void test02()throws Exception{
// 獲取代理對象
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
// 拼接條件
User param = new User();
// param.setId(41);
// param.setUsername("老王");
List<User> list = userMapper.findByIdAndUsernameIf(param);
for (User user : list) {
System.out.println(user);
}
}
2.2.3 set 用于update語句
需求
動態(tài)更新user表數(shù)據(jù),如果該屬性有值就更新,沒有值不做處理
① UserMapper接口
// set 更新
public void updateIf(User user);
② UserMapper.xml
<!--
set標簽 更新 ,將條件中的最后一個逗號抹除
-->
<update id="updateIf" parameterType="User">
update user
<set>
<if test="username !=null">
username = #{username} ,
</if>
<if test="birthday !=null">
birthday = #{birthday} ,
</if>
<if test="sex !=null">
sex = #{sex} ,
</if>
<if test="address != null">
address = #{address},
</if>
</set>
where id = #{id}
</update>
③ 測試
@Test
public void test03()throws Exception{
// 獲取代理對象
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
// 設(shè)置更新內(nèi)容
User user = new User();
user.setId(50);
user.setUsername("小四");
userMapper.updateIf(user);
}
2.2.4 foreach 用于循環(huán)遍歷【重點】
需求
根據(jù)多個id查詢,user對象的集合
select * from user where id in (41,43,46);
* <foreach>標簽用于遍歷集合,它的屬性:
? collection:代表要遍歷的集合元素
? open:代表語句的開始部分
? close:代表結(jié)束部分
? item:代表遍歷集合的每個元素,生成的變量名
? sperator:代表分隔符
練習三個版本
- 普通list集合
- 普通array數(shù)組
- 實體屬性list集合
① UserMapper
// foreach標簽,普通list集合
public List<User> findByList(List<Integer> ids);
// foreach標簽,普通array數(shù)組
public List<User> findByArray(Integer [] ids);
// foreach標簽,實體屬性list集合
public List<User> findByQueryVo(QueryVo queryVo);
② UserMapper.xml
<!--
foreach標簽,普通list集合
傳遞 普通類型list集合 collection="list" 屬性取值:collection、list
-->
<select id="findByList" parameterType="list" resultType="User">
select * from user where id in
<foreach collection="list" open="(" close=")" item="id" separator=",">
#{id}
</foreach>
</select>
<!--
foreach標簽,普通array數(shù)組
傳統(tǒng) 普通類型array數(shù)組 collection="array" 屬性取值 array
-->
<select id="findByArray" parameterType="int" resultType="User">
select * from user where id in
<foreach collection="array" open="(" close=")" item="id" separator=",">
#{id}
</foreach>
</select>
<!--
foreach標簽,實體屬性list集合
傳遞 實體中l(wèi)ist屬性集合的話,collection="ids" 取值,實體的屬性名
-->
<select id="findByQueryVo" parameterType="QueryVo" resultType="User">
select * from user where id in
<foreach collection="ids" open="(" close=")" item="id" separator=",">
#{id}
</foreach>
</select>
③ 測試
// foreach標簽
@Test
public void test04()throws Exception{
// 獲取代理對象
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
// 普通list集合
/* List ids = new ArrayList();
ids.add(41);
ids.add(46);
List list = userMapper.findByList(ids);*/
// 普通array數(shù)組
/* Integer[] ids = {41,46,49};
List<User> list = userMapper.findByArray(ids);*/
// 實體屬性list集合
List ids = new ArrayList();
ids.add(41);
ids.add(46);
QueryVo queryVo = new QueryVo();
queryVo.setIds(ids);
List<User> list = userMapper.findByQueryVo(queryVo);
System.out.println(list);
}
2.3 SQL片段
應(yīng)用場景
映射文件中可將重復的 sql 提取出來,使用時用 include 引用即可,最終達到 sql 重用的目的
<!--
foreach標簽,普通list集合
傳遞 普通類型list集合 collection="list" 屬性取值:collection、list
-->
<select id="findByList" parameterType="list" resultType="User">
<include refid="selectUser"></include> where id in
<foreach collection="list" open="(" close=")" item="id" separator=",">
#{id}
</foreach>
</select>
<!--
foreach標簽,普通array數(shù)組
傳統(tǒng) 普通類型array數(shù)組 collection="array" 屬性取值 array
-->
<select id="findByArray" parameterType="int" resultType="User">
<include refid="selectUser"></include> where id in
<foreach collection="array" open="(" close=")" item="id" separator=",">
#{id}
</foreach>
</select>
<!--
foreach標簽,實體屬性list集合
傳遞 實體中l(wèi)ist屬性集合的話,collection="ids" 取值,實體的屬性名
-->
<select id="findByQueryVo" parameterType="QueryVo" resultType="User">
<include refid="selectUser"></include> where id in
<foreach collection="ids" open="(" close=")" item="id" separator=",">
#{id}
</foreach>
</select>
<!--
將當前映射文件的共同的sql代碼抽取一個片段,實現(xiàn)sql的復用性...
id="selectUser" 當前sql片段的唯一標識
-->
<sql id="selectUser">
select id,username,birthday,sex,address from user
</sql>
2.4 知識小結(jié)
MyBatis映射文件配置
<select>:查詢
<insert>:插入
<update>:修改
<delete>:刪除
<selectKey>:返回主鍵
<where>:where條件
<if>:if判斷
<foreach>:for循環(huán)
<set>:set設(shè)置
<sql>:sql片段抽取
三 表關(guān)系回顧
在關(guān)系型數(shù)據(jù)庫當中,表關(guān)系分為三種
* 特殊情況:
一個訂單只能從屬于一個用戶,mybatis框架就把這個多對一看做成一對一來實現(xiàn)
* 數(shù)據(jù)建立表關(guān)系:通過主外鍵關(guān)聯(lián)
* 實體建立關(guān)系:通過屬性關(guān)聯(lián)

四 MyBatis多表查詢

環(huán)境搭建

4.1 一對一(多對一)
一對一查詢模型
用戶表和訂單表的關(guān)系為,一個用戶有多個訂單,一個訂單只從屬于一個用戶
一對一查詢的需求:查詢一個訂單,與此同時查詢出該訂單所屬的用戶

① 實體和表映射關(guān)系
SELECT * FROM orders o INNER JOIN `user` u ON o.`uid` = u.`id` WHERE o.`id` = 1

② Order實體類
// 訂單實體類
public class Order {
private Integer id;
private Date ordertime;
private Double money;
// 一個訂單從屬于一個用戶
private User user;
}
③ OrderMapper接口
public interface OrderMapper {
// 一對一關(guān)聯(lián)查詢
public Order findByIdWithUser(Integer id);
}
④ OrderMapper.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="cn.itcast.dao.OrderMapper">
<resultMap id="orderMap" type="cn.itcast.domain.Order">
<id column="id" property="id"></id>
<result column="ordertime" property="ordertime"></result>
<result column="money" property="money"></result>
<!--
一對一多表關(guān)聯(lián) association標簽
property="user" 關(guān)聯(lián)實體的屬性名
javaType="cn.itcast.domain.User" 關(guān)聯(lián)實體java類型
-->
<association property="user" javaType="cn.itcast.domain.User">
<id column="uid" property="id"></id>
<result column="username" property="username"></result>
<result column="birthday" property="birthday"></result>
<result column="sex" property="sex"></result>
<result column="address" property="address"></result>
</association>
</resultMap>
<!--
一對一關(guān)聯(lián)查詢
resultType:單表映射封裝
resultMap:多表查詢必須手動映射封裝
-->
<select id="findByIdWithUser" parameterType="int" resultMap="orderMap">
SELECT * FROM orders o INNER JOIN `user` u ON o.`uid` = u.`id` WHERE o.`id` = #{id}
</select>
</mapper>
⑤ 測試
public class OrderMapperTest {
private SqlSession sqlSession = null;
// 此方法在測試方法執(zhí)行之前,執(zhí)行
@Before
public void before() {
// 獲取sqlSession對象
sqlSession = MyBatisUtils.openSession();// 此方法必須線程內(nèi)獨享....
}
// 此方法在測試地方法執(zhí)行之后,執(zhí)行
@After
public void after() {
// 關(guān)閉sqlSession
MyBatisUtils.close(sqlSession);
}
// 一對一關(guān)聯(lián)測試
@Test
public void test01()throws Exception{
// 獲取代理對象
OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class);
// 根據(jù)id查詢
Order order = orderMapper.findByIdWithUser(1);
System.out.println(order);
}
}
4.2 一對多
一對多查詢模型
用戶表和訂單表的關(guān)系為,一個用戶有多個訂單,一個訂單只從屬于一個用戶
一對多查詢的需求:查詢一個用戶,與此同時查詢出該用戶具有的訂單

① 實體和表關(guān)系
SELECT *,o.id AS oid FROM `user` u INNER JOIN orders o ON u.`id` = o.`uid` WHERE u.`id`=41

② User實體類
public class User {
private Integer id;
private String username;
private Date birthday;
private String sex;
private String address;
// 一個用戶具有多個訂單
private List<Order> orderList;
}
③ UserMapper接口
public interface UserMapper {
// 一對多關(guān)聯(lián)
public User findByIdWithOrders(Integer id);
}
④ 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="cn.itcast.dao.UserMapper">
<resultMap id="userMap" type="cn.itcast.domain.User">
<id column="id" property="id"></id>
<result column="username" property="username"></result>
<result column="birthday" property="birthday"></result>
<result column="sex" property="sex"></result>
<result column="address" property="address"></result>
<!--
一對多關(guān)聯(lián) collection標簽
property="orderList" 關(guān)聯(lián)實體集合的屬性名
ofType="cn.itcast.domain.Order" 關(guān)聯(lián)實體的java類型(集合泛型的類型)
-->
<collection property="orderList" ofType="cn.itcast.domain.Order">
<id column="oid" property="id"></id>
<result column="ordertime" property="ordertime"></result>
<result column="money" property="money"></result>
</collection>
</resultMap>
<!--
一對多關(guān)聯(lián)
-->
<select id="findByIdWithOrders" parameterType="int" resultMap="userMap">
SELECT *,o.id AS oid FROM `user` u INNER JOIN orders o ON u.`id` = o.`uid` WHERE u.`id`=#{id}
</select>
</mapper>
⑤ 測試

public class UserMapperTest extends BaseMapperTest {
// 一對多測試
@Test
public void test01() throws Exception {
// 獲取代理
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
User user = userMapper.findByIdWithOrders(41);
System.out.println(user);
}
}
4.3 多對多(由二個一對多組成)
多對多查詢的模型
用戶表和角色表的關(guān)系為,一個用戶有多個角色,一個角色被多個用戶使用
多對多查詢的需求:查詢用戶同時查詢出該用戶的所有角色
在mybatis中多對多實現(xiàn),跟一對多步驟是一樣,區(qū)別就在于sql語句

① 實體和表關(guān)系
SELECT * FROM `user` u
INNER JOIN user_role ur ON u.`id` = ur.`uid` -- 用戶連接中間表
INNER JOIN role r ON ur.`rid` = r.`id` -- 再根據(jù)中間表連接角色
WHERE u.id = 41 -- 用戶id 作為條件

② User和Role實體
public class Role {
private Integer id;
private String roleName;
private String roleDesc;
}
public class User {
private Integer id;
private String username;
private Date birthday;
private String sex;
private String address;
// 一個用戶具有多個角色
private List<Role> roleList;
}
③ UserMapper接口
// 多對多關(guān)聯(lián)
public User findByIdWithRoles(Integer id);
④ UserMapper.xml

<resultMap id="userWithRoleMap" type="cn.itcast.domain.User">
<id column="id" property="id"></id>
<result column="username" property="username"></result>
<result column="birthday" property="birthday"></result>
<result column="sex" property="sex"></result>
<result column="address" property="address"></result>
<!--
多對多實現(xiàn)步驟和一對多是一樣的(區(qū)別在于sql語句)
-->
<collection property="roleList" ofType="cn.itcast.domain.Role">
<id column="rid" property="id"></id>
<result column="role_name" property="roleName"></result>
<result column="role_desc" property="roleDesc"></result>
</collection>
</resultMap>
<!--
多對多關(guān)聯(lián)
-->
<select id="findByIdWithRoles" parameterType="int" resultMap="userWithRoleMap">
SELECT * FROM `user` u
INNER JOIN user_role ur ON u.`id` = ur.`uid` -- 用戶連接中間表
INNER JOIN role r ON ur.`rid` = r.`id` -- 再根據(jù)中間表連接角色
WHERE u.id = #{id} -- 用戶id 作為條件
</select>
⑤ 測試
// 多對多測試(根據(jù)用戶查詢角色)
@Test
public void test02()throws Exception{
// 獲取代理
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
User user = userMapper.findByIdWithRoles(41);
System.out.println(user);
}
作業(yè):以角色為中心,查詢多個用戶
4.4 知識小結(jié)
一對一配置:使用<resultMap>+<association>做配置
association:
property:關(guān)聯(lián)的實體屬性名
javaType:關(guān)聯(lián)的實體類型(別名)
一對多配置:使用<resultMap>+<collection>做配置
collection:
property:關(guān)聯(lián)的集合屬性名
ofType:關(guān)聯(lián)的集合泛型類型(別名)
多對多配置:使用<resultMap>+<collection>做配置
collection:
property:關(guān)聯(lián)的集合屬性名
ofType:關(guān)聯(lián)的集合泛型類型(別名)
多對多的配置跟一對多很相似,難度在于SQL語句的編寫。
4.5 優(yōu)化測試
public class BaseMapperTest {
protected SqlSession sqlSession = null;
// 此方法在測試方法執(zhí)行之前,執(zhí)行
@Before
public void before() {
// 獲取sqlSession對象
sqlSession = MyBatisUtils.openSession();// 此方法必須線程內(nèi)獨享....
}
// 此方法在測試地方法執(zhí)行之后,執(zhí)行
@After
public void after() {
// 關(guān)閉sqlSession
MyBatisUtils.close(sqlSession);
}
}
public class OrderMapperTest extends BaseMapperTest { // 繼承父類,就可以直接使用 父類的方法和成員變量了
// 一對一關(guān)聯(lián)測試
@Test
public void test01() throws Exception {
// 獲取代理對象
OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class);
// 根據(jù)id查詢
Order order = orderMapper.findByIdWithUser(1);
System.out.println(order);
}
}
老師下午總結(jié)
回顧
1.resultMap標簽的作用以及常見的異常
resultmap標簽的作用,什么時候需要使用到resultmap標簽:
1. 單表查詢的時候?qū)嶓w類的屬性名與表的列名不對應(yīng)的情況下。
2. 多表查詢的時候我們也要使用。
① 實體類
package com.itheima.model;
import java.util.Date;
import java.util.List;
public class User {
private Integer id;
private String username;
private Date birthday;
private String sex;
private String address;
// 一個用戶具有多個角色
private List<Role> roleList;
// 一個用戶具有多個訂單
private List<Order> orderList;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public List<Order> getOrderList() {
return orderList;
}
public void setOrderList(List<Order> orderList) {
this.orderList = orderList;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", birthday=" + birthday +
", sex='" + sex + '\'' +
", address='" + address + '\'' +
", orderList=" + orderList +
'}';
}
}
②接口
package com.itheima.dao;
import com.itheima.model.User;
import java.util.List;
public interface UserDao {
public List<User> findAll();
}
③接口對應(yīng)的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="com.itheima.dao.UserDao">
<!-- resultmap的使用場景:
1. 多表查詢的時候
2. 實體類的屬性名與表的列名不對應(yīng)
-->
<resultMap id="UserMapper" type="user">
<!-- property 實體類的屬性名
column 表的列名-->
<result property="username" column="name"/>
</resultMap>
<!--注意: 一旦使用resultmap標簽,那么指定返回值類型的時候不是使用resultType了,而是使用reusltmap-->
<select id="findAll" resultMap="UserMapper">
select * from user
</select>
</mapper>
④測試類(使用該測試之前必須把MyBatisUtils工具類導入)
package com.itheima.test;
import com.itheima.dao.UserDao;
import com.itheima.model.User;
import com.itheima.utils.BaseMapperTest;
import com.itheima.utils.MyBatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.util.List;
public class MyBatisTest extends BaseMapperTest {
@Test
public void test01(){
SqlSession sqlSession = MyBatisUtils.openSession();
//獲取接口代理對象
UserDao userDao = sqlSession.getMapper(UserDao.class);
List<User> list = userDao.findAll();
System.out.println("查詢結(jié)果:"+ list);
}
}
2.多表查詢
- association 封裝單個對象的屬性
- collection 封裝一個集合屬性
一對一
用戶表和訂單表的關(guān)系為,一個用戶有多個訂單,==一個訂單只從屬于一個用戶==
①創(chuàng)建用戶實體類
public class User {
private Integer id;
private String username;
private Date birthday;
private String sex;
private String address;
}
②創(chuàng)建訂單實體類,并且把一個訂單只屬于某一個客戶的關(guān)系描述清楚
public class Order {
private Integer id;
private Integer uid;
private Date ordertime;
private Double money;
private User user;
}
③編寫接口
package com.itheima.dao;
import com.itheima.model.Order;
public interface OrderDao {
//根據(jù)訂單的id查找訂單
public Order findById(int id);
}
④編寫接口對應(yīng)的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="com.itheima.dao.OrderDao">
<!--如果是多表查詢,那么需要使用reusltMap標簽-->
<resultMap id="OrderMap" type="order">
<id property="id" column="oid"/>
<result property="ordertime" column="ordertime"/>
<result property="money" column="money"/>
<!--如果你的屬性是一個對象,那么我們則需要使用association標簽-->
<association property="user" javaType="User">
<id column="id" property="id"/>
<result column="name" property="username"/>
<result column="birthday" property="birthday"/>
<result column="sex" property="sex"/>
<result column="address" property="address"/>
</association>
</resultMap>
<select id="findById" resultMap="OrderMap">
SELECT * ,o.`id` AS oid FROM USER u INNER JOIN orders o ON o.`uid`=u.`id` WHERE o.`id`=#{id}
</select>
</mapper>
⑤測試
//測試一對一的關(guān)系
@Test
public void test02(){
SqlSession sqlSession = MyBatisUtils.openSession();
//獲取接口代理對象
OrderDao orderDao = sqlSession.getMapper(OrderDao.class);
Order order = orderDao.findById(1);
System.out.println("訂單信息:"+ order);
}
今日重點
- resultmap使用場景以及基本使用
- 模糊查詢, 模糊查詢只需要練習最后一種。concat(concat,"%");
- 動態(tài)sql語句
- 多表查詢 Collection標簽 association標簽
作業(yè): 今天帥哥的代碼你們練習完畢發(fā)給組長,我會問組長或者班主任要。
時間: 明天晚上九點鐘之前.
學習反饋
| 反饋 | 回復 |
|---|---|
| 好像模糊查詢還有一種bind標簽(這種不講是實際開發(fā)不用嗎) | bind便簽是用于綁定一個變量去使用的,目前企業(yè)里面用得不多。另外mybatis里面還有很多的標簽,這里只會講解最為常用標簽.如果同學們有興趣那么可以自己去了解一下。 |
| 講一下多對多的執(zhí)行流程 | 等會老師會講解的。 |
| 突然學好多標簽,還不怎么接受得來;還有多表查詢覺得復雜,又聽不懂 | 等會老師會講解的。 |
| 感覺學的一團糟。。。很多知識只是抄的順手。。不理解的地方很多 | 當你抄代碼之前一定要問清楚即將要抄的語句,我們抄代碼之前一定要明白該語句的作用。 否則今晚抄完,還沒有睡著就已經(jīng)忘記了。 代碼:先看得懂,然后再去抄,才能自己寫。 看不懂的情況可以問同學,問老師。 |
| 今天內(nèi)容還是比較多,麻煩老師再講一下多表查詢這里的java代碼實現(xiàn),還不是很清楚 | 等會老師會講解的。 |
答疑區(qū)
| 疑問 | 回復 |
|---|---|
| SqlSession放成員變量位置,有何線程安全問題? | 說的是需要自己手動關(guān)閉。不釋放資源的話會造成內(nèi)存泄露。 后面是用spring整合之后就不用自己釋放資源了。 |
| SqlSession放成員變量位置,有何線程安全問題? | 1,SqlSession作為一個接口,其并沒有線程安全性的問題,我們常說的線程安全問題是SqlSession的一個實現(xiàn)DefaultSqlSession, 2.并發(fā)操作使用了同一個DefaultSqlSession的實例,而同一個DefaultSqlSession的實例使用的是同一個Executor對象, |
| 為什么需要用別名,然后還特地給別名弄映射呢? | 考慮你的類的字段和表字段可能不一致的場景。 |
| 那我要是換一個別名,映射是不是也得跟著改,這樣豈不是很麻煩,增加了很大工作量,還不如不寫別名 | 是的.我們講的是字段名稱和類中的屬性名稱不一致的解決方案.實際開發(fā)盡量避免這種不一致.就不用搞這種映射關(guān)系了. |
| ‘%${value}%’ 括號中為什么只能寫value | mybatis源碼寫死的.因此只能寫value |
| ‘%${value}% 這種是字符串拼接 會產(chǎn)生 sql注入問題concat()也是字符串拼接呀,為什么不會有sql注入問題 | ${value}是拼接sql #{key} 這個是預編譯sql |
| 嵌套怎么理解 | concat(concat('%',#{name}),'%') 首先里面的concat使用%與name進行拼接,得到結(jié)果%#{name},然后外層再使用concat讓%#{name}與%再進行拼接 |
| 返回主鍵的意義在哪 | 剛剛于帥老師說了一個應(yīng)用場景,比如:我們添加了一個部門之后,需要馬上給該部門添加員工 |
| 嗯嗯我的意思就是剛 創(chuàng)建就直接獲取的意義 是吧? | 假如我們使用的是ajax, 添加完一個部門的時候,馬上彈出一個框配置該部門的員工,那么這個表單是不是就要拿到剛剛的部門主鍵了。 |
| 老師,多個單引號拼接是指MySQL會將多個連續(xù)的單引號包裹的多個字符串自動拼接成一個大的字符串嗎? | 是的,就是一個字符串拼接。 |
| 臨時變量item的值必須和#{}中的值一致是嗎? | 是的 |
| foreach標簽的item的屬性的值是固定的嗎 | item的屬性值是可以改變的 |
| foreach標簽對于數(shù)組類型的,怎么前面的傳入的類型(就是parameterType)又不需要帶[]了,不是int[]而是int了.這也是別名嗎 | 不是別名,這里寫int相當于是寫了容器中存放的類型. |
| 為什么不寫uid屬性 | 直播間屏幕一直在更新.你突然問一句:為什么不寫uid屬性? 到底哪里為什么不寫?請結(jié)合上下文,完整描述自己的問題.謝謝. |
| JavaType屬性的是怎么寫 | 就是當前屬性對象的類型, 比如Order類中包含User,那么該user屬性的javaType類型則是User |
| before這個倆注解,能用private修飾嗎 | 不可以 |