国产的开源框架,基于mybatis,相当于对mybatis进行了二次的封装,是2019年开源中国里面排行第一的框架,它的核心功能就是简化mybatis开发,提高效率。
官网:Redirecthttps://mp.baomidou.com/
MyBatis-Plus (opens new window)(简称 MP)是一个 MyBatis (opens new window)的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。
使用第三方组件:
-
导入对应的依赖
-
写相应的配置
-
编写代码
找依赖的官网:https://mvnrepository.com/
一、快速上手步骤
1、创建数据库、数据表
2、创建SpringBoot项目
3、导入依赖
<!-- https://mvnrepository.com/artifact/com.baomidou/mybatis-plus-boot-starter -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!-- Druid依赖 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.8</version>
</dependency>
如果是springboot3,则替换一下依赖
<!-- https://mvnrepository.com/artifact/com.baomidou/mybatis-plus-spring-boot3-starter -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
<version>3.5.6</version>
</dependency>
注意:导入mybatis-plus的依赖就不需要导入mybatis依赖了,它自己已经做了集成,目前还没有接入spring的官方孵化器。
4.编写配置
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/shop_db?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=false
username: root
password: root
druid:
initial-size: 20
min-idle: 20
max-active: 100
max-wait: 10000
time-between-eviction-runs-millis: 60000
min-evictable-idle-time-millis: 30000
validation-query: SELECT 1 FROM DUAL
test-while-idle: true
test-on-borrow: true
test-on-return: false
5、创建对应的entity、mapper
使用通用mapper
@Repository
public interface UserMapper extends BaseMapper<User> {
}
在对应的mapper上面继承基本的接口 BaseMapper,至此所有的CRUD操作已经编写完成了。
6、在主启动类上添加配置
@MapperScan("cn.hxzy.mapper")
7、编写测试代码
继承了BaseMapper,所有的方法全部来自父类,当然我们也可以扩展编写自己的方法。
提一下这个Wrapper,它是条件构造器,可以在里面添加很多查询条件。
二、配置yml
现在所有的sql是不可见的,我们希望看到sql的执行过程,所以配置日志,配置映射xml位置,配置别名
# mybatis-plus配置
mybatis-plus:
configuration:
map-underscore-to-camel-case: false
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #日志配置
type-aliases-package: cn.hxzy.entity
mapper-locations: classpath:/mapper/*Mapper.xml
配置xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.hxzy.mybatisplus.mapper.UserMapper">
</mapper>
三、CRUD操作
mapper接口的常用方法:
@Autowired
private UserMapper userMapper;
@Test
void getUser1() {
//查询单个对象
User user = userMapper.selectById(2L);
System.out.println(user);
}
@Test
void getUser2(){
//查询单个对象
QueryWrapper<User> queryWrapper=new QueryWrapper<>();
queryWrapper.eq("id",1L);
User user = userMapper.selectOne(queryWrapper);
System.out.println(user);
}
@Test
void getList(){
//条件构造器 where id=1 queryWrapper.eq("id",1);
//QueryWrapper<User> queryWrapper=new QueryWrapper<>();
//查询集合数据
List<User> userList = userMapper.selectList(null);
for (User user : userList) {
System.out.println(user);
}
}
@Test
void insert(){
//新增操作
int num = userMapper.insert(new User(6L, "张三", 22, "87747@qq.com"));
if(num>0){
System.out.println("新增数据成功");
}
}
@Test
void update1(){
//1、修改第1种
User user = new User(6L, "张三丰", 122, "87747@qq.com");
int num = userMapper.updateById(user);
if(num>0){
System.out.println("修改数据成功");
}
}
@Test
void update2(){
//2、修改第2种
User user = new User(6L, "张三丰", 122, "87747@qq.com");
UpdateWrapper<User> updateWrapper=new UpdateWrapper<>();
updateWrapper.eq("id",6L); //条件where语句
updateWrapper.set("name","张无忌"); //set设值
int num = userMapper.update(updateWrapper);
if(num>0){
System.out.println("修改数据成功");
}
}
@Test
void update3(){
//3、修改第3种
User user = new User(6L, "李四", 32, "87747@qq.com");
UpdateWrapper<User> updateWrapper=new UpdateWrapper<>();
updateWrapper.eq("id",6L); //条件where语句
int num = userMapper.update(user,updateWrapper);
if(num>0){
System.out.println("修改数据成功");
}
}
@Test
void delete1(){
//删除1
int num = userMapper.deleteById(6L);
if(num>0){
System.out.println("删除成功");
}
}
@Test
void delete2(){
//删除2
QueryWrapper<User> queryWrapper=new QueryWrapper<>();
queryWrapper.eq("id",5L);
int num = userMapper.delete(queryWrapper);
if(num>0){
System.out.println("删除成功");
}
}
@Test
void delete3(){
//删除3
User user = new User();
user.setId(6L);
int num = userMapper.deleteById(user);
if(num>0){
System.out.println("删除成功");
}
}
四、常用注解
@TableName 用来映射数据库的表名,如果表名与实体类名不一致,在实体类上添加
@TableName 用来映射数据库的表名,如果表名与实体类名不一致,在实体类上添加
@TableField 用来映射字段,用法同上
//表明:此字段不属于表的列
@TableField(exist=false)
@TableField(value="列的字段名")
@TableId 设置注解映射
@TableId(type = IdType.ASSIGN_ID)
private Long userId;
查看这个枚举类型IdType:
AUTO(0),
NONE(1),
INPUT(2),
ASSIGN_ID(3),
ASSIGN_UUID(4);
private final int key;
private IdType(int key) {
this.key = key;
}
public int getKey() {
return this.key;
}
主键生成策略:
值 | 描述 |
---|---|
AUTO | 数据库自增 |
NONE | MP 自己设置注解,采用雪花算法实现 实体类使用String,数据库使用bigint |
INPUT | 需要开发者手动赋值 【】住院号:062415 000001 000002 062415 99999999 |
ASSIGN_ID | MP 分配ID, 可以使用Long,Integer, String 花算法实现 |
ASSIGN_UUID | 分配UUID,主键类型必须是String |
分布式系统唯一ID生成策略之雪花算法
SnowFlake 算法,是 Twitter 开源的分布式 id 生成算法。其核心思想就是:使用一个 64 bit 的 long 型的数字作为全局唯一 id。在分布式系统中的应用十分广泛,且ID 引入了时间戳,基本上保持自增的。
在@TableField主键 的属性里设置 exit=false ,表示不是数据库字段,就不会映射了,一般用于DTO,VO等
select=false 表示就不去查询
五、使用fill完成字段自动填充
@TableField 的属性,表示自动填充,将对象存入数据库的时候,由mybatis-plus自动给某些字段赋值,create_time,update_time等
步骤:
1、数据库必须先添加字段,然后实体类加注解
@TableField(fill = FieldFill.INSERT)
private Date createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updateTime;
2、创建自动填充的处理器
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
//metaObject 元数据
this.setFieldValByName("createTime",new Date(),metaObject);
this.setFieldValByName("updateTime",new Date(),metaObject);
}
@Override
public void updateFill(MetaObject metaObject) {
this.setFieldValByName("updateTime",new Date(),metaObject);
}
}
3、测试
六、逻辑删除
1、在数据库上扩展列deleted
2、实体类上扩展属性
private Integer deleted;
3、配置文件上添加
mybatis-plus:
global-config:
db-config:
logic-delete-field: deleted # 全局逻辑删除的实体字段名(since 3.3.0,配置后可以忽略不配置步骤2)
logic-delete-value: 1 # 逻辑已删除值(默认为 1)
logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
注意:
logic-delete-value: 1 # 逻辑已删除值(默认为 1) logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
这两行配置可以省略,是默认值,可以自由定义删除状态的值
七、乐观锁插件
乐观锁和悲观锁是两种思想,用于解决并发场景下的数据竞争问题。
乐观锁:是一种基于冲突检测的方法,检测到冲突时操作就会失败。在操作数据时非常乐观,认为别人不会同时修改数据。因此乐观锁不会上锁,只是在执行更新的时候判断一下在此期间别人是否修改了数据:如果别人修改了数据则放弃操作,否则执行操作。
悲观锁:悲观锁在操作数据时比较悲观,认为别人会同时修改数据。因此操作数据时直接把数据锁住,直到操作完成后才会释放锁;上锁期间其他人不能修改数据。
解决事务之间的丢失更新
实现步骤:
1、数据库上扩展version的字段 ,设置默认值为1
2、实体类上添加version属性 ,添加@Version注解
3、配置乐观锁插件
package cn.hxzy.config;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MybatisplusConfig {
/**
* 新版
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor mp = new MybatisPlusInterceptor();
mp.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return mp;
}
}
4、测试乐观锁是否生效
@Test
public void test(){
User user = userMapper.selectById(5L);
user.setAge(169);
//模拟一个捷足先登的第三方
user.setVersion(user.getVersion()+1);
userMapper.updateById(user);
}
八、条件构造器
条件构造器方法:
QueryWrapper<T> wrapper=new QueryWrapper<T>();
1.eq:等于
wrapper.eq("id","1415862105323061249");
2.gt:大于 ge: 大于等于
wrapper.gt("age",24);
3.lt 小于 le:小于等于
4.ne:不等于
5.like: 模糊查询 likeLeft: 百分号在左边 likeRight: 百分号在右边
wrapper.like("name","郭");
6.排序
wrapper.orderByDesc("age");
7.map封装条件
Map<String,Object> maps=new HashMap<String,Object>();
maps.put("age",24);
maps.put("name","Billie");
===
wrapper.allEq(maps);
8.in
wrapper.in("id",list);
9.inSql
QueryWrapper<User> wrapper = new QueryWrapper<User>();
wrapper.inSql("id", "10");
wrapper.inSql(true, "id", "4");
User user = userMapper.selectOne(wrapper);
List<User> list = userMapper.selectList(wrapper);
list.forEach(System.out::print);
-
updateWrapper
UpdateWrapper<User> updateWrapper=new UpdateWrapper<>();
九、分页查询操作
1.配置
mybatisplus内置了分页插件,配置拦截器组件
package cn.hxzy.config;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
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 mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}
2.测试
@Test
public void testPage(){
QueryWrapper<User> wrapper = new QueryWrapper<User>();
wrapper.like("name","张");
//Page的构造方法,参数1代表页码,参数2代表每页显示多少条记录
Page<User> page=new Page<>(2,3);
userMapper.selectPage(page,wrapper);
List<User> records = page.getRecords(); //得到记录集合
long total = page.getTotal(); //获取总记录数
System.out.println("总记录数:"+total);
records.forEach(System.out::println);
}
十、代码生成器
让代码来写代码,让代码来生成一个项目结构。 -逆向工程
AutoGenerator 是 MyBatis-Plus 的代码生成器,通过 AutoGenerator 可以快速生成 Entity、Mapper、Mapper XML、Service、ServiceImpl、Controller 等各个模块的代码,极大的提升了开发效率。
1.导入MybatisPlus Generator依赖
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.3.1.tmp</version>
</dependency>
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity</artifactId>
<version>1.7</version>
</dependency>
<!--swagger2 核心依赖-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<!-- swagger-ui为项目提供api展示及测试的界面-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.25</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
2.生成器
package cn.hxzy;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.GlobalConfig;
import com.baomidou.mybatisplus.generator.config.PackageConfig;
import com.baomidou.mybatisplus.generator.config.StrategyConfig;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
public class MybatisPlus_Generator {
public static void main(String[] args) {
//创建generator对象
AutoGenerator autoGenerator = new AutoGenerator();
//1、配置数据源 DataSourceConfig
DataSourceConfig dataSourceConfig = new DataSourceConfig();
dataSourceConfig.setUrl("jdbc:mysql://localhost:3306/ticket?serverTimezone=GMT%2B8&useUnicode=true&useSSL=false&characterEncoding=utf8");
dataSourceConfig.setDriverName("com.mysql.cj.jdbc.Driver");
dataSourceConfig.setUsername("root");
dataSourceConfig.setPassword("root");
autoGenerator.setDataSource(dataSourceConfig);
//2、全局配置 GlobalConfig
GlobalConfig globalConfig = new GlobalConfig();
//项目生成的路径
globalConfig.setOutputDir(System.getProperty("user.dir") + "/src/main/java");
globalConfig.setAuthor("shujun.Meng"); //作者
globalConfig.setOpen(false); //项目创建完毕后,是否要打开资源目录
globalConfig.setFileOverride(false);//是否覆盖原来生成的代码
//UserService
globalConfig.setServiceName("%sService");//生成的service里面没有I的前缀
globalConfig.setSwagger2(true);//开启Swagger的配置
globalConfig.setDateType(DateType.ONLY_DATE);//关于日期的设置
autoGenerator.setGlobalConfig(globalConfig);
//3、包信息
PackageConfig packageConfig = new PackageConfig();
packageConfig.setParent("cn.hxzy.teacher");
//packageConfig.setModuleName("user");//设置模块名称 一会
packageConfig.setController("controller");
packageConfig.setService("service");
packageConfig.setServiceImpl("service.impl");
packageConfig.setMapper("mapper");
packageConfig.setEntity("entity");
//packageConfig.setXml("mapper.xml");
autoGenerator.setPackageInfo(packageConfig);
//4、配置策略
StrategyConfig strategyConfig = new StrategyConfig();
//去掉数据表的前缀
strategyConfig.setTablePrefix("sys_");
//去掉数据表字段的前缀
strategyConfig.setFieldPrefix("user_");
strategyConfig.setEntityLombokModel(true);//添加Lombok注解
strategyConfig.setNaming(NamingStrategy.underline_to_camel);// 表名生成策略
strategyConfig.setColumnNaming(NamingStrategy.underline_to_camel);//下划线转驼峰
strategyConfig.setInclude("sys_user"); //要生成的数据表
autoGenerator.setStrategy(strategyConfig);
//5、执行
autoGenerator.execute();
}
}
十一、通用Service
通用servcie接口
public interface UserService extends IService<User> {
}
实现类
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
}
查询
list();
list(queryWrapper);
getById(id);
删除
removeById(id);
remove(条件构造器);
新增
save(实体类);
saveOrUpdate(实体类);//实体类上如果有ID值,则是修改操作,如果ID为空,则是新增操作
saveBatch(集合);//批量新增
修改
updateById(实体类);//根据实体类的ID值进行修改
update(条件构造器);