文章目录
简介:
Mybatis-Plus将使用mybatis过程中那些常用且固定的简单CRUD套路进行进一步封装(BaseMapper,page等等)
并且由于service也就是调用mapper进行服务的,所以自然mp也将service进行了封装,只需要传参(实体类)继承配置就可以使用。
interface接口都是声明crud方法,class才是基于实例化base/VoMapper等实现crud方法
mp提供的BaseMapper接口包含了常用且固定的简单CRUD接口方法,还提供了对应接口方法的SQL语句。 只需要简单配置Vo传参,自定义Mapper继承,@Mapper/@Autowired注解代理装配bean后就可以调用接口方法进行单表操作。
可以搜Mybatis的mapper接口没有实现类为什么可以执行增删改查(springboot的@MapperScan)?
Mybatis的核心就是基于mapper的配置性注入实现mapper接口类从而直接操作mapper实现crud功能。
@MapperScan
作用:指定要变成实现类的接口所在的包,然后包下面的所有接口在编译之后都会生成相应的实现类。
配置扫描的是java接口不是xml文件,而maven默认不扫描xml文件,需要单独配置maven扫描xml文件。
@MapperScan注解
注意事项
自定义CRUD的SQL方法:Vo实体类变量封装映射的是select的结果集字段名,可以通过SQL的as给结果集字段起别名来匹配Vo的变量名。
若是基于VoMapper自带的固定CRUD方法则变量名需要和数据库字段名一一匹配,因为需要根据Vo变量名识别字段名进而实现CRUD功能并封装对应固定查询的结果集(因为是固定模板所以不会有特殊的起别名等,只能使变量名匹配映射数据库字段名)。
反观自定义的SQL语句,自带查询字段等信息无需基于变量名映射字段名,仅需要封装结果集信息。
@TableField
- 记住一件事(无论mybatis或者mp还是hibernate):实体类名和数据库表名,实体类变量名和列名都要一致相同。
- 注意:createTime(驼峰式命名)----create_time(数据库列命名)
MyBatis用到接口方法名等等时也要xml文件一致,绝对不会出错。 反之则可能出错。 - 基本上mybatis的xml文件的所有标识符属性的值都要和对应的接口类保持一致,甚至文件名也要相同,若未指定xml文件位置则还需要将xml文件和接口类放在同一目录下。
mp错误示范:
cause:com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Table
‘student.users1’ doesn’t exist(实体类名与表名未对应)
Cause:com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown
column ‘id1’ in ‘field list’(实体类变量名与列名未对应)
图示
配置文件
# 服务端口
#http://localhost:8001/eduservice/teacher/
server.port=8001
# 服务名
spring.application.name=service-edu
# 环境设置:dev、test、prod
spring.profiles.active=dev
# mysql数据库连接
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/education?useUnicode=true&characterEncoding=utf-8
#涉及汉字操作需要设置?useUnicode=true&characterEncoding=utf-8用来统一编码。
spring.datasource.username=root
spring.datasource.password=
#mybatis日志,可以查看使用的SQL语句
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
配置类
package com.example.mp.conf;
import com.baomidou.mybatisplus.core.injector.ISqlInjector;
import com.baomidou.mybatisplus.extension.injector.LogicSqlInjector;
import com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import com.baomidou.mybatisplus.extension.plugins.PerformanceInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
//声明为配置类,专门用于配置环境
@Configuration
//配置mapper扫描的映射文件
@MapperScan("com.example.mp.mapper")
public class MPConfig {
//配置乐观锁插件
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor(){
return new OptimisticLockerInterceptor();
}
//配置分页查询插件
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
//配置逻辑删除插件
@Bean
public ISqlInjector iSqlInjector(){
return new LogicSqlInjector();
}
/**
* SQL 执行性能分析插件(可以显示分页插件的SQL代码运行)
* 开发环境使用,线上不推荐。 maxTime 指的是 sql 最大执行时长
*
* 三种环境
* * dev:开发环境
* * test:测试环境
* * prod:生产环境
*/
@Bean
@Profile({"dev","test"})// 设置 dev test 环境开启
public PerformanceInterceptor performanceInterceptor() {
PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor();
performanceInterceptor.setMaxTime(500);//ms,超过此处设置的ms则sql不执行
performanceInterceptor.setFormat(true);
return performanceInterceptor;
}
}
lombok
在项目中使用Lombok可以减少很多重复代码的书写。比如说getter/setter/toString/(无参/有参)构造等方法的编写
@Data:生成getter/setter方法
@AllArgsConstructor:生成有参数构造方法
@NoArgsConstructor:生成无参数构造
实体类中的变量属性还要设置public set/get方法(可以用lombok插件的@Data)
若IDEA未下载lombok插件且使用了@Data注解则大量set/get爆红且@Data不报错。原理:编译时,lombok插件会对@Data注解的实体类属性实现get/set方法
@MapperScan注解
1、@Mapper注解:
作用:在接口类上添加了@Mapper,在编译之后会生成相应的接口实现类
添加位置:接口类上面
@Mapper
public interface UserDAO {
//代码
}
如果想要每个接口都要变成实现类,那么需要在每个接口类上加上@Mapper注解,比较麻烦,解决这个问题用@MapperScan
2、@MapperScan
作用:指定要变成实现类的接口所在的包,然后包下面的所有接口在编译之后都会生成相应的实现类
添加位置:是在Springboot启动类上面添加,或者配置类上面(SpringBoot扫描配置类)
查找
实体类(entity):
数据表名是通过实体类名进行绑定映射。
数据表字段是通过实体类变量名进行绑定映射。
mp提供的BaseMapper接口包含了常用且固定的简单CRUD,还提供了对应接口方法的SQL语句。
只需要简单配置继承传参就可以进行单表操作(并绑定数据库表)。
插入(mp主键生成策略)
MyBatis-Plus默认实现5种主键生成策略,分别是:
- AUTO,配合数据库设置自增主键,可以实现主键的自动增长,类型为number;
- INPUT,由用户输入;
- NONE,mp不设置主键,等同于INPUT;
- ID_WORKER/ID_WORKER_STR,只有当用户未输入时,采用雪花算法生成一个适用于分布式环境的全局唯一主键,类型可以是String和number;
- UUID,只有当用户未输入时,生成一个String类型的主键,但不保证全局唯一;
作者:文景大大 链接:https://www.jianshu.com/p/a59ea9bc8132 来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处
MyBatis-Plus(自带)默认的主键策略是: ID_WORKER/ID_WORKER_STR 全局唯一 ID(64位二进制=19位十进制)
snowflake(雪花)算法 其核心思想是: 使用41bit作为毫秒数,10bit作为机器的ID(5个bit是数据中心,5个bit的机器ID),
12bit作为毫秒内的流水号(意味着每个节点在每毫秒可以产生 4096 个 ID), 最后还有一个符号位,永远是0。
具体实现的代码可以参看https://github.com/twitter/snowflake。
雪花算法支持的TPS可以达到419万左右(2^22*1000)。
一共41+10+12+1=64位二进制
雪花算法在工程实现上有单机版本和分布式版本。单机版本如下,分布式版本可以参看美团leaf算法:https://github.com/Meituan-Dianping/Leaf
ID_WORKER/ID_WORKER_STR注意事项
AUTO使用方法
拓展
mp自带算法自动生成ID主键值后(AUTO除外),先将ID主键值赋给实体类对象的id,然后再给进行对应的数据库插入操作。
例如:
多表且1对1关系时,两表可用同一ID,这样就会用到插入之后的实体类对象的id值来进行对应表信息的ID插入了。
更新(修改)
错误示范:
自动填充赋值(createTime和updateTime)
实体类
实现插入时间和更新时间的自动填充
注解实现自动填充
也可以使用set不使用注解
注解方式
@TableField注解需要放在对应注入变量上方(规范化)
乐观锁(判断式更新)
mp乐观锁实现方式:
- 取出记录时,获取当前version(查)
- 更新时,带上这个version
- 执行更新时, set version = newVersion where version = oldVersion(判断)
- 如果version不对,就更新失败(改)
(先查后改)
乐观锁SQL语句
UPDATE user
SET money=#{money},version=#{version+1}
WHERE id=#{id} and version=#{version}
mp中乐观锁插件使用时:必须先查(得到oldVersion)才可以(比较version值)后改。
如以下SQL语句所示,需知oldVersion值
UPDATE
user
SET
name='gclgg',
pass='355985',
create_time='2022-01-25 09:44:35',
update_time='2022-01-25 19:57:49.908',
version=4
WHERE
id=1485790668226932737
AND version=3
批量ID查找
// 批量查询
@Test
public void findIds(){
List<User> users=usersMapper.selectBatchIds(Arrays.asList(1485790477566349314L,1485790668226932737L));
System.out.println(users);
}
条件查询
注意条件查询中HashMap的设置键为String,值为对应实体类类型
// 条件查询
@Test
public void findByMap(){
HashMap<String,Object>hp=new HashMap<>();
hp.put("name","gclgg");
hp.put("pass",123456);
List<User> users=usersMapper.selectByMap(hp);
System.out.println(users);
}
分页查询(基于Page)
配置类中配置分页插件
//配置分页查询插件
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
删除
物理删除
批量删除
条件删除
逻辑删除(黑名单等)
逻辑删除弊端:若把name属性设置为primary键那么逻辑删除后该用户名仍然不可使用。
配置为deleted=1为删除,deleted=0为未删除
mp其他时也会考虑逻辑删除变量deleted。
因为在application.properties文件中的配置在全局都适应。
性能分析插件(SQL分析)
例如:可以看到mp插件中乐观锁SQL语句
application配置全局文件
该全局配置文件是配置全局,所以针对全部操作生效。
全局配置文件只能用于配置项目启动时自动实例化的功能类参数来实现对应配置等等,配置外部插件需要使用配置类来实例化对应的插件类。
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/student?useUnicode=true&characterEncoding=utf-8
#url需要配置utf-8进行汉字编码
spring.datasource.username=root
spring.datasource.password=
#mybatis日志,可以查看使用的SQL语句
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
#逻辑删除
mybatis-plus.global-config.db-config.logic-delete-value=1
mybatis-plus.global-config.db-config.logic-not-delete-value=0
#环境设置:dev、test、prod
spring.profiles.active=dev
配置类(configuration)
package com.example.mp.conf;
import com.baomidou.mybatisplus.core.injector.ISqlInjector;
import com.baomidou.mybatisplus.extension.injector.LogicSqlInjector;
import com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import com.baomidou.mybatisplus.extension.plugins.PerformanceInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
//声明为配置类,专门引入配置
@Configuration
//配置mapper扫描的映射文件
@MapperScan("com.example.mp.mapper")
public class MPConfig {
//配置乐观锁插件
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor(){
return new OptimisticLockerInterceptor();
}
//配置分页查询插件
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
//配置逻辑删除插件
@Bean
public ISqlInjector iSqlInjector(){
return new LogicSqlInjector();
}
/**
* SQL 执行性能分析插件
* 开发环境使用,线上不推荐。 maxTime 指的是 sql 最大执行时长
*
* 三种环境
* * dev:开发环境
* * test:测试环境
* * prod:生产环境
*/
@Bean
@Profile({"dev","test"})// 设置 dev test 环境开启
public PerformanceInterceptor performanceInterceptor() {
PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor();
performanceInterceptor.setMaxTime(500);//ms,超过此处设置的ms则sql不执行
performanceInterceptor.setFormat(true);
return performanceInterceptor;
}
}
自动注入处理类(Handler)
package com.example.mp.handler;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
import java.util.Date;
@Component
public class myMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
this.setFieldValByName("createTime",new Date(), metaObject);
this.setFieldValByName("updateTime",new Date(), metaObject);
this.setFieldValByName("version",1,metaObject);
}
@Override
public void updateFill(MetaObject metaObject) {
this.setFieldValByName("updateTime",new Date(), metaObject);
}
}
mapper文件
package com.example.mp.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.mp.User;
import org.springframework.stereotype.Repository;
@Repository
public interface UsersMapper extends BaseMapper<User>{
}
实体类
package com.example.mp;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.Version;
import lombok.Data;
import java.util.Date;
@Data
public class User {
private Long id;
private String name;
private String pass;
//实体类:驼峰式命名createTime-对应-列名:create_time
@TableField(fill = FieldFill.INSERT)//插入时赋值
private Date createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)//插入,更新时赋值
private Date updateTime;
@Version//乐观锁:更新时判断再更新
@TableField(fill = FieldFill.INSERT)//插入时赋值
private Integer version;
@TableLogic
private Integer deleted;
}
SpringBoot启动类
package com.qlugcl.eduservice;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
//启动类,用于启动该项目的springboot框架从而运行项目
@SpringBootApplication
//用于配置,要用到的配置类路径。com.qlugcl.servicebase中的SwaggerConfig
@ComponentScan(basePackages = "com.qlugcl")//扫描该项目和maven引入工程的com.qlugcl包,否则该启动类只扫描该对应当前项目的包
public class EduServiceApplication {
public static void main(String[] args) {
SpringApplication.run(EduServiceApplication.class,args);
}
}
乐观锁SQL分析
先where判断version再set修改version
复杂条件查询(基于QueryWrapper的动态SQL)
//创建QueryWrapper对象进行复杂条件查询的SQL语句设置
QueryWrapper<User> wrapper = new QueryWrapper<>();
//使用wrapper进行查询
List<User> users = usersMapper.selectList(wrapper);
System.out.println(users);
ge—大于等于(>=)
eq—等于
ne—不等于
between—区间查询
like—模糊查询
orderByDesc—降序排序
last—拼接SQL语句
select—指定要查询的列
注意:
可以基于SQL进行多重复杂条件查询。
一个SQL拼接方法实现条件,模糊查询并分页显示(基于QueryWrapper,Page)
根据teacherQuery中属性是否为空可以通过拼接SQL。
实现对应的查询全部(全空),条件查询(部分非空值作为条件),模糊查询(对应模糊属性非空)等功能,最后还进行分页处理。
//4 条件查询带分页的方法
@PostMapping("pageTeacherCondition/{current}/{limit}")
public R pageTeacherCondition(@PathVariable long current,@PathVariable long limit,
@RequestBody(required = false) TeacherQuery teacherQuery) {
//创建page对象
Page<EduTeacher> pageTeacher = new Page<>(current,limit);
//构建条件
QueryWrapper<EduTeacher> wrapper = new QueryWrapper<>();
// 多条件组合查询
// mybatis学过 动态sql
String name = teacherQuery.getName();
Integer level = teacherQuery.getLevel();
String begin = teacherQuery.getBegin();
String end = teacherQuery.getEnd();
//判断条件值是否为空,如果不为空拼接条件
if(!StringUtils.isEmpty(name)) {
//构建条件
wrapper.like("name",name);
}
if(!StringUtils.isEmpty(level)) {
// 因为Object包含toString()实例方法,所以
wrapper.eq("level",level);
}
if(!StringUtils.isEmpty(begin)) {
wrapper.ge("gmt_create",begin);
}
if(!StringUtils.isEmpty(end)) {
wrapper.le("gmt_create",end);
}
//调用方法实现条件查询分页
teacherService.page(pageTeacher,wrapper);
long total = pageTeacher.getTotal();//总记录数
List<EduTeacher> records = pageTeacher.getRecords(); //数据list集合
return R.ok().data("total",total).data("rows",records);
}
代码
package com.example.mp;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.mp.mapper.UsersMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
//作用:用于标识声明一个springboot框架容器。
@SpringBootTest
class MpApplicationTests {
@Autowired
private UsersMapper usersMapper;
@Test
public void findAll() {
List<User> users=usersMapper.selectList(null);
System.out.println(users);
}
@Test
public void insert(){
User users=new User();
users.setName("gclgg");
users.setPass("123456");
// users.setCreateTime(new Date());
// users.setUpdateTime(new Date());
int result=usersMapper.insert(users);
System.out.println(result);
}
@Test
public void update(){
User user=new User();
user.setId(1485790668226932737L);
user.setPass("355985");
// user.setUpdateTime(new Date());
// 更新除ID以外修改过默认值(0,null)的属性
int result=usersMapper.updateById(user);
System.out.println(result);
}
// 测试乐观锁,必须先查后改才生效
@Test
public void testOpt(){
User user;
user=usersMapper.selectById(1485790668226932737L);
user.setPass("355985");
// user.setUpdateTime(new Date());
// 更新除ID以外修改过默认值(0,null)的属性
int result=usersMapper.updateById(user);
System.out.println(result);
}
// 批量查询
@Test
public void findIds(){
List<User> users=usersMapper.selectBatchIds(Arrays.asList(1485790477566349314L,1485790668226932737L));
System.out.println(users);
}
// 条件查询
@Test
public void findByMap(){
HashMap<String,Object>hp=new HashMap<>();
hp.put("name","gclgg");
hp.put("pass",123456);
List<User> users=usersMapper.selectByMap(hp);
System.out.println(users);
}
// 分页查询
@Test
public void page(){
//1 创建page对象
//传入两个参数: 当前页 和 每页显示记录数
Page<User> page = new Page<>(1,3);
//调用mp分页查询的方法
//调用mp分页查询过程中,底层封装
//把分页所有数据封装到page对象里面
usersMapper.selectPage(page,null);
//通过page对象获取分页数据
System.out.println("当前页"+page.getCurrent());//当前页
System.out.println("每页数据list集合"+page.getRecords());//每页数据list集合
System.out.println("每页显示记录数"+page.getSize());//每页显示记录数
System.out.println("总记录数"+page.getTotal()); //总记录数
System.out.println("总页数"+page.getPages()); //总页数
System.out.println("是否有下一页"+page.hasNext()); //下一页
System.out.println("是否有上一页"+page.hasPrevious()); //上一页
}
//删除操作 物理删除
@Test
public void testDeleteById(){
int result = usersMapper.deleteById(1485918452676915201L);
System.out.println(result);
}
//批量删除
@Test
public void testDeleteBatchIds() {
int result = usersMapper.deleteBatchIds(Arrays.asList(1,2));
System.out.println(result);
}
//条件删除
@Test
public void testDeleteByMap() {
HashMap<String, Object> map = new HashMap<>();
map.put("name", "gclgg");
map.put("pass", 123456);
int result = usersMapper.deleteByMap(map);
System.out.println(result);
}
//mp实现复杂查询操作
@Test
public void testSelectQuery() {
//创建QueryWrapper对象
QueryWrapper<User> wrapper = new QueryWrapper<>();
//指定要查询的列
// 通过QueryWrapper设置条件
wrapper.select("id","name");
//ge、gt、le、lt
//查询age>=30记录
//第一个参数字段名称,第二个参数设置值
wrapper.ge("pass",12345);
//eq、ne
// wrapper.eq("name","lilei");
// wrapper.ne("name","lilei");
//between
//查询密码长度区间 10000-10000000
// wrapper.between("pass",10000,1000000);
//like
// wrapper.like("name","gc");
//orderByDesc
// wrapper.orderByDesc("id");
//last
wrapper.last("AND pass='123456'");
List<User> users = usersMapper.selectList(wrapper);
System.out.println(users);
}
}
mybatis-plus代码生成器
此处为固定代码,只需要能改懂配置就可以。
原理:数据库读取+文本代码生成
- 基于mp的自动生成代码,直接配置传参,继承mp封装简单且固定的crud的mapper,service的代码。
- 最后我们只需要编写业务逻辑(controller和service.Impl)就行。
编写业务逻辑的时候需要使用service层代码的时候,可以直接进入mp自动化生成的ServiceImpl查看源码中封装好的crud方法然后进行调用传参。
若是需要使用未封装的service功能,则可以通过原生baseMapper编写新service方法实现对应功能。
也可以使用mybatis的方法实现需要的数据库操作方法。
package com.createcode;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.annotation.IdType;
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;
import org.junit.Test;
/**
* @author
* @since 2018/12/13
* 基于mp的自生成代码,直接配置继承好基于mp的service,mapper的代码。
*/
public class CodeGenerator {
@Test
public void run() {
// 1、创建代码生成器
AutoGenerator mpg = new AutoGenerator();
// 2、全局配置
GlobalConfig gc = new GlobalConfig();
String projectPath = System.getProperty("user.dir");
// projectPath="F:\\javaweb项目\\edu_parent\\service\\service_edu"
gc.setOutputDir("F:\\javaweb项目\\edu_parent\\service\\service_edu"+ "/src/main/java");
gc.setAuthor("testjava");
gc.setOpen(false); //生成后是否打开资源管理器(就是把父文件夹打开,全部摊开)
gc.setFileOverride(false); //重新生成时文件是否覆盖
// 否则变为IUserService
gc.setServiceName("%sService"); //去掉Service接口的首字母I
gc.setIdType(IdType.ID_WORKER_STR); //主键策略
gc.setDateType(DateType.ONLY_DATE);//定义生成的实体类中日期类型
gc.setSwagger2(true);//开启Swagger2模式
mpg.setGlobalConfig(gc);
// 3、数据源配置
DataSourceConfig dsc = new DataSourceConfig();
dsc.setUrl("jdbc:mysql://localhost:3306/education");
dsc.setDriverName("com.mysql.jdbc.Driver");
dsc.setUsername("root");
dsc.setPassword("");
dsc.setDbType(DbType.MYSQL);
mpg.setDataSource(dsc);
// 4、包配置
PackageConfig pc = new PackageConfig();
pc.setParent("com.qlugcl");
pc.setModuleName("eduservice"); //模块名
pc.setController("controller");
pc.setEntity("entity");
pc.setService("service");
pc.setMapper("mapper");
mpg.setPackageInfo(pc);
// 5、策略配置
StrategyConfig strategy = new StrategyConfig();
// 数据库表,根据数据库表创建mapper,controller,service的类名(EduTeacher%%)
strategy.setInclude("edu_teacher");
strategy.setNaming(NamingStrategy.underline_to_camel);//数据库表映射到实体的命名策略
strategy.setTablePrefix(pc.getModuleName() + "_"); //生成实体时去掉表前缀
strategy.setColumnNaming(NamingStrategy.underline_to_camel);//数据库表字段映射到实体的命名策略
strategy.setEntityLombokModel(true); // lombok 模型 @Accessors(chain = true) setter链式操作
strategy.setRestControllerStyle(true); //restful api风格控制器
strategy.setControllerMappingHyphenStyle(true); //url中驼峰转连字符
mpg.setStrategy(strategy);
// 6、执行
mpg.execute();
}
}
IDEA也可以基于数据库表,自动生成mapper层和service层代码
IDEA自动生成代码方法
MyBatis-Plus的自定义SQL操作(xml版)
基本上mybatis的xml文件的所有标识符属性的值都要和对应的接口类保持一致,甚至文件名也要相同,若未指定xml文件位置则还需要将xml文件和接口类放在同一目录下。
#springboot中使用mapper的项目在全局配置文件配置mapper xm文件位置
mybatis-plus.mapper-locations=classpath:com/qlugcl/eduservice/mapper/xml/*.xml
开发步骤
- mapper层定义接口方法,参数值,返回值类型等等。
- 根据mapper层的接口方法数据配置对应的xml映射文件。
- 在navicat中编写SQL语句测试可用后粘贴进xml映射文件。
- service层使用baseMapper调用编写的接口方法传参实现功能。
为什么可以使用baseMapper操作自己写的接口方法
Mybatis-Plus的自定义SQL操作(注解版)
下图对应的Mapper层和service层以及serviceImpl层的类声明以及注解(@Mapper,@Service)都是MP规范格式模板。
实现了MP制定好的简单单表CRUD方法声明(Service)和方法实现(ServiceImpl基于VoMapper),只需要传参VoMapper和Vo即可
interface接口都是声明crud方法,class才是基于实例化base/VoMapper等实现crud方法
model层(实体类命名与数据字段名要协调)
原理:Vo实体类变量封装映射的是select的结果集,可以通过as给结果集起别名来匹配Vo的变量名。
@TableField(select = false) //查询时,则不返回该字段的值
@TableField(value = "字段名") //通过tableField进行字段名和变量名不一致的映射
@TableField(exist = false) //声明该字段在数据库表中不存在,不参与数据库表的映射
@Data
public class Vo{
private Long 对应数据表 bigInt
private String 对应数据表 varchar
}
mapper层
自定义Vomapper继承baseMapper的作用主要是基于baseMapper简单单表crud的基础上,添加自定义crud方法。
mybatis中的#和$的区别
大多数情况下还是经常使用#,一般能用#的就别用$;但有些情况下必须使用$,传入表名或字段名的时候,例:MyBatis排序时使用order by 动态参数时需要注意,用$而不是#
#传入的参数在SQL中显示为字符串,$传入的参数在SqL中直接显示为传入的值.
@Param
首先明确这个注解是为SQL语句中参数赋值而服务的。
@Param的作用就是给参数命名,比如在mapper里面某方法A(int id),当添加注解后A(@Param("userId") int id),也就是说外部想要取出传入的id值,只需要取它的参数名userId就可以了。将参数值传如SQL语句中,通过#{userId}进行取值给SQL的参数赋值。
@Mapper
@DS("该类全部SQL方法调用的数据库")
//若整个项目仅有一个数据库则忽略该注解,若该注解加在方法上则是表示仅限该方法调用的数据库
public interface VoMapper extends BaseMapper<Vo> {
@Select("此处填写select的SQL语句并且表示填充的#{参数名}")
public List<Vo> queryVo(@Param("参数名") String 参数);
}
形参为对象
@Mapper
@DS("该类全部SQL方法调用的数据库")
//若整个项目仅有一个数据库则忽略该注解,若该注解加在方法上则是表示仅限该方法调用的数据库
public interface VoMapper extends BaseMapper<Vo> {
@Select("此处填写select的SQL语句并且表示填充的#{vo对象.变量名}")
public List<Vo> queryVo(@Param("vo对象") Vo vo);
}
service层
IService定义了简单单表的crud接口方法。
public interface VoService extends IService<Vo> {
public List<Vo> queryVo(String 参数);
}
(重点)serviceImpl层
注意:MP封装的ServiceImpl通过baseMapper实现了service层IService中的基础crud方法框架,只需要自定义传参VoMapper extends BaseMapper<Vo>就可以实现功能了,可以ctr+左击进入查看一下。
Iservice定义的crud接口方法已经在ServiceImpl中用basemapper实现了框架,只缺VoMapper和Vo参数。
VoServiceImpl继承ServiceImpl实现的Service接口方法后就不需要再次实现对应接口方法。
只需要实现自定义的crud方法并且可以借助继承的baseMapper实现对应功能。
@Service
public class VoServiceImpl extends ServiceImpl<VoMapper, Vo> implements VoService {
@Resource
VoMapper voMapper;
@Override
public List<Vo> queryVo(String 参数) {
//用自定义的VoMapper方法实现Service功能
return voMapper.queryVo(参数);
}
}
controller层
@RequestParam注解详细使用
- @RequestMapping是一个无方法的注解。@GetMapping和@PostMapping是组合注解,分别是@RequestMapping(method = RequestMethod.GET)和@RequestMapping(method = RequestMethod.POST)的缩写。
- 用POSTMapping和GetMapping代替RequestMapping,简化controller方法头注解。
- @RequestMapping(value = “/Spath”, produces = “application/json;charset=UTF-8”, method = RequestMethod.GET)== @GetMapping(value = “/Spath”, produces = “application/json;charset=UTF-8”)
默认:@RequestParam==@RequestParam(value="参数名",required=true) String 参数名
特殊:@RequestParam(value="URL参数名",required=false) String 参数名
required=false:当URL中没有对应参数的时候也不报错。
@RestController
@Slf4j
@RequestMapping("/Fpath")
public class VoController {
@Resource
VoService voService;//此处注入的VoServiceImpl
@RequestMapping(value = "/Spath", produces = "application/json;charset=UTF-8", method = RequestMethod.GET)
public List<Vo> queryVo(@RequestParam(value="URL参数名",required=false) String 参数名){
return voService.queryVo(参数);
}
}
- @RequestMapping(value = “/Spath”, produces = “application/json;charset=UTF-8”, method = RequestMethod.POST)== @PostMapping(value = “/Spath”, produces = “application/json;charset=UTF-8”)
HttpServletRequest详解
getParameter(String name) 根据name获取请求参数(常用)类Get方法
getParameterValues(String name) 根据name获取请求参数列表(常用)
@RestController
@Slf4j
@RequestMapping("/Fpath")
public class VoController {
@PostMapping("/Spath")
public ReturnMsg trigger(HttpServletRequest request, @RequestBody Vo vo) {
Object x = vo.getDateTimeFmt();
Object y = request.getParameter("S");//此处就是将URL(请求行)的S参数提取出来类似Get方法
}
}
注意:SpringMVC @RequestParam
SpringMvc @RequestParam 使用推荐使用包装类型
主要原因false,反之若是true试验一下
注意事项
mybatis部分截图介绍
注意xml映射文件名和接口名需要保持一致。
原理:基于bean.class:包名.类名来进行对应xml文件的查找匹配和加载,注入。(若是配置文件指定xml文件位置则无需强制和接口类在同一目录下)
maven默认加载机制不识别xml文件
org.apache.ibatis.binding.BindingException: Invalid bound statement (not found)