在演示UpdateWrapper的案例中,我們在代碼中編寫了更新的SQL語句:
@Test
void testUpadateWrapper(){List<Long> ids = List.of(1L,2L,4L);//生成SQLUpadateWrapper<User> wrapper =new UpdateWrapper<User> ().setSql("balance =balance -200").in("id",ids);// 第一個參數可以給null 不填更新字段和數據
userMapper.update(null,wrapper);
}
?這種寫法在企業中不允許 因為Sql語句最好都在持久層而不是業務層
由于條件是in語句,只能將Sql寫在Mapper.xml文件中然后使用foreach來生成動態的SQL
所以,MybatisPlus提供了自定義SQL功能,可以讓我們利用Wrapper生成查詢條件,再結合Mapper.xml編寫SQL
@Test
void testCustomWrapper() {// 1.準備自定義查詢條件List<Long> ids = List.of(1L, 2L, 4L);QueryWrapper<User> wrapper = new QueryWrapper<User>().in("id", ids);// 2.調用mapper的自定義方法,直接傳遞WrapperuserMapper.deductBalanceByIds(200, wrapper);
}
?然后在UserMapper中自定義SQL:、
package com.itheima.mp.mapper;import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.itheima.mp.domain.po.User;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Update;
import org.apache.ibatis.annotations.Param;public interface UserMapper extends BaseMapper<User> {@Select("UPDATE user SET balance = balance - #{money} ${ew.customSqlSegment}")void deductBalanceByIds(@Param("money") int money, @Param("ew") QueryWrapper<User> wrapper);
}
擴展ew.customSqlSegment
${ew.customSqlSegment}
?是 MyBatis-Plus 中用于集成條件構造器(QueryWrapper
?或?LambdaQueryWrapper
)的核心占位符,主要作用是1. 動態拼接 SQL 條件片段
2.實現 "自定義 SQL 骨架 + 動態條件拼接" 的靈活查詢。
3.無需大量的手寫<if>標簽判斷條件是否存在,簡化SQL編寫
4.支持復雜的條件邏輯
例如:
wrapper.eq("status", 1).and(i -> i.like("name", "張").or().like("name", "李"));
等價于
WHERE status = 1 AND (name LIKE '%張%' OR name LIKE '%李%')
多表關聯
利用Wrapper中自定義條件結合自定義SQL實現多表查詢的效果
例如,我們要查詢出所有收貨地址在北京的并且用戶id在1、2、4之中的用戶
<select id="queryUserByIdAndAddr" resultType="com.itheima.mp.domain.po.User">SELECT *FROM user uINNER JOIN address a ON u.id = a.user_idWHERE u.id<foreach collection="ids" separator="," item="id" open="IN (" close=")">#{id}</foreach>AND a.city = #{city}</select>
先補充一下foreach表格屬性,讓曦哥加深印象、
屬性 | 描述 |
---|---|
collection | 指定要遍歷的集合。表示傳入過來的參數的數據類型。該屬性是必須指定的,要做 foreach 的對象。 |
index | 索引,index 指定一個名字,用于表示在迭代過程中,每次迭代到的位置。遍歷 list 的時候 index 就是索引,遍歷 map 的時候 index 表示的就是 map 的 key,item 就是 map 的值。 |
item | 表示本次迭代獲取的元素,若collection為List、Set或者數組,則表示其中的元素;若collection為map,則代表key-value的value,該參數為必選 |
open | 表示該語句以什么開始,最常用的是左括弧’(’,注意:mybatis會將該字符拼接到整體的sql語句之前,并且只拼接一次,該參數為可選項 |
separator | 表示在每次進行迭代之間以什么符號作為分隔符。select * from tab where id in(1,2,3)相當于1,2,3之間的"," |
close | 表示該語句以什么結束,最常用的是右括弧’)’,注意:mybatis會將該字符拼接到整體的sql語句之后,該參數為可選項 |
但是基于自定義SQL結合Wrapper的玩法,我們就可以利用Wrapper來構造查詢條件 然后手寫Select以及From部分,從而實現多表查詢
1. 首先構建一個查詢條件
@Test void testCustomJionWrapper(){QueryWrapper<User> wrapper =new QueryWrapper<User>().in("u.id",List.of(1L,2L,4L).eq("a.city","北京");// 調用mapper自定義方法 List<User> users = userMapper.queryUserByWrapper(wrapper);user.forEach(System.out::println):
}
2.然后再UserMapper中自定義方法
@Select("SELECT u.* FROM user u INNER JOIN address a ON u.id = a.user_id ${ew.customSqlSegment}")
//參數通過 @Param 注解指定名稱為 "ew"(是 EntityWrapper 的縮寫),類型是 MyBatis-Plus 提供的條件構造器 QueryWrapper,用于動態構建查詢條件
List <User> queryUserByWrapper(@Param("ew")QueryWrapper<User> wrapper)
或者也可以在UserMapper.xml中寫SQL
<select id ="queryUserByIdAndAddr" resultTyp="com.itheima.mp.domain.po.user">SELECT * FROM user u INNER JOIN address a ON u.id = a.user_id ${ew.customSqlSegment}
</select>