赞
踩
实体类的属性(对应表中的字段)都使用驼峰式命名。
例如Student表
中,有一个字段stu_name
。
则对应实体类中为private String stuName
,不能直接命名为stu_name
。
什么是Mybatis-plus?
MyBatis-Plus(简称 MP)是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。
特点:
MySQL
、MariaDB
、Oracle
、DB2、H2、HSQL、SQLite、Postgre、SQLServer 等多种数据库环境准备,mysql数据库准备一张表。为了简单演示,我准备了一个student表,只有id和name两个属性,其中随便插点数据即可。
创建一个springboot项目,导入mybatis-plus
、mysql
的启动器。
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <!--导入mysql数据库--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <!--导入mybatis-plus启动器--> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.4.1</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies>
配置配置文件:配置连接数据库的信息
spring:
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql:///test01?serverTimezone=Asia/Shanghai
username: root
password: root
编写实体类Student.class(略)
编写mapper,继承BaseMapper
public interface StudentMapper extends BaseMapper<Student> {
}
在启动类上添加@MapperScan
注解,扫描mapper包。
@SpringBootApplication
@MapperScan("com.sixu.mapper")
public class BaomidouMybatisPlusApplication {
public static void main(String[] args) {
SpringApplication.run(BaomidouMybatisPlusApplication.class, args);
}
}
接下来就可以编写测试类了,进行测试。
@SpringBootTest
class BaomidouMybatisPlusApplicationTests {
@Autowired
private StudentMapper studentMapper;
@Test
void test01() {
List<Student> list = studentMapper.selectList(null); //UserMapper 中的 selectList() 方法的参数为 MP 内置的条件封装器 Wrapper,所以不填写就是无任何条件
for (Student student : list) {
System.out.println(student);
}
}
}
结果演示:
这次入门,便能认识到Mybatis-plus的简便之处,甚至连简单的sql语句都省略了。
AutoGenerator 是 MyBatis-Plus 的代码生成器,通过 AutoGenerator 可以快速生成 Entity、Mapper、Mapper XML、Service、Controller 等各个模块的代码,极大的提升了开发效率。
顾名思义,就是自动生成那些简单结构的代码。
演示:
添加依赖:
注意:MyBatis-Plus 从 3.0.3 之后移除了代码生成器与模板引擎的默认依赖,需要手动添加相关依赖
模板引擎:MyBatis-Plus 支持 Velocity(默认)、Freemarker、Beetl,用户可以选择自己熟悉的模板引擎,如果都不满足您的要求,可以采用自定义模板引擎。
注意!如果您选择了非默认引擎,需要在 AutoGenerator 中 设置模板引擎。
AutoGenerator generator = new AutoGenerator(); // set freemarker engine generator.setTemplateEngine(new FreemarkerTemplateEngine()); // set beetl engine generator.setTemplateEngine(new BeetlTemplateEngine()); // set custom engine (reference class is your custom engine class) generator.setTemplateEngine(new CustomTemplateEngine()); // other config ...
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
<!--导入mybatis-plus启动器--> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.4.1</version> </dependency> <!--添加 代码生成器 依赖--> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-generator</artifactId> <version>3.4.1</version> </dependency> <!--添加 模板引擎 依赖--> <dependency> <groupId>org.apache.velocity</groupId> <artifactId>velocity-engine-core</artifactId> <version>2.2</version> </dependency>
编写自动生成代码类,在其中编写配置
public class MyCodeGenerator { public static void Generator() { String projectPath = System.getProperty("user.dir"); // 全局配置 GlobalConfig globalConfig = new GlobalConfig(); globalConfig.setOutputDir(projectPath + "/quickStart/src/main/java") .setAuthor("sixu") //设置作者名字 .setBaseResultMap(true) //SQL 映射文件 .setBaseColumnList(true) //SQL 片段 .setOpen(false); // 数据源配置 DataSourceConfig dataSourceConfig = new DataSourceConfig(); dataSourceConfig.setUrl("jdbc:mysql:///test01?serverTimezone=Asia/Shanghai") .setDriverName("com.mysql.jdbc.Driver") .setUsername("root") .setPassword("root"); //配置包路径 PackageConfig pc = new PackageConfig(); pc.setParent("com.sixu") //配置父包路径 .setModuleName("mybatisPlusAutoGenerator") //配置业务包路径 .setMapper("mapper") .setEntity("entity") .setService("service") .setController("controller"); // 自定义配置 InjectionConfig cfg = new InjectionConfig() { @Override public void initMap() { // to do nothing } }; //下面的模板引擎是 velocity,如果模板引擎是freemarker,则 String templatePath = "/templates/mapper.xml.ftl" String templatePath = "/templates/mapper.xml.vm"; // 自定义输出配置 List<FileOutConfig> focList = new ArrayList<>(); // 自定义配置会被优先输出 focList.add(new FileOutConfig(templatePath) { @Override public String outputFile(TableInfo tableInfo) { // 自定义输出文件名 , 如果你 Entity 设置了前后缀、此处注意 xml 的名称会跟着发生变化!! return projectPath + "/quickStart/src/main/resources/mapper/" + pc.getModuleName() + "/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML; } }); cfg.setFileOutConfigList(focList); // 配置模板 TemplateConfig templateConfig = new TemplateConfig(); templateConfig.setXml(null); //策略配置 StrategyConfig strategy = new StrategyConfig(); strategy.setNaming(NamingStrategy.underline_to_camel) //设置命名规则 underline_to_camel 底线变驼峰 .setColumnNaming(NamingStrategy.underline_to_camel) //设置设置列命名 underline_to_camel 底线变驼峰 //.setSuperEntityClass() //你自己的父类实体,没有就不用设置! //.setSuperControllerClass() //你自己的父类控制器,没有就不用设置! .setEntityLombokModel(true) //是否加入lombok .setInclude("student") //设置表名 .setSuperEntityColumns("id") //设置超级超级列 .setControllerMappingHyphenStyle(true) //设置controller映射联字符 .setTablePrefix(pc.getModuleName() + "_"); //表的前缀 // 代码生成器 AutoGenerator mpg = new AutoGenerator(); mpg.setGlobalConfig(globalConfig) .setDataSource(dataSourceConfig) .setPackageInfo(pc) .setCfg(cfg) .setTemplate(templateConfig) .setStrategy(strategy) .execute(); } public static void main(String[] args) { Generator(); // 开始生成 } }
开始生成
生成前:
生成后:
由此可见,这个代码自动生成极大的减轻了程序员的负担。
但同时也提醒我们,要不断学习,现在这个时代,不进步就是在退步。
MybatisPlus内置了mapper层的简单的CURD操作。
只需要mapper层的接口继承BaseMappe<T\>
,然后再启动类添加注解@MapperScan()
将mapper层扫描进去。
增
方法:
int insert(T entity); //entity代表一个实体类对象
案例:
/*增*/
public void addStudent(Student student){
studentMapper.insert(student);
}
controller层
@GetMapping("addStudent/{name}")
public String addStudent(String name){
studentService.addStudent(new Student("mapper层增加测试"));
return "增加成功";
}
测试:
删
方法:
// 根据 ID 删除
int deleteById(Serializable id);
// 根据 entity 条件,删除记录
int delete(@Param(Constants.WRAPPER) Wrapper<T> wrapper);
// 删除(根据ID 批量删除)
int deleteBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);
// 根据 columnMap 条件,删除记录
int deleteByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);
案例:
service层
/*删*/
public void delStudent(int id){
studentMapper.deleteById(id);
}
controller层
@GetMapping("deleteStu/{id}")
public String deleteStu(@PathVariable int id){
studentService.delStudent(id);
return "删除成功";
}
测试:
改
方法:
// 根据 whereEntity 条件,更新记录
int update(@Param(Constants.ENTITY) T entity, @Param(Constants.WRAPPER) Wrapper<T> updateWrapper);
// 根据 ID 修改
int updateById(@Param(Constants.ENTITY) T entity);
案例:
service层
/*改*/
public void updateStu(Student student){
studentMapper.updateById(student);
}
controller层
@GetMapping("updateStu/{id}/{name}")
public String updateStu(@PathVariable int id,@PathVariable String name){
studentService.updateStu(new Student(id,name));
return "修改id:"+id+" 的学生成功";
}
测试:
查
//单条记录查询 T selectById(Serializable id); // 根据 ID 查询 T selectOne(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper); // 根据 entity 条件,查询一条记录 //多条记录查询 List<T> selectBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList); // 查询(根据ID 批量查询) List<T> selectList(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper); // 根据 entity 条件,查询全部记录。为null时代表不设条件,查询全部记录 List<T> selectByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap); // 查询(根据 columnMap 条件) List<Map<String, Object>> selectMaps(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper); // 根据 Wrapper 条件,查询全部记录 List<Object> selectObjs(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);// 根据 Wrapper 条件,查询全部记录。注意: 只返回第一个字段的值 //多条记录分页查询 IPage<T> selectPage(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper); // 根据 entity 条件,查询全部记录(并翻页) IPage<Map<String, Object>> selectMapsPage(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper); // 根据 Wrapper 条件,查询全部记录(并翻页) // 根据 Wrapper 条件,查询总记录数 Integer selectCount(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
案例:
service层:
/*查*/
public List<Student> findAll(){
List<Student> students = studentMapper.selectList(null);
return students;
}
controller层:
@GetMapping("findStudent")
public String findStudent(){
return studentService.findAll().toString();
}
测试:
MybatisPlus 也内置了servic层的一些简单操作。
步骤:
自定义sevice接口,继承IService(T)
。
再自定义service的实现类,实现自定义接口service接口,同时继承ServiceImpl(M extends BaseMapper<T>,T)。
如上图:我在实现Student01Service
的同时又继承了ServiceImpl
,并且将StudentMapper
作为泛型传入,所以在controller可以同时使用mapper层和service层的内置方法。为了将servie层方法和mapper层方法区分开来,service层的方法都是以save
(增) 、remove
(删)、update
(改)、get
|list
|page
|count
(查) 开头的。
查询
查询单条:get
// 根据 ID 查询
T getById(Serializable id);
// 根据 Wrapper,查询一条记录。结果集,如果是多个会抛出异常,随机取一条加上限制条件 wrapper.last("LIMIT 1")
T getOne(Wrapper<T> queryWrapper);
// 根据 Wrapper,查询一条记录
T getOne(Wrapper<T> queryWrapper, boolean throwEx);
// 根据 Wrapper,查询一条记录
Map<String, Object> getMap(Wrapper<T> queryWrapper);
// 根据 Wrapper,查询一条记录
<V> V getObj(Wrapper<T> queryWrapper, Function<? super Object, V> mapper);
查询多条:list
List<T> list(); // 查询所有
List<T> list(Wrapper<T> queryWrapper); // 查询列表
Collection<T> listByIds(Collection<? extends Serializable> idList); // 查询(根据ID 批量查询)
Collection<T> listByMap(Map<String, Object> columnMap); // 查询(根据 columnMap 条件)
List<Map<String, Object>> listMaps(); // 查询所有列表
List<Map<String, Object>> listMaps(Wrapper<T> queryWrapper); // 查询列表
List<Object> listObjs(); // 查询全部记录
<V> List<V> listObjs(Function<? super Object, V> mapper); // 查询全部记录
List<Object> listObjs(Wrapper<T> queryWrapper); // 根据 Wrapper 条件,查询全部记录
<V> List<V> listObjs(Wrpper<T> queryWrapper, Function<? super Object, V> mapper); // 根据 Wrapper 条件,查询全部记录
分页查询:page
IPage<T> page(IPage<T> page); // 无条件分页查询,page 表示翻页对象
IPage<T> page(IPage<T> page, Wrapper<T> queryWrapper); // 条件分页查询
IPage<Map<String, Object>> pageMaps(IPage<T> page); // 无条件分页查询
IPage<Map<String, Object>> pageMaps(IPage<T> page, Wrapper<T> queryWrapper); // 条件分页查询
查询记录数:count
int count(); // 查询总记录数
int count(Wrapper<T> queryWrapper); // 根据 Wrapper 条件,查询总记录数
新增:save
// 插入一条记录(选择字段,策略插入)
boolean save(T entity);
// 插入(批量)
boolean saveBatch(Collection<T> entityList);
// 插入(批量)
boolean saveBatch(Collection<T> entityList, int batchSize);
删除:remove
// 根据 entity 条件,删除记录
boolean remove(Wrapper<T> queryWrapper);
// 根据 ID 删除
boolean removeById(Serializable id);
// 根据 columnMap 条件,删除记录
boolean removeByMap(Map<String, Object> columnMap);
// 删除(根据ID 批量删除)
boolean removeByIds(Collection<? extends Serializable> idList);
修改:update
// 根据 UpdateWrapper 条件,更新记录 需要设置sqlset
boolean update(Wrapper<T> updateWrapper);
// 根据 whereEntity 条件,更新记录
boolean update(T entity, Wrapper<T> updateWrapper);
// 根据 ID 选择修改
boolean updateById(T entity);
// 根据ID 批量更新
boolean updateBatchById(Collection<T> entityList);
// 根据ID 批量更新
boolean updateBatchById(Collection<T> entityList, int batchSize);
参考:https://blog.csdn.net/m0_46159545/article/details/107161814
在mybatisplus中,使用内置的mapper层或service层查询语句时,需要传入一个参数,这个参数就是条件。
例如,在使用mapper层内置方法 selectList()
方法时,如果传入参数为null则表示没有条件,查询全部。
如果需要给查询设置一些条件,例如上面例子student表,想要模糊查询name中带有 “sixu” 的学生,则需要传入条件构造器。
条件构造器体系
Wrapper
: 条件构造抽象类,最顶端父类AbstractWrapper
: 用于查询条件封装,生成 sql 的 where 条件。Lambda
语句,查询或删除。Lambda
语句,修改。其实QueryWrapper和UpdateWrapper的大多数方法都是继承自AbstractWrapper,两者在大部分条件下都是可以互相替换的。使用方法也很简单,只需要new一个条件对象,然后使用方法来设置条件即可,接下来介绍那些可以设置条件的方法。
说明:
- 以下出现的第一个入参
boolean condition
表示该条件是否加入最后生成的sql中- 以下代码块内的多个方法均为从上往下补全个别
boolean
类型的入参,默认为true
- 以下出现的泛型
Param
均为Wrapper
的子类实例(均具有AbstractWrapper
的所有方法)- 以下方法在入参中出现的
R
为泛型,在普通wrapper中是String
,在LambdaWrapper中是函数(例:Entity::getId
,Entity
为实体类,getId
为字段id
的getMethod)- 以下方法入参中的
R column
均表示数据库字段,当R
具体类型为String
时则为数据库字段名(字段名是数据库关键字的自己用转义符包裹!)!而不是实体类数据字段名!!!,另当R
具体类型为SFunction
时项目runtime不支持eclipse自家的编译器!!!- 以下举例均为使用普通wrapper,入参为
Map
和List
的均以json
形式表现!- 使用中如果入参的
Map
或者List
为空,则不会加入最后生成的sql中!!!- 有任何疑问就点开源码看,看不懂函数的,点击我学习新知识
下面简单介绍一下经常使用到的方法。
eq、ne、lt、gt、le、ge
eq:等于 =
eq("name", "老王"); // name ='sixu'
ne:不等于 <>
ne("name", "老王"); // name <> 'sixu'
lt:小于 <
lt("id",10); // id < 10
gt: 大于 >
gt("id",10); // id > 10
le: 小于等于 <=
le("id",10); // id <= 10
ge: 大于等于 >=
gt("id",10); // id >= 10
isNull、isNotNull
isNull:字段 IS NULL
isNull(R column)
isNull(boolean condition, R column)
isNull("name"); //name is null
isNotNull:字段 IS NOT NULL
isNotNull(R column)
isNotNull(boolean condition, R column)
isNotNull("name"); //name is not null
like、notLike、likeLeft、likeRight
like:用于模糊查询 Like ‘%值%’
like(R column, Object val)
like(boolean condition, R column, Object val)
like("name","si"); // name LIKE '%si%'
notLike: not Like ‘%值%’
notLike(R column, Object val)
notLike(boolean condition, R column, Object val)
notLike("name","si"); // name NOT LIKE '%si%'
likeLeft:Like ‘%值’
likeLeft(R column, Object val)
likeLeft(boolean condition, R column, Object val)
likeLeft("name","xu"); //Like '%xu', 表示以‘xu’结尾
likeRight:Like ‘值%’
likeRight(R column, Object val)
likeRight(boolean condition, R column, Object val)
likeRight("name","si"); //Like 'si%', 表示以'si'开头
between、notbetween
between:BETWEEN 值1 AND 值2
between(R column, Object val1, Object val2)
between(boolean condition, R column, Object val1, Object val2)
between("id",0,10); //BETWEEN 0 AND 10
notbetween:NOT BETWEEN 值1 AND 值2
notBetween(R column, Object val1, Object val2)
notBetween(boolean condition, R column, Object val1, Object val2)
notBetween("id",0,10); //NOT BETWEEN 0 AND 10
in、notIn、inSql、notInSql、exists、notExists
in:IN (v1,v2,…,vn)
in(R column, Collection<?> value)
in(boolean condition, R column, Collection<?> value)
in("id",{1,5,8}) // id in (1,5,8)
notIn:NOT IN (v1,v2,…,vn),可以传入数组形式的参数,也可以传入Object类型的多个参数。
notIn(R column, Collection<?> value)
notIn(boolean condition, R column, Collection<?> value)
notIn(R column, Object... values)
notIn(boolean condition, R column, Object... values)
notIn("age",{1,2,3}) //age not in (1,2,3)
notIn("age", 1, 2, 3) //age not in (1,2,3)
inSql:与in
的区别在于传入参数,in
的传入参数一般是数组或者集合(继承于Collection);而 insql
的传入参数是以字符串形式的(可以直接传入一个复杂的SQL语句)。
inSql(R column, String inValue)
inSql(boolean condition, R column, String inValue)
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)
notInSql:参数是字符串,sql语句
notInSql(R column, String inValue)
notInSql(boolean condition, R column, String inValue)
notInSql("age", "1,2,3,4,5,6") //age not in (1,2,3,4,5,6)
notInSql("id", "select id from table where id < 3") //id not in (select id from table where id < 3)
exists:拼接EXISTS语句
EXISTS(包括 NOT EXISTS )子句的返回值是一个BOOL值。如何其子句有结果,就相当于True。
例如:下面两个sql语句的效果相同。
假设有两张表,TableIn 和TableEx ,要查询TableIn 表中ANAME与TableEx 表中BNAME相同的信息。
select * from TableIn where exists(select BID from TableEx where BNAME=TableIn.ANAME)
select * from TableIn where ANAME in(select BNAME from TableEx)
exists(String existsSql)
exists(boolean condition, String existsSql)
exists("select id from table where age = 1") //exists (select id from table where age = 1)
notExists:拼接NOTEXISTS语句
notExists(String notExistsSql)
notExists(boolean condition, String notExistsSql)
notExists("select id from table where age = 1") //not exists (select id from table where age = 1)
or、and
or:拼接OR。
注意:主动调用
or
表示紧接着下一个方法不是用and
连接!(不调用or
则默认为使用and
连接)
or()
or(boolean condition)
eq("id",1).or().eq("name","老王") //id = 1 or name = '老王'
and:拼接and
and(Consumer<Param> consumer)
and(boolean condition, Consumer<Param> consumer)
and(i -> i.eq("name", "李白").ne("status", "活着")) //and (name = '李白' and status <> '活着')
groupBy
groupBy(R... columns)
groupBy(boolean condition, R... columns)
groupBy("id", "name") //group by id,name
orderBy、orderByAsc、orderByDesc
orderBy
orderBy(boolean condition, boolean isAsc, R... columns)
orderBy(true, true, "id", "name") //order by id ASC,name ASC
orderByAsc:默认升序
orderByAsc(R... columns)
orderByAsc(boolean condition, R... columns)
orderByAsc("id", "name") //order by id ASC,name ASC
orderByDesc:默认降序
继承自
AbstractWrapper
,自身的内部属性entity
也用于生成 where 条件。可以通过
new QueryWrapper().lambda()
方法获取LambdaQueryWrapper
。
select:
select(String... sqlSelect)
select(Predicate<TableFieldInfo> predicate)
select(Class<T> entityClass, Predicate<TableFieldInfo> predicate)
继承自
AbstractWrapper
,自身的内部属性entity
也用于生成 where 条件。
可以通过new UpdateWrapper().lambda()
方法获取LambdaUpdateWrapper
。
set
set(String column, Object val)
set(boolean condition, String column, Object val)
set("name", "思绪")
setSql
setSql(String sql)
setSql("name = '思绪'")
以快速入门环境为例,在该案例的基础上,进行改造,实现分页浏览;
添加配置信息(可以创建一个配置类,这里为了方便,就直接在启动类中进行配置)
@Bean
public PaginationInterceptor paginationInterceptor() {
PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
// 设置请求的页面大于最大页后操作, true调回到首页,false 继续请求 默认false
// paginationInterceptor.setOverflow(false);
// 设置最大单页限制数量,默认 500 条,-1 不受限制
//paginationInterceptor.setLimit(500);
// 开启 count 的 join 优化,只针对部分 left join
paginationInterceptor.setCountSqlParser(new JsqlParserCountOptimize(true));
return paginationInterceptor;
}
然后再mapper中定义一个方法
@Select("select * from student")
IPage<Student> selectPageVo(Page<Student> page);
service层
/*分页查询*/
@Override
public IPage<Student> selectPageVo(Page<Student> page) {
return studentMapper.selectPageVo(page);
}
controller层
@GetMapping("selectPageVo/{pageNum}")
public String selectPageVo(@PathVariable int pageNum){
IPage<Student> studentIPage=new Page<Student>(pageNum,3); //第一个参数表示当前第几页,第二个参数表示每页最大记录
studentIPage=studentService.selectPageVo((Page<Student>) studentIPage);
List<Student> lists = studentIPage.getRecords();
return lists.toString();
}
测试:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。