多表聯查
上文講過了自定義sql ,和wrapper的使用,但是我們可以發現 我們查詢的都是數據庫中的一張表,那么怎么進行多表聯查呢,當然也是用自定義sql來進行實現
比如說? 查詢 id 為 1? 2 4 的用戶 并且 地址在北京 的 用戶名稱 普通的sql查詢如下
select u.username from tb_user u,address a where u.id=a.user_id and a.city='北京' and u.id i n(1,2,4);
用join on 實現多表的sql為??
select u.username from tb_user u join address a on u.id=a.user_id where a.city='北京' and u.id in(1,2,4);
那么 我們如何用mp 來進行改造 自定義sql 來進行多表查詢呢
? ? ?先用? wrapper 來進行后面 where? 條件的拼接? 再用自定義sql 拼接
廢話不多說 直接上代碼??
?然后再usermapper中定義方法?
@Select("SELECT u.* FROM user u INNER JOIN address a ON u.id = a.user_id ${ew.customSqlSegment}")
List<User> queryUserByWrapper(@Param("ew")QueryWrapper<User> wrapper);
service接口
mp不僅對基本的 mapper層進行了接口的封裝,還對service層進行了接口的封裝,使得 基礎的crud也可以直接在controller層直接調用service層直接查詢,更加提升了代碼的簡潔性
而使用Iservice中的方法也很簡單??
通常我們有兩個? 一個是接口service,一個是實現接口的實現類? ? ?我們只需要讓接口繼承 iservice,然后讓自己的實現類 實現自己的接口,并且繼承serviceimpl? ?廢話不多說? 我們直接上代碼
其中User是對應的數據庫實體類? ?,同樣Usermapper 也是??
?但是我們這樣說是顯得太過寬泛? 我們直接上例子 對service接口進行測試
接口測試
我們 假如說? 現在有一個需求? ?根據用戶的id 來進行扣減用戶的余額? ?,而在用戶表中有一個狀態? 只有狀態正常的
并且余額充足的才能進行余額的扣減? ??
現在 我們在 Usercontroller 中定義 一個方法
//根據id扣除余額@PutMapping("/{id}/deduction/{money}")void deductMoney(@PathVariable Long id,@PathVariable Integer money){myService.deductMoney(id,money);}
然后是 userservice接口
package com.itheima.mp.service;import com.baomidou.mybatisplus.extension.service.IService;
import com.itheima.mp.domain.po.User;public interface IUserService extends IService<User> {void deductBalance(Long id, Integer money);
}
最后是實現類
package com.itheima.mp.service.impl;import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.itheima.mp.domain.po.User; import com.itheima.mp.mapper.UserMapper; import com.itheima.mp.service.IUserService; import org.springframework.stereotype.Service;@Service public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {@Overridepublic void deductBalance(Long id, Integer money) {// 1.查詢用戶User user = getById(id);// 2.判斷用戶狀態if (user == null || user.getStatus() == 2) {throw new RuntimeException("用戶狀態異常");}// 3.判斷用戶余額if (user.getBalance() < money) {throw new RuntimeException("用戶余額不足");}// 4.扣減余額baseMapper.deductMoneyById(id, money);} }
?mapper中的實現接口為??
@Update("UPDATE user SET balance = balance - #{money} WHERE id = #{id}")
void deductMoneyById(@Param("id") Long id, @Param("money") Integer money);
但是 但是這樣是否有點不太優雅? ?那么? 我們怎么把他變得優雅? 來? 讓我們改造一下
優雅的接口測試
首先? 我們可以看到 在 我們對比用戶狀態的時候 用戶狀態異常的數字是寫死的,這樣寫有沒有問題,沒有問題,但是假如我們以后用了多個用戶狀態的的數字,以后想改 是不是特別 的麻煩? ,所以我們干脆定義一個枚舉類型,來進行 用戶狀態的對比
我們原來user實體類中的類型 是?
是interger類型的對比 ,下面 我們 定義一個如下的枚舉? ?
?并在mp的yaml文件中配置枚舉處理器
mybatis-plus:configuration:default-enum-type-handler: com.baomidou.mybatisplus.core.handlers.MybatisEnumTypeHandler
配置好 之后再把user實體類中的 狀態的類型 改成 枚舉類型? ? ?
好,那么現在我們來解釋一下? 枚舉類型中的注解??
使用enumvalue 注解,代表著? 枚舉類中的哪個值 作為 數據庫status字段的值? ??
比如說? ?我們? 數據庫中定義的字段status為? int類型的,然后我們對應的數據庫user表的實體類user 的類型是 枚舉類型的這樣就會導致我們在查詢插入的時候出現類型轉換的錯誤,我們加上這個注解,開啟配置枚舉處理器,就可以 實現二者值之間的自動轉換??
下面 我們來 寫一個例子
@PostMappingvoid userSelect(@Param("id") Long id){
//通過枚舉類型 加用戶id進行查詢LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<User>().eq(User::getId, id).eq(User::getStatus, UserStatus.NORMAL);User user1 = myService.getBaseMapper().selectOne(wrapper);System.out.println(user1);//使用枚舉類型插入用戶User user = new User();
//我們著重看這一行 setstatususer.setStatus(UserStatus.NORMAL);user.setUsername("wang");user.setPassword("123456");UserInfo userInfo = new UserInfo();userInfo.setAge(1);userInfo.setGender("22");userInfo.setIntro("6666666");user.setInfo(userInfo);myService.save(user);
}
?下面我們用apifox進行測試??
可以看到? 用了enumvalue注解? 已經成功的把枚舉類型轉換成數據庫類型了,是不是灰常的優雅
優雅的json處理器
在上文中我們看到 怎么還有個userinfo 那玩意是什么鬼 ,下面我們來解釋一下?
?在數據庫中 我們的info字段定義的是一個json類型
但是 在我么們user實體類中確實 一個string類型的 字段? ,在我們插入的時候 會非常的麻煩 我們需要把字符串類型寫成類似于json類型進行插入,這樣太麻煩? ?
我們? 直接可以定義一個json類型的實體類 ,然后把user實體類的類型換成該json類型的實體類 ,然后再user實體類字段上加上json類型處理器的注解? 就可以完成轉換
@Data
@AllArgsConstructor(staticName = "set")
@NoArgsConstructor
public class UserInfo {private Integer age;private String intro;private String gender;
}
這樣我們再插入的時候 就可以完成 json類型之間的轉換了