MyBatis-Plus (opens new window)(简称 MP)是一个 MyBatis (opens new window) 的增强工具,在mybatis的基础上只做增强不做改变
CREATE DATABASE mybatis_plus;
DROP TABLE IF EXISTS my_user;
CREATE TABLE my_user
(
id BIGINT(20) NOT NULL COMMENT '主键ID',
NAME VARCHAR(30) NULL DEFAULT NULL COMMENT '姓名',
age INT(11) NULL DEFAULT NULL COMMENT '年龄',
email VARCHAR(50) NULL DEFAULT NULL COMMENT '邮箱',
PRIMARY KEY (id)
);
INSERT INTO my_user (id, NAME, age, email) VALUES
(1, 'Jone', 18, '[email protected]'),
(2, 'Jack', 20, '[email protected]'),
(3, 'Tom', 28, '[email protected]'),
(4, 'Sandy', 21, '[email protected]'),
(5, 'Billie', 24, '[email protected]');
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.6.2version>
<relativePath/>
parent>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starterartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
<dependency>
<groupId>com.baomidougroupId>
<artifactId>mybatis-plus-boot-starterartifactId>
<version>3.5.0version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<scope>runtimescope>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<optional>trueoptional>
dependency>
dependencies>
spring:
datasource:
username: root
password: 123456
url: jdbc:mysql://localhost:3306/mybatis_plus? serverTimezone=GMT%2B8&characterEncoding=utf-8 #mysql8驱动需要添加时区
driver-class-name: com.mysql.cj.jdbc.Driver #mysql8驱动
#mybatis日志
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
#数据访问层的xml位置
mapper-locations: classpath:mappers/*.xml
/**
* @Author 李燕茹
* @create 2022/1/20 13:43
*/
@SpringBootApplication //启动类注解
@MapperScan("com.xyxy.mapper") //Mapper扫包
public class MybatisPlusApplication {
public static void main(String[] args) {
SpringApplication.run(MybatisPlusApplication.class,args);
}
}
@Data
@TableName("my_user") //数据库表名和类名不一致时添加注解
public class User {
private Long id;
private String name;
private Integer age;
private String email;
}
//接口继承基类,有很多内置方法
public interface UserMapper extends BaseMapper<User> {
}
/**
* @Author 李燕茹
* @create 2022/1/20 13:47
*/
@SpringBootTest
public class MapperTest {
// @Autowired //默认按照类型自动装配,是spring的注解
@Resource //默认按照名字装配,找不到对应名称是按照类型装配,是J2EE的注解
private UserMapper userMapper;
@Test
public void testFindAll(){
//selectList()方法的参数:封装了查询条件
//null:不加任何查询条件
List<User> users = userMapper.selectList(null);
public void testFindAll(){
List<User> users = userMapper.selectList(null);
users.forEach(System.out::println);
}
}
控制台打印结果:
User(id=1, name=Jone, age=18, [email protected])
User(id=2, name=Jack, age=20, [email protected])
User(id=3, name=Tom, age=28, [email protected])
User(id=4, name=Sandy, age=21, [email protected])
User(id=5, name=Billie, age=24, [email protected])
MP中的基本CRUD在内置的BaseMapper中已经实现
@Test
public void testInsert(){
User user = new User();
user.setName("zhangsan");
user.setAge(3);
user.setEmail("[email protected]");
int insert = userMapper.insert(user);
System.out.println("返回受影响的行数:"+insert);
}
@Test
public void testSelect(){
//根据id查询结果
User user = userMapper.selectById(1);
System.out.println("根据id查询结果:"+user);
//根据id的集合查找结果集
List<User> users = userMapper.selectBatchIds(Arrays.asList(1, 2, 3, 4));
System.out.println("根据ids查询结果集:" +users);
//根据条件查询
Map map = new HashMap();
map.put("name","zhangsan");
map.put("age",3);
List<User> userList = userMapper.selectByMap(map);
System.out.println("根据条件map集合查询:"+userList);
}
@Test
public void testUpdate(){
User user = new User();
user.setId(1L);
user.setName("修改");
//update时生成的SQL是动态语句,将传入的user不为空的数据进行修改
int update = userMapper.updateById(user);
System.out.println("受影响的行数:" +update);
}
@Test
public void testDelete(){
int delete = userMapper.deleteById(5);
System.out.println("受影响的行数:"+delete);
}
MP中有接口IService和其实现类ServiceImpl封装了常见的业务层逻辑代码
public interface UserService extends IService<User> {
}
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
}
@Test
public void testCount(){
long count = userService.count();
System.out.println("数据记录条数:"+count);
}
@Test
public void testSaveBatch(){
// SQL长度有限制,海量数据插入单条SQL无法实行,
// 因此MP将批量插入放在了通用Service中实现,而不是通用Mapper
ArrayList<User> users = new ArrayList<>();
for (int i = 0; i < 5; i++) {
User user = new User();
user.setName("Helen" + i);
user.setAge(10 + i);
users.add(user);
}
userService.saveBatch(users);
}
public interface UserMapper extends BaseMapper<User> {
List<User> selectAllByName(String name);
}
<select id="selectAllByName" resultType="com.xyxy.pojo.User">
select * from my_user where name=#{name}
select>
@Test
public void testSelectAllByName(){
List<User> users = userMapper.selectAllByName("zhangsan");
System.out.println(users);
}
public interface UserService extends IService<User> {
List<User> listAllByName(String name);
}
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
@Override
public List<User> listAllByName(String name) {
// baseMapper对象指向当前业务的mapper对象
return baseMapper.selectAllByName(name);
}
}
@Test
public void testSelectAllByName(){
List<User> users = userService.listAllByName("zhangsan");
System.out.println(users);
}
标注在实体类上
@TableName("my_user") //数据库表名
public class User {
type属性用来定义主键策略
@TableId(type = IdType.ASSIGN_ID)
private Long id;
注意:当对象的id被明确赋值时,不会使用雪花算法
@TableId(type = IdType.AUTO)
private Long id;
注意:该类型请确保数据库设置了 ID自增 否则无效
#全局设置主键生成策略
mybatis-plus.global-config.db-config.id-type=auto
(1)value属性:将数据库字段与实体类属性名对应
(2)自动填充
阿里巴巴的开发手册中建议每个数据库表必须要有create_time 和 update_time字段,我们可以使用自动填充功能维护这两个字段
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
实现元对象处理器接口 -> 创建handler包,创建MyMetaObjectHandler类
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
this.strictInsertFill(metaObject,"createTime", LocalDateTime.class,LocalDateTime.now());
this.strictInsertFill(metaObject,"updateTime", LocalDateTime.class,LocalDateTime.now());
}
@Override
public void updateFill(MetaObject metaObject) {
this.strictUpdateFill(metaObject,"updateTime",LocalDateTime.class,LocalDateTime.now());
}
}
测试添加和修改
逻辑删除:只对自动注入的 sql 起效:
方法一:配置com.baomidou.mybatisplus.core.config.GlobalConfig$DbConfig
mybatis-plus:
global-config:
db-config:
logic-delete-field: flag # 全局逻辑删除的实体字段名(since 3.3.0,配置后可以忽略不配置步骤2)
logic-delete-value: 1 # 逻辑已删除值(默认为 1)
logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
方法二:添加@TableLogic注解
@TableLogic
@TableField(value = "is_delete")
private Integer isDelete;
测试删除
1、创建配置类
@Configuration
@MapperScan("scan.your.mapper.package")
public class MybatisPlusConfig {
/**
* 新的分页插件,一缓和二缓遵循mybatis的规则,需要设置 MybatisConfiguration#useDeprecatedExecutor = false 避免缓存出现问题(该属性会在旧插件移除后一同移除)
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}
2、测试类
@Test
public void testPage(){
//创建分页参数
Page<User> pageParam = new Page<>(1,5);
Page<User> page = userMapper.selectPage(pageParam, null);
System.out.println(page.getTotal());//记录条数
System.out.println(page.getRecords());//数据
}
1、编写UserMapper接口
/**
* 查询 : 根据年龄查询用户列表,分页显示
* @param page 分页对象,xml中可以从里面进行取值,传递参数 Page 即自动分页,必须放在第一位
* @param age 年龄
* @return 分页对象
*/
IPage<User> selectByPage(Page<?> page,Integer age);
2、xml
<select id="selectByPage" resultType="com.xyxy.pojo.User">
select * from my_user where age > #{age}
select>
3、测试类
@Test
public void testPage2(){
//创建分页参数
Page<User> pageParam = new Page<>(1,5);
userMapper.selectByPage(pageParam,18);
List<User> list = pageParam.getRecords();
System.out.println(list);//数据
}
1、配置文件
@Configuration
@MapperScan("scan.your.mapper.package")
public class MybatisPlusConfig {
/**
* 新的分页插件,一缓和二缓遵循mybatis的规则,需要设置 MybatisConfiguration#useDeprecatedExecutor = false 避免缓存出现问题(该属性会在旧插件移除后一同移除)
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
//分页插件
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
//乐观锁插件
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return interceptor;
}
}
2、加注解
@Version
private Integer version;
Wrapper : 条件构造抽象类,最顶端父类
AbstractWrapper : 用于查询条件封装,生成 sql 的 where 条件
QueryWrapper : 查询条件封装
UpdateWrapper : Update 条件封装
AbstractLambdaWrapper : 使用Lambda 语法
LambdaQueryWrapper :用于Lambda语法使用的查询Wrapper
LambdaUpdateWrapper : Lambda 更新封装Wrapper
@Test
public void test1() {
//查询名字中包含n,年龄大于等于10且小于等于20,email不为空的用户
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper
.like("name", "m")
.between("age", 10, 20)
.isNotNull("email");
List<User> users = userMapper.selectList(queryWrapper);
users.forEach(System.out::println);
}
@Test
public void test2() {
//按年龄降序查询用户,如果年龄相同则按id升序排列
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper
.orderByDesc("age")
.orderByAsc("age");
List<User> users = userMapper.selectList(queryWrapper);
users.forEach(System.out::println);
}
@Test
public void test3() {
//删除email为空的
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.isNull("email");
int delete = userMapper.delete(queryWrapper);
System.out.println("成功记录:" +delete);
}
@Test
public void test4() {
//查询名字中包含n,且(年龄小于18或email为空的用户),并将这些用户的年龄设置为18,
// 邮箱设置为 [email protected]
QueryWrapper<User> queryWrapper =new QueryWrapper<>();
queryWrapper.like("name","n")
.and(i -> i.lt("age",18).or().isNull("email"));
User user = new User();
user.setAge(18);
user.setEmail("[email protected]");
int update = userMapper.update(user, queryWrapper);
System.out.println("成功记录数:" + update);
}
@Test
public void test5() {
//查询所有用户的用户名和年龄
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.select("name","age");
List<User> users = userMapper.selectList(queryWrapper);
users.forEach(System.out::println);
}
@Test
public void test6() {
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.inSql("id","select id from my_user where id<3");
List<User> users = userMapper.selectList(queryWrapper);
users.forEach(System.out::println);
}
@Test
public void test7() {
//组装set子句
UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
updateWrapper
.set("age", 18)
.set("email", "[email protected]")
.like("name", "n")
.and(i -> i.lt("age", 18).or().isNull("email")); //lambda表达式内的逻辑优先运算
//这里必须要创建User对象,否则无法应用自动填充。如果没有自动填充,可以设置为null
User user = new User();
int result = userMapper.update(user, updateWrapper);
System.out.println(result);
}
动态组装查询条件
@Test
public void test8() {
//查询名字中包含n,年龄大于10且小于20的用户,查询条件来源于用户输入,是可选的
//定义查询条件,有可能为null(用户未输入)
String name = null;
Integer ageBegin = 10;
Integer ageEnd = 20;
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
// if (StringUtils.isNotBlank(name)){
// queryWrapper.like("name",name);
// }
// if (ageBegin != null){
// queryWrapper.ge("age",ageBegin);
// }
// if (ageEnd != null){
// queryWrapper.lt("age",ageEnd);
// }
queryWrapper
.like(StringUtils.isNotBlank(name),"name",name)
.ge(ageBegin != null,"age",ageBegin)
.lt(ageEnd != null,"age",ageEnd);
List<User> users = userMapper.selectList(queryWrapper);
users.forEach(System.out::println);
}
@Test
public void test9() {
//查询名字中包含n,年龄大于10且小于20的用户,查询条件来源于用户输入,是可选的
//定义查询条件,有可能为null(用户未输入)
String name = null;
Integer ageBegin = 10;
Integer ageEnd = 20;
LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper
//避免使用字符串,防止运行时出错
.like(StringUtils.isNotBlank(name),User::getName,name)
.ge(ageBegin != null,User::getAge,ageBegin)
.lt(ageEnd != null,User::getAge,ageEnd);
List<User> users = userMapper.selectList(queryWrapper);
users.forEach(System.out::println);
}
@Test
public void test10() {
//查询名字中包含n,且(年龄小于18或email为空的用户),并将这些用户的年龄设置为18,
// 邮箱设置为 [email protected]
LambdaUpdateWrapper<User> queryWrapper =new LambdaUpdateWrapper<>();
queryWrapper.like(User::getName,"n")
.and(i -> i.lt(User::getAge,18).or().isNull(User::getEmail));
User user = new User();
user.setAge(18);
user.setEmail("[email protected]");
int update = userMapper.update(user, queryWrapper);
System.out.println("成功记录数:" + update);
}
<dependency>
<groupId>com.baomidougroupId>
<artifactId>mybatis-plus-generatorartifactId>
<version>3.5.1version>
dependency>
适用3.5.1以上版本
package com.xyxy.blog.utils;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.OutputFile;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import java.util.Collections;
/**
* @Author 李燕茹
* @create 2021/12/20 20:14
* MybatisPlus代码生成器
*/
public class MPGenerator {
public static void main(String[] args) {
FastAutoGenerator.create("jdbc:mysql://localhost:3306/blog?useUnicode=true&serverTimezone=Asia/Shanghai&characterEncoding=utf8&autoReconnect=true&useSSL=false&allowMultiQueries=true",
"root", "123456")
.globalConfig(builder -> {
builder.author("李燕茹") // 设置作者
.enableSwagger() // 开启 swagger 模式
.fileOverride() // 覆盖已生成文件
.commentDate("yyyy-MM-dd")
.outputDir(System.getProperty("user.dir")+"\\src\\main\\java"); // 指定输出目录
})
.packageConfig(builder -> {
builder.parent("com.mp") // 设置父包名
.moduleName("blog") // 设置父包模块名
.entity("entity")
.service("service")
.serviceImpl("service.serviceImpl")
.controller("controller")
.mapper("mapper")
.xml("mapper")
.pathInfo(Collections.singletonMap(OutputFile.mapperXml, System.getProperty("user.dir")+"\\src\\main\\resources\\")); // 设置mapperXml生成路径
})
.strategyConfig(builder -> {
builder.addInclude("tb_menu") // 设置需要生成的表名
.addTablePrefix("tb_") //过滤表明前缀,
.serviceBuilder() //service生成策略
.formatServiceFileName("%sService") //service类名,%s适配,根据表明替换
.formatServiceImplFileName("%sServiceImpl") // service实现类
.entityBuilder() //实体类生成策略
.enableLombok() //开启lombok
.logicDeleteColumnName("deleted") //说明逻辑删除是哪个字段
.enableTableFieldAnnotation() // 属性加上说明注解
.controllerBuilder() //controller生成策略
.formatFileName("%sController")
.enableRestStyle() //开启RestController
.mapperBuilder()
.superClass(BaseMapper.class) //dao层继承父类
.formatMapperFileName("%sMapper")
.enableMapperAnnotation() //@Mapper注解开启
.formatXmlFileName("%sMapper");
})
.templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板,默认的是Velocity引擎模板
.execute();
}
}
<dependency>
<groupId>com.baomidougroupId>
<artifactId>mybatis-plus-generatorartifactId>
<version>3.4.1version>
dependency>
<dependency>
<groupId>org.apache.velocitygroupId>
<artifactId>velocity-engine-coreartifactId>
<version>2.0version>
dependency>
package com.atguigu.srb.core;
public class CodeGenerator {
@Test
public void genCode() {
// 1、创建代码生成器
AutoGenerator mpg = new AutoGenerator();
// 2、全局配置
GlobalConfig gc = new GlobalConfig();
String projectPath = System.getProperty("user.dir");
gc.setOutputDir(projectPath + "/src/main/java");
gc.setAuthor("Helen");
gc.setOpen(false); //生成后是否打开资源管理器
gc.setServiceName("%sService"); //去掉Service接口的首字母I
gc.setIdType(IdType.AUTO); //主键策略
gc.setSwagger2(true);//开启Swagger2模式
mpg.setGlobalConfig(gc);
// 3、数据源配置
DataSourceConfig dsc = new DataSourceConfig();
dsc.setUrl("jdbc:mysql://localhost:3306/srb_core?serverTimezone=GMT%2B8&characterEncoding=utf-8");
dsc.setDriverName("com.mysql.cj.jdbc.Driver");
dsc.setUsername("root");
dsc.setPassword("123456");
dsc.setDbType(DbType.MYSQL);
mpg.setDataSource(dsc);
// 4、包配置
PackageConfig pc = new PackageConfig();
pc.setParent("com.atguigu.srb.core");
pc.setEntity("pojo.entity"); //此对象与数据库表结构一一对应,通过 DAO 层向上传输数据源对象。
mpg.setPackageInfo(pc);
// 5、策略配置
StrategyConfig strategy = new StrategyConfig();
strategy.setNaming(NamingStrategy.underline_to_camel);//数据库表映射到实体的命名策略
strategy.setColumnNaming(NamingStrategy.underline_to_camel);//数据库表字段映射到实体的命名策略
strategy.setEntityLombokModel(true); // lombok
strategy.setLogicDeleteFieldName("is_deleted");//逻辑删除字段名
strategy.setEntityBooleanColumnRemoveIsPrefix(true);//去掉布尔值的is_前缀(确保tinyint(1))
strategy.setRestControllerStyle(true); //restful api风格控制器
mpg.setStrategy(strategy);
// 6、执行
mpg.execute();
}
}