MyBatis-Plus框架
ORM介绍
- ORM(Object Relational Mapping,对象关系映射)是为了解决面向对象与关系数据库存在的互不匹配现象的一种技术
- ORM通过使用描述对象和数据库之间映射的元数据将程序中的对象自动持久化到关系数据库中
- ORM框架的本质是简化编程中操作数据库的编码
MyBatis-Plus介绍
- Mybatis是一款优秀的数据持久层ORM框架,被广泛地应用于应用系统
- MyBatis能够非常灵活地实现动态SQL,可以使用XML或注解来配置和映射原生信息,能够轻松地将Java的POJO(Plain Ordinary Java Object,普通的Java对象)与数据库中的表和字段进行关系映射
- MyBatis-Plus是一个MyBatis的增强工具,在MyBatis的基础上做了增强,简化了开发
添加依赖
全局配置
配置数据库相关信息
添加完成后,还需要在配置文件中添加相应的配置
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/test?useSSL=false
spring.datasource.username=root
spring.datasource.password=root
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
添加@MapperScan注解
对于mybatis操作数据库的组件,我们称之为mapper
数据库相关的操作我们都会添加到mapper包里面
我们需要告诉MyBatis你的mapper包在哪里,所以需要在启动类添加@MapperScan
注解
package com.example.demo;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@MapperScan("com.example.demo.mapper")
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
MyBatis CRUD注解
MyBatis提供了很多注解来帮助我们完成增删改查
注解 | 功能 |
---|---|
@Insert | 实现插入 |
@Update | 实现更新 |
@Delete | 实现删除 |
@Select | 实现查询 |
@Result | 实现结果集封装 |
@Results | 可以与@Result一起使用,封装多个结果集 |
@One | 实现一对一结果集封装 |
@Many | 实现一对多结果集封装 |
MyBatis使用
创建一个新的SpringBoot项目,这里我取名为mpdemo
1、在pom.xml
中,配置MyBatis的相关依赖
<!-- MyBatisPlus依赖 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.2</version>
</dependency>
<!-- mysql驱动依赖 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<!-- 数据连接池 druid -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.20</version>
</dependency>
2、在application.properties
中,配置数据库的链接属性
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/test?useSSL=false
spring.datasource.username=root
spring.datasource.password=root
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
server.port=8088
3、为主类MpdemoApplication
添加包扫描
package com.example.mpdemo;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@MapperScan("com.example.mpdemo.mapper")
public class MpdemoApplication {
public static void main(String[] args) {
SpringApplication.run(MpdemoApplication.class, args);
}
}
4、在主包com.example.mpdemo
下创建entity
包,在该包下新增一个实体类User
package com.example.mpdemo.entity;
import lombok.Data;
@Data
public class User {
private int id;
private String username;
private String password;
private String birthday;
}
5、在主包com.example.mpdemo
下创建controller
包,并在controller包中创建新增控制器类UserController
package com.example.mpdemo.controller;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
public class UserContoller {
@GetMapping("/user")
public String query(){
return "查询用户";
}
}
6、在主包com.example.mpdemo
下创建mapper
包,并且在mapper包中新建mapper接口UserMapper
注:对于MyBatis,不需要实现它,只需要把方法的声明写上就好,数据库的操作会由MyBatis来完成,故写上一个接口即可
package com.example.mpdemo.mapper;
import com.example.mpdemo.entity.User;
import org.apache.ibatis.annotations.*;
import java.util.List;
//用于操作用户表,MyBaits会根据Mapper注解,动态实现UserMapper接口(实现类),动态代理技术
//Spring会自动创建UserMapper接口实现类对应的实例
@Mapper
public interface UserMapper {
// 查询所有用户并以列表的方式储存
@Select("select * from user")
public List<User> find();
}
7、接下来回到UserController
中调用这个mapper
虽然这个UserMapper是个接口,但我们不需要去实现它。因为MyBatis已经自动帮我们实现了,我们只需要直接调用它即可
package com.example.mpdemo.controller;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
public class UserContoller {
// 定义一个属性userMapper,没有进行注入前,它是null的
// @Autowired注解会将UserMapper接口中实例化的对象给自动注入到这个属性中
@Autowired
private UserMapper userMapper;
@GetMapping("/user")
public String query(){
// 调用UserMapper的find方法来获取数据表中所有的数据并存入变量userList中
List<User> userList = userMapper.find();
return "查询用户";
}
}
如果想要向前端返回JSON格式的数据,那么只需要把方法的返回值String
修改为List
并返回userList
即可
@GetMapping("/user")
public List query(){
// 调用UserMapper的find方法来获取数据表中所有的数据并存入变量userList中
List<User> userList = userMapper.find();
return userList;
}
8、在Mapper中实现插入数据接口
// 插入数据使用@Insert注解,用#{id}表示动态数据占位符
@Insert("insert into user values (#{id},#{username},#{password},#{birthday})")
public int insert(User user);// 返回一个int类型,插入失败返回0,成功返回1
9、在Controller中新增save方法
@PostMapping("/user")
// 接收前端传过来的User对象,调用userMapper.insert方法存入
public String save(User user){
int i = userMapper.insert(user); // 拿insert方法的返回值
// 判断插入是否成功
if(i > 0){
return "插入成功";
}else {
return "插入失败";
}
}
10、删除,修改同理,此处略
MyBatis-Plus使用
如果使用MyBatis-Plus,可以进一步简化Mapper的代码
1、在接口上继承MyBatis-Plus提供的BaseMapper接口并传入一个实体类
package com.example.mpdemo.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.mpdemo.entity.User;
import org.apache.ibatis.annotations.*;
import java.util.List;
@Mapper
public interface UserMapper extends BaseMapper<User> {
}
查看BaseMapper的源代码,可以看到它已经为我们创建了许多增删改查的方法,因此我们不需要自己写CRUD语句了,可以直接继承该接口并在Controller中使用
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package com.baomidou.mybatisplus.core.mapper;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import org.apache.ibatis.annotations.Param;
public interface BaseMapper<T> extends Mapper<T> {
int insert(T entity);
int deleteById(Serializable id);
int deleteByMap(@Param("cm") Map<String, Object> columnMap);
int delete(@Param("ew") Wrapper<T> queryWrapper);
int deleteBatchIds(@Param("coll") Collection<? extends Serializable> idList);
int updateById(@Param("et") T entity);
int update(@Param("et") T entity, @Param("ew") Wrapper<T> updateWrapper);
T selectById(Serializable id);
List<T> selectBatchIds(@Param("coll") Collection<? extends Serializable> idList);
List<T> selectByMap(@Param("cm") Map<String, Object> columnMap);
T selectOne(@Param("ew") Wrapper<T> queryWrapper);
Integer selectCount(@Param("ew") Wrapper<T> queryWrapper);
List<T> selectList(@Param("ew") Wrapper<T> queryWrapper);
List<Map<String, Object>> selectMaps(@Param("ew") Wrapper<T> queryWrapper);
List<Object> selectObjs(@Param("ew") Wrapper<T> queryWrapper);
<E extends IPage<T>> E selectPage(E page, @Param("ew") Wrapper<T> queryWrapper);
<E extends IPage<Map<String, Object>>> E selectMapsPage(E page, @Param("ew") Wrapper<T> queryWrapper);
}
我们可以直接调用MyBatis-Plus中提供的现成方法,实现简单的CRUD,可以看到我的UserMapper中现在没有任何方法
2、回到UserController
类中,将语句修改为MyBatis-Plus提供的方法
@GetMapping("/user")
public List query(){
// selectList是一个查询列表的语句,可以传入一个参数来按条件查询,不需要则填null
List<User> userList = userMapper.selectList(null);
return userList;
}
@PostMapping("/user")
public String save(User user){
int i = userMapper.insert(user); // MyBatis-Plus自带的插入方法就叫insert,故不变
if(i > 0){
return "插入成功";
}else {
return "插入失败";
}
}
多表查询及分页查询
实现复杂关系映射,可以使用@Result、@Results、@One、@Many注解完成复杂关系的配置
多表查询案例
用户表与订单表的多表查询
t_user表
DROP TABLE IF EXISTS `t_user`;
CREATE TABLE `t_user` (
`id` int NOT NULL AUTO_INCREMENT,
`username` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '0',
`password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '0',
`birthday` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '0',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
t_order表
DROP TABLE IF EXISTS `t_order`;
CREATE TABLE `t_order` (
`id` int NOT NULL AUTO_INCREMENT,
`ordertime` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '0',
`total` int NOT NULL,
`uid` int NOT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
1、修改实体类
package com.example.mpdemo.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.util.List;
@TableName("t_user") // 声明这个实体类对应的是数据库中t_user这张表
public class User {
@TableId(type = IdType.AUTO) // 声明下面这个id字段是一个主键,并且自动增长
private int id;
private String username;
private String password;
private String birthday;
// 描述用户的所有订单
// 这个字段实际上是不存在的,所以需要声明告诉MyBatis-Plus这个字段实际上是不存在的(exist = false)
@TableField(exist = false)
private List<Order> orders;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getBirthday() {
return birthday;
}
public void setBirthday(String birthday) {
this.birthday = birthday;
}
public List<Order> getOrders() {
return orders;
}
public void setOrders(List<Order> orders) {
this.orders = orders;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
", birthday='" + birthday + '\'' +
", orders=" + orders +
'}';
}
}
这样五个字段的SQL语句是SELECT id,username,password.orders FROM t_user
但是实际上,t_user
表中并没有相应字段,所以需要给orders方法添加注解@TableField(exist = false)
来声明并没有这个字段
2、修改UserMapper接口
MyBatis-Plus只能实现基本的CRUD,复杂的查询语句还需要自己编写
这里需要自行修改查询语句,如果使用了自己定义的SQL语句,那么实体类中的@TableName
注解就无关紧要了,因为查询调用的是用户自定义的方法,而不是MyBatis-Plus提供的方法。
@Select("select * from t_user")
@Results(
{
@Result(column = "id",property = "id"),
@Result(column = "username",property = "username"),
@Result(column = "password",property = "password"),
@Result(column = "birthday",property = "birthday"),
@Result(column = "id",property = "orders",javaType = List.class,
many=@Many(select = "com.example.mpdemo.mapper.OrderMapper.selectByUid")
)
}
)
List<User> selectAllUserAndOrders();
一个结果集注解@Results
中包含多个@Result
注解,每个@Result
都必须完成对列名和属性名的映射(即使他们都相同)
其中唯一有变动的是最后一条结果集,映射的是id与orders
它先声明要使用表里的id
字段,把这个字段映射给orders
属性,再传入这个orders的java类型List
MyBatis中允许调用其他Mapper的方法使用many参数并传入@Many注解,注:此处类名需要写全
接着在浏览器中访问这个方法
可以看到order字段可以成功取到order表的值
条件构造器
AbstractWrapper
AbstractWrapper是QueryWrapper(LambdaQueryWrapper) 和 UpdateWrapper(LambdaUpdateWrapper) 的父类
用于生成 sql 的 where 条件, entity 属性也用于生成 sql 的 where 条件
注意: entity 生成的 where 条件与 使用各个 api 生成的 where 条件没有任何关联行为
QueryWrapper和UpdateWrapper都是用来做条件查询的
要使用首先得创建一个QueryWrapper对象
QueryWrapper<User> queryWrapper = new QueryWrapper(); // 接收实体类User的QueryWrapper对象
然后在这个对象上进行条件查询。具体查询方法可以在MyBatis-Plus官方文档查询
如要查询一个username为zhangsan的数据,就可以用.eq方法
queryWrapper.eq("username","zhangsan")
操作完返回继承的BaseMapper中自带的查询方法即可,完整代码
@GetMapping("/user/find")
public List<User> findByCond(){
QueryWrapper<User> queryWrapper = new QueryWrapper();
queryWrapper.eq("username","zhangsan");
return userMapper.selectList(queryWrapper);
}
分页查询案例
MyBatis-Plus提供了分页插件,可以简便地使用分页查询功能,只需简单地进行配置
1、编写配置文件
新建一个配置类,类名不限,这里我取名为MyBatisPlusConfig
放在config包下
package com.example.mpdemo.config;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MyBatisPlusConfig {
@Bean
public MybatisPlusInterceptor paginationInterceptor() {
// 相当做了一个MyBatisPlus的拦截器,每次进行查询都会被拦截
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// 再定义了一个分页拦截器,新建一个拦截器并传入一个枚举参数,这个参数是你当前使用的数据库
PaginationInnerInterceptor paginationInterceptor = new PaginationInnerInterceptor(DbType.MYSQL);
// 添加拦截器
interceptor.addInnerInterceptor(paginationInterceptor);
return interceptor;
}
}
2、创建分页查询路由
实现分页需要创建一个MyBatisPlus自带的Page对象,并传入一个实体类,构造器传参则是查询的范围
@GetMapping("/user/findByPage")
public IPage findByPage(){
//设置起始值及每页条数
Page<User> page = new Page<>(0,2);
// Ipage也是默认封装的对象,用于查询结果集。第二个参数可以传入一个Wrapper
IPage iPage = userMapper.selectPage(page,null);
return iPage;
}
3、尝试访问
可以看到成功返回了两条记录