MyBatis在MyBatis Plus中的基本使用
yBatis Plus是基于MyBatis(https://mybatis.org/mybatis-3/zh/index.html),除了增加了更多方便的API外,也可以使用原生的MyBatis操作。
原生Mybatis操作数据库有两套API:
- 基于XML配置文件的方式:这种方式需要创建一个映射XML文件来定义SQL语句和结果映射关系。在XML文件中,你可以定义CRUD操作以及参数类型、返回类型等信息。通过读取XML配置文件,Mybatis会自动生成相应的SQL语句,并将查询结果映射为对应的Java对象。
第一步:resource下面编写一个xml:cn/bobohost/market/dao/UserDemoMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--名称空间,必须对应mapper接口-->
<mapper namespace="cn.bobohost.market.dao.UserDemoMapper">
<!--select 写select语句的标签,还有insert update delete
id:必须和mapper接口中的方法名一模一样,会被自动调用
resultType:查询出来的数据用什么java对象来封装
-->
<select id="selectUser" resultType="cn.bobohost.market.pojo.User">
select * from t_user where id = #{id}
</select>
</mapper>
在工程中,在java的文件夹中叫包(cn.bobohost.market.dao),在resources中的文件夹(资源)叫文件夹(cn/bobohost/market/dao)。本质在硬盘上都是文件夹,编写形式不同。
第二步:编写java代码:cn.bobohost.market.dao.UserDemoMapper:
package cn.bobohost.market.dao;
import cn.bobohost.market.pojo.User;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Select;
/**
* 用户持久层接口
* 默认无需实现,底层会自动通过动态代理实现。
*/
public interface UserDemoMapper extends BaseMapper<User> {
/**
* 根据id来查询用户(xml方式)
* 注意方法名必须和xml中的id一致!!!
* @param id
* @return
*/
User selectUser(Integer id);
}
2.注解方式:这种方式使用注解来直接在Java接口上标记SQL语句,省去了编写XML配置文件的过程。通过在方法上加上注解,可以指定SQL语句以及参数类型、返回类型等信息。
(简单明了,效率高,没有xml)
直接写mapper的java代码,使用注解来写语句,编写java代码:cn.bobohost.market.dao.UserDemoMapper:
package cn.bobohost.market.dao;
import cn.bobohost.market.pojo.User;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Select;
/**
* 用户持久层接口
* 默认无需实现,底层会自动通过动态代理实现。
*/
public interface UserDemoMapper extends BaseMapper<User> {
/**
* 根据id来查询用户(注解)
* @param id
* @return
*/
@Select("select * from t_user where id = #{id}")
User selectUserById(Integer id);
}
编程思想:约定编程。约定大于配置”(Convention over Configuration,简称为CoC)
自定义的更多操作-模糊查询(注解)
需求:根据用户名模糊查询用户列表:
第一步:mapper中定义方法,编写语句
cn.bobohost.market.dao.UserDemoMapper
package cn.bobohost.market.dao;
import cn.bobohost.market.pojo.User;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Select;
import java.util.List;
/**
* 用户持久层接口
* 默认无需实现,底层会自动通过动态代理实现。
*/
public interface UserDemoMapper extends BaseMapper<User> {
@Select("select * from t_user where user_name like concat('%',#{userName},'%')")
List<User> selectByUserNameLike(String userName);
}
第二步:编写业务层和表现层的相关代码:
cn.bobohost.market.service.UserDemoService
/**
* 根据用户名模糊查询用户列表
* @param userName
* @return
*/
List<User> findUserListByUserNameLike(String userName);
cn.bobohost.market.service.impl.UserDemoServiceImpl
@Override
public List<User> findUserListByUserNameLike(String userName) {
return userDemoMapper.selectByUserNameLike(userName);
}
cn.bobohost.market.web.controller.UserDemoController
private UserDemoService userDemoService;
@Autowired
public void setUserDemoService(UserDemoService userDemoService) {
this.userDemoService = userDemoService;
}
/**
* 根据用户名模糊查询
* @param userName
* @return
*/
@GetMapping("/username/{userName}")
public ResultDto<List<User>> listByUserNameLike(@PathVariable String userName){
List<User> userList = userDemoService.findUserListByUserNameLike(userName);
return ResultDto.success("查询成功", userList);
}
额外配置:
查看MyBatis打印的语句配置:
application-dev.yml
mybatis-plus:
configuration:
#会将MyBatis自己组装好的语句(要执行的语句)打印在控制台
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
完整简单的CRUD注解
cn.bobohost.market.dao.UserDemoMapper
@Select("select * from t_user where user_name like concat('%',#{userName},'%')")
List<User> selectByUserNameLike(String userName);
//保存
@Insert("insert into t_user values (null,#{userName},#{age})")
void insertUser(User user);
@Update("update t_user set user_name = #{userName} ,age = #{age} where id = #{id}")
void updateUserById(User user);
@Delete("delete from t_user where id =#{id}")
void deleteUserById(Integer id);
复杂数据操作-查询等
很多情况下数据操作的条件会比较复杂,尤其是查询,那么如何构建复杂查询条件?
- 1)面向语句:自己写复杂语句。(根据mysql学的内容自己整)优点学习成本低。
- 2)面向对象:使用MyBatisplus的Wrapper接口的api拼接条件。优点:不用怎么写sql,mapper中也无需写代码了。需要单独学习。
下面讲解面向对象的条件查询,使用的AbstractWrapper接口的子类:QueryWrapper(拼查询条件) 和 UpdateWrapper(拼更新条件)
查询条件:
需求:查询年龄大于等18岁的用户的列表
cn.bobohost.market.service.impl.UserDemoServiceImpl
@Override
public List<User> findUserListByAgeGte(Integer age, String userName) {
//构建业务条件
QueryWrapper<User> qw =new QueryWrapper<>();
//年龄大于等于某值
//参数1:数据库的字段列名,参数2:值
// qw.ge("age",age);
// //姓名包含xxx字符串,新版本无需加%了
// qw.like("user_name",userName);
//链式编程
qw.ge("age",age)
.like("user_name",userName);
//返回查询结果
return userDemoMapper.selectList(qw);
}
UserDemoController
/**
* 根据年龄和姓名查询
* @param age
* @param userName
* @return
*/
@GetMapping("/username/{userName}/age/{age}")
public ResultDto listByAgeGte(@PathVariable Integer age,@PathVariable String userName){
return ResultDto.success("查询成功"
//调用业务cent
,userDemoService.findUserListByAgeGte(age,userName));
}
分页查询
业务层会有分页查询,如下面的分页工具条:
不管前端是如何展示分页的,后端都一样。
前后端如何数据的配合才能分页呢?
-
请求:
- 前端:当前页码,每页最大记录数
- 后端:接收前端的两个参数,构建查询。
-
响应:
- 后端:根据分页查询的结果,封装出分页结果对象,该对象一般包含两个内容:符合条件的总记录数,当前页的列表
- 前端:获取到分页结果对象数据,进行计算页码和展示数据。
下面使用MyBatis plus来实现后端的分页查询。
第一步:配置MyBatisplus的分页拦截器
再建立一个包:config,用来存放java的配置。
package cn.bobohost.market.config;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
//代表当前类是个配置类。
@Configuration
//扫描Mapper(dao)
@MapperScan("cn.bobohost.market.dao")
public class MybatisPlusConfig {
/**
* 新的分页插件,一缓和二缓遵循mybatis的规则,需要设置 MybatisConfiguration#useDeprecatedExecutor = false 避免缓存出现问题(该属性会在旧插件移除后一同移除)
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.H2));
return interceptor;
}
// @Bean
// public ConfigurationCustomizer configurationCustomizer() {
// return configuration -> configuration.setUseDeprecatedExecutor(false);
// }
}
第二步:编写分页查询代码
UserDemoController
/**
* 分页结果查询
* @param user
* @param pageNum
* @param pageSize
* @return
*/
@PostMapping("/page/{pageNum}/{pageSize}")
public ResultDto listPage(@RequestBody User user,@PathVariable int pageNum,@PathVariable int pageSize){
ResultPageDto<User> userResultPageDto = userDemoService.findUserListPage(user, pageNum, pageSize);
return ResultDto.success("查询成功",userResultPageDto);
}
UserDemoService
/**
* 分页列表及
* @param user
* @return
*/
ResultPageDto<User> findUserListPage(User user,int pageNum,int pageSize);
cn.bobohost.market.service.impl.UserDemoServiceImpl
@Override
public ResultPageDto<User> findUserListPage(User user,int pageNum,int pageSize) {
//分页条件对象:参数1:当前的页码,参数2:每页显示的最大记录数
Page pageRequest =Page.of(pageNum,pageSize);
//业务的条件对象
QueryWrapper<User> qw =new QueryWrapper<>();
//一定要判断业务条件是否存在,否则语句会有问题
if(user.getAge()!=null){
qw.ge("age",user.getAge());
}
if(user.getUserName()!=null){
qw.like("userName",user.getUserName());
}
//参数1:请求的分页条件对象
//参数2:业务的条件对象
Page pageResponse = userDemoMapper.selectPage(pageRequest, qw);
//重新组装结果
return ResultPageDto.of(
//总记录数
pageResponse.getTotal(),
//当前页的数据
pageResponse.getRecords()
);
}