<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<groupId>org.jqgroupId>
<artifactId>mpSpringBootartifactId>
<version>1.0-SNAPSHOTversion>
<properties>
<java.version>1.8java.version>
properties>
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.2.5.RELEASEversion>
<relativePath/>
parent>
<dependencies>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>8.0.29version>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
dependency>
<dependency>
<groupId>com.baomidougroupId>
<artifactId>mybatis-plus-boot-starterartifactId>
<version>3.0.5version>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
<exclusions>
<exclusion>
<groupId>org.junit.vintagegroupId>
<artifactId>junit-vintage-engineartifactId>
exclusion>
exclusions>
dependency>
dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
plugin>
plugins>
build>
project>
mysql 8 配置 必须增加时区配置
# mysql 8 配置 必须增加时区配置
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis_plus?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
lombok 自动生成set、get方法
package com.jq.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private Long id;
private String name;
private Integer age;
private String email;
}
继承BaseMapper,所有crud都已编写完成
package com.jq.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.jq.pojo.User;
import org.springframework.stereotype.Repository;
@Repository // 代表持久层
public interface UserMapper extends BaseMapper<User> {
}
我们需要在启动类上去扫描我们的mapper包下的所有接口,@MapperScan(“com.jq.mapper”)
package com.jq;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
//扫描Mapper文件夹
@MapperScan("com.jq.mapper")
@SpringBootApplication
public class MybatisPlusApplication {
public static void main(String[] args) {
SpringApplication.run(MybatisPlusApplication.class,args);
}
}
package com.jq;
import com.jq.mapper.UserMapper;
import com.jq.pojo.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
@SpringBootTest
public class MybatisPlusApplicationTest {
//继承BaseMapper。所有的方法都自父类
//我们也可以编写自己的扩展方法
@Autowired
private UserMapper userMapper;
@Test
void contextLoads(){
//参数是一个Wrapper,条件构造器,这里我们先不用,设置为null即可
//查询全部用户
List<User> users = userMapper.selectList(null);
users.forEach(System.out::println);
}
}
我们所有的sql是不可见的,我们需要知道它是怎么执行的,所以我们必须要看日志!
# 配置日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
/**
* 测试插入
*/
@Test
public void testInsert(){
User user = new User();
user.setName("小明");
user.setAge(3);
user.setEmail("[email protected]");
int result = userMapper.insert(user); //自动生成id
System.out.println(result);//受影响的行数
System.out.println(user); //发现,id会自动回填
}
数据库中主键生成
雪花算法,自动生成id,Long型id
雪花算法生成的ID是一个64 bit的long型的数字且按时间趋势递增。
public enum IdType {
AUTO(0),
NONE(1),
INPUT(2), //手动输入
ID_WORKER(3),
UUID(4),
ID_WORKER_STR(5);
}
/**
* 测试更新
*/
@Test
public void testUpdate(){
User user = new User();
//通过条件自动拼接动态sql
user.setId(5L);
user.setName("小红");
user.setAge(10);
user.setEmail("[email protected]");
int result = userMapper.updateById(user); //自动生成id
System.out.println(result);//受影响的行数
}
创建时间、修改时间!这些操作一般都是自动化完成的,我们不希望手动更新!
阿里巴巴开发手册,所有数据库表
再次测试插入方法,先把实体类同步
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
//对应数据库的主键(uuid,自增id,雪花算法,redis,zookeeper)
@TableId(type = IdType.ID_WORKER) //描述:主键注解
private Long id;
private String name;
private Integer age;
private String email;
private Date createTime;
private Date updateTime;
}
实体类的字段属性上添加注解
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
//对应数据库的主键(uuid,自增id,雪花算法,redis,zookeeper)
@TableId(type = IdType.ID_WORKER) //描述:主键注解
private Long id;
private String name;
private Integer age;
private String email;
//字段添加填充内容
@TableField(fill = FieldFill.INSERT)
private Date createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updateTime;
}
编写处理器处理这个注解即可!
package com.jq.handler;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
import java.util.Date;
@Slf4j
@Component //把自己定义的处理器加入到spring 的ioc容器中
public class MyMetaObjectHandler implements MetaObjectHandler {
/**
* 插入时的填充策略
* @param metaObject
*
*
*/
@Override
public void insertFill(MetaObject metaObject) {
log.info("start insert fill ....");
/**
* default MetaObjectHandler
* setFieldValByName(String fieldName, Object fieldVal, MetaObject metaObject)
*/
this.setFieldValByName("createTime",new Date(),metaObject);
this.setFieldValByName("updateTime",new Date(),metaObject);
}
/**
*
* @param metaObject
*/
@Override
public void updateFill(MetaObject metaObject) {
log.info("start update fill ....");
this.setFieldValByName("updateTime",new Date(),metaObject);
}
}
测试插入,测试更新即可
描述:字段注解(非主键)
public @interface TableField {
String value() default "";
String el() default "";
boolean exist() default true;
String condition() default "";
String update() default "";
FieldStrategy strategy() default FieldStrategy.DEFAULT;
FieldFill fill() default FieldFill.DEFAULT;
boolean select() default true;
}
public enum FieldFill {
DEFAULT,
INSERT,
UPDATE,
INSERT_UPDATE;
}
总是认为总是出现问题,无论干什么都会上锁,再去操作
总是认为不会出现问题,无论干什么都不去上锁。如果出现问题,再次更新值测试!
取出记录时,获取当前 version
更新时,带上这个 version
执行更新时,
set version = newVersion where version = oldVersion
如果 version 不对,就更新失败
实体类添加对应的字段
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
//对应数据库的主键(uuid,自增id,雪花算法,redis,zookeeper)
@TableId(type = IdType.ID_WORKER) //描述:主键注解
private Long id;
private String name;
private Integer age;
private String email;
@Version //乐观锁的注解
private Integer version;
//字段添加填充内容
@TableField(fill = FieldFill.INSERT)
private Date createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updateTime;
}
注册组件
package com.jq.config;
import com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;
//扫描Mapper文件夹
@MapperScan("com.jq.mapper")
@EnableTransactionManagement
@Configuration //配置类
public class MybatisPlusConfig {
/**
* 旧版
*/
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
return new OptimisticLockerInterceptor();
}
/**
* 新版
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return mybatisPlusInterceptor;
}
}
测试代码
/**
* 测试乐观锁成功
*/
@Test
public void testoptimisticLocker(){
//1.查询用户信息
User user = userMapper.selectById(1L);
//2.修改用户信息
user.setName("张飞");
user.setEmail("[email protected]");
//3.执行更新操作
userMapper.updateById(user);
}
多线程要加锁
/**
* 测试乐观锁失败!多线程下
*/
@Test
public void testoptimisticLocker2(){
//线程1
User user = userMapper.selectById(1L);
user.setName("张飞");
user.setEmail("[email protected]");
//模拟另一个线程执行插队操作
User user2 = userMapper.selectById(1L);
user2.setName("张飞的大哥");
user2.setEmail("[email protected]");
userMapper.updateById(user2);//如果没有乐观锁,就会覆盖插队线程的值
//自旋锁多次尝试提交
//3.执行更新操作
userMapper.updateById(user);
}
描述:乐观锁注解、标记 @Verison 在字段上
/**
* 测试查询,单个查询
*/
@Test
public void testSelectById(){
User user = userMapper.selectById(1L);
System.out.println(user);
}
/**
* 测试查询,多单个查询
*/
@Test
public void testSelectById2(){
List<User> users = userMapper.selectBatchIds(Arrays.asList(1, 2, 3));
users.forEach(System.out::println);
}
/**
* 条件查询之一 使用map操作
*/
@Test
public void testSelectById3(){
HashMap<String, Object> map = new HashMap<>();
//自定义要查询的条件
map.put("name","张飞");
List<User> users = userMapper.selectByMap(map);
users.forEach(System.out::println);
}
原始的limit进行分页
pageHelper第三方插件
Mybatis Plus 内置了分页插件
//扫描Mapper文件夹
@MapperScan("com.jq.mapper")
@EnableTransactionManagement
@Configuration //配置类
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
//注册乐观锁插件
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
/**
* 新的分页插件,一缓和二缓遵循mybatis的规则,需要设置 MybatisConfiguration#useDeprecatedExecutor = false 避免缓存出现问题(该属性会在旧插件移除后一同移除)
*/
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
@Bean
public ConfigurationCustomizer configurationCustomizer() {
return configuration -> configuration.setUseDeprecatedExecutor(false);
}
}
测试分页查询
/**
* 测试分页查询
*
*/
@Test
public void testPage(){
/**
* 参数1:当前页
* 参数2:页面大小
*/
Page<User> page = new Page<>(2,3);
userMapper.selectPage(page,null);
page.getRecords().forEach(System.out::println);
}
/**
* 测试删除,,单个删除,根据id删除记录
*/
@Test
public void testDeleteById(){
userMapper.deleteById(1L);
}
/**
* 测试删除,,单个删除,根据id删除记录
*/
@Test
public void testDeleteById2(){
userMapper.deleteBatchIds(Arrays.asList(1,2,3));
}
/**
* 测试删除 ,通过条件删除,使用map操作
*/
@Test
public void testDeleteById3() {
HashMap<String, Object> map = new HashMap<>();
//自定义要查询的条件
map.put("name", "小红");
userMapper.deleteByMap(map);
}
测试逻辑删除
pojo实体类中添加属性
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
//对应数据库的主键(uuid,自增id,雪花算法,redis,zookeeper)
@TableId(type = IdType.ID_WORKER) //描述:主键注解
private Long id;
private String name;
private Integer age;
private String email;
@Version //乐观锁的注解
private Integer version;
@TableLogic //逻辑删除
private Integer deleted;
//字段添加填充内容
@TableField(fill = FieldFill.INSERT)
private Date createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updateTime;
}
配置
# 配置逻辑删除
# 全局逻辑删除的实体字段名(since 3.3.0,配置后可以忽略不配置步骤2)flag
# 逻辑已删除值(默认为 1)
# 逻辑未删除值(默认为 0)
mybatis-plus.global-config.db-config.logic-delete-value=1
mybatis-plus.global-config.db-config.logic-not-delete-value=0
测试一下删除
走的是更新操作,并不是删除操作
更新数据库中,deleted的值为1
再次执行查询操作,会自动带上deleted=0
public @interface TableLogic {
String value() default "";
String delval() default "";
}
十分重要,我们写一些复杂的的sql就可以使用它来替代!
isNotNull("name")--->name is not null
ge("age", 12)--->age >= 18
@Test
void contextLoads() {
//查询name不为空的用户,并且邮箱不为空的用户,年龄>=12
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.isNotNull("name") //isNotNull("name")--->name is not null
.isNotNull("email") // isNotNull("email")--->name is not null
.ge("age",12); //ge("age", 12)--->age >= 18
userMapper.selectList(wrapper).forEach(System.out::println);
}
@Test
void test2() {
// 查询名字 小琳
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("name","小琳");
User user = userMapper.selectOne(queryWrapper);
System.out.println(user);
}
BETWEEN 值1 AND 值2
between("age", 18, 30)--->age between 18 and 30
@Test
void test3() {
// 查询年龄在 2-22岁之间的用户
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.between("age",2,22); //区间
Integer count = userMapper.selectCount(queryWrapper); //查询结果数
System.out.println(count);
}
NOT LIKE ‘%值%’
notLike("name", "王")--->name not like '%王%'
LIKE ‘%值’
likeLeft("name", "王")--->name like '%王'
LIKE ‘值%’
likeRight("name", "王")--->name like '王%'
@Test
void test4() {
//
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
// 左和右 e%
queryWrapper.notLike("name","e")
.likeRight("email","t");
List<Map<String, Object>> maps = userMapper.selectMaps(queryWrapper);
maps.forEach(System.out::println);
}
inSql("age", "1,2,3,4,5,6")--->age in (1,2,3,4,5,6)
inSql("id", "select id from table where id < 3")--->id in (select id from table where id < 3)
@Test
void test5() {
//
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
// 左和右 e%
queryWrapper.inSql("id","select id from user where id<6");
List<Object> objects = userMapper.selectObjs(queryWrapper);
objects.forEach(System.out::println);
}
SELECT id,name,age,email,version,deleted,create_time,update_time FROM user WHERE deleted=0 AND (id IN (select id from user where id<6))
ORDER BY 字段, … DESC
orderByDesc("id", "name")--->order by id DESC,name DESC
@Test
void test6() {
//根据id 排序
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.orderByAsc("id");
List<User> users = userMapper.selectList(queryWrapper);
users.forEach(System.out::println);
}
AutoGenerator 是 MyBatis-Plus 的代码生成器,通过 AutoGenerator 可以快速生成
等各个模块的代码,极大的提升了开发效率。
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<groupId>org.jqgroupId>
<artifactId>mpgeneratorartifactId>
<version>1.0-SNAPSHOTversion>
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.6.3version>
<relativePath/>
parent>
<properties>
<java.version>1.8java.version>
properties>
<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.1version>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<optional>trueoptional>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<scope>runtimescope>
dependency>
<dependency>
<groupId>com.baomidougroupId>
<artifactId>mybatis-plus-generatorartifactId>
<version>3.5.1version>
dependency>
<dependency>
<groupId>org.freemarkergroupId>
<artifactId>freemarkerartifactId>
<version>2.3.31version>
dependency>
dependencies>
project>
FastAutoGenerator.create("url", "username", "password")
.globalConfig(builder -> {
builder.author("baomidou") // 设置作者
.enableSwagger() // 开启 swagger 模式
.fileOverride() // 覆盖已生成文件
.outputDir("D://"); // 指定输出目录
})
.packageConfig(builder -> {
builder.parent("com.baomidou.mybatisplus.samples.generator") // 设置父包名
.moduleName("system") // 设置父包模块名
.pathInfo(Collections.singletonMap(OutputFile.mapperXml, "D://")); // 设置mapperXml生成路径
})
.strategyConfig(builder -> {
builder.addInclude("t_simple") // 设置需要生成的表名
.addTablePrefix("t_", "c_"); // 设置过滤表前缀
})
.templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板,默认的是Velocity引擎模板
.execute();
import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.OutputFile;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import sun.font.TrueTypeFont;
import java.util.Collections;
public class FastAutoGeneratorTest {
public static void main(String[] args) {
FastAutoGenerator.create("jdbc:mysql://127.0.0.1:3306/rjdb?characterEncoding=utf-8&userSSL=false&serverTimezone=GMT%2B8", "root", "123456")
//全局配置
.globalConfig(builder -> {
builder.author("jq") // 设置作者
.enableSwagger() // 开启 swagger 模式
.fileOverride() // 覆盖已生成文件
.outputDir("F://JavaCode//GeneratorCode/src/main/java"); // 指定输出目录
})
//包配置
.packageConfig(builder -> {
builder.parent("com.jq") // 设置父包名
.moduleName("mybatisplus") // 设置父包模块名
.pathInfo(Collections.singletonMap(OutputFile.mapperXml, "F://JavaCode//GeneratorCode")); // 设置mapperXml生成路径
})
//策略配置
.strategyConfig(builder -> {
builder.addInclude("address_book","category") // 设置需要生成的表名
.addTablePrefix("t_", "c_"); // 设置过滤表前缀
//entity配置
//builder.entityBuilder().enableLombok(); //开启 lombok 模型
//controller配置
builder.controllerBuilder().enableHyphenStyle() // 开启驼峰转连字符
.enableRestStyle();//开启生成@RestController 控制器
})
.templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板,默认的是Velocity引擎模板
.execute();
}
}