前言
项目开发一直使用MyBatis , 简单,方便,容易上手,调优比其他的ORM框架容易的多。最近一次偶然的搜索,发现了MyBatis Plus, 试用之后,真是太爽了。MyBatis Plus是攻城狮的福利,几乎不用编码就可以完成单表的CRUD操作。使用心得做个记录。
一、准备环境
IDE编辑器:IntelliJ IDEA 2018.2.4(Ultimate Edition)
数据库:MySQL 5.7
框架:MyBatis Plus 3.05 , Spring Boot 2.0.6
管理工具:Maven 3.3.9
JDK:jdk1.8或以上
1. IDEA设置
idea是java开发的利器,我个人的常用设置有这么几项:
1) 设置自动导入包
自动导入包2) 设置提示快捷键
idea默认的代码提示是ctrl + 空格,常和输入法冲突,可以改为 alt + /,特别是从Eclipse转过来的同学,alt + / 比较顺手。
设置代码提示快捷键 alt + /
3) 设置多Tab标签
idea默认代码区的Tab标签是单行显示,多文件时不方便。
代码区多Tab显示
4) 设置提示不区分大小写
idea默认是按首字母大小写匹配,进行代码提示, 例如输入FileReader,必须F是大写才有提示, 设置完成后 f 也可以有提示。
代码提示不区分大小写
5) 设置的包显示风格
设置包的扁平风格2. 安装其他软件
安装jdk1.8 , mysql 5.7 ,maven3以上版本
二、初识 MyBatis Plus
官网:MyBatis Plus
MyBatis Plus 简称MP, 是MyBatis的增强,不做改变,只做增强。简单而又强大。
MP是一只带着蓝色面罩的小鸟。
1. 功能特性
- 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
- 损耗小:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作
- 强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求
- 支持 Lambda 形式调用:通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错
- 支持多种数据库:支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer2005、SQLServer 等多种数据库
- 支持主键自动生成:支持多达 4 种主键策略(内含分布式唯一 ID 生成器 - Sequence),可自由配置,完美解决主键问题
- 支持 XML 热加载:Mapper 对应的 XML 支持热加载,对于简单的 CRUD 操作,甚至可以无 XML 启动
- 支持 ActiveRecord 模式:支持 ActiveRecord 形式调用,实体类只需继承 Model 类即可进行强大的 CRUD 操作
- 支持自定义全局通用操作:支持全局通用方法注入( Write once, use anywhere )
- 支持关键词自动转义:支持数据库关键词(order、key......)自动转义,还可自定义关键词
- 内置代码生成器:采用代码或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 层代码,支持模板引擎,更有超多自定义配置等您来使用
- 内置分页插件:基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通 List 查询
- 内置性能分析插件:可输出 Sql 语句以及其执行时间,建议开发测试时启用该功能,能快速揪出慢查询
- 内置全局拦截插件:提供全表 delete 、 update 操作智能分析阻断,也可自定义拦截规则,预防误操作
- 内置 Sql 注入剥离器:支持 Sql 注入剥离,有效预防 Sql 注入攻击
以上特性大多都是项目开发中必用的功能。
2. 开始上手
MP主页有示例,按照例子步骤就可以快速搭建MP项目。
-
准备表 student
主键是id字段, auto increment
student.png
-
创建Spring Boot项目
建议使用 Spring Initializr,依赖项选择MySQL
创建springboot项目
依赖MySQL
-
pom.xml
工程属性
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
parent依赖项
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.6.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
SpringBoot 依赖项
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
MyBatis Plus依赖项
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.0.5</version>
</dependency>
MySQL 依赖项
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
-
配置数据库信息
编辑resource/application.yml文件,使用默认的application.properties文件也是可以的,两种类型的文件作用一样,语法格式有区别。
spring:
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/demo?useUnicode=true&characterEncoding=UTF-8
username: test
password: 123456
-
创建entity类
创建Student类,属性名和列名相同
public class Student {
//指定主键为 自动增长(mysql的 auto increment)
@TableId(value = "id",type = IdType.AUTO)
private Integer id;
private String name;
private Integer age;
private String email;
private Integer status;
private Date createtime;
// set | get
- 创建Mapper接口
public interface StudentMapper extends BaseMapper<Student> {
//无需任何内容
}
-
测试insert
在test/java/ 目下创建测试类,使用@Test修饰测试方法
@SuppressWarnings("all")
@RunWith(SpringRunner.class)
@SpringBootTest
public class MPTest {
@Autowired
private StudentMapper studentMapper;
@Test
public void testInsertStudent(){
Student student = new Student();
student.setName("李名");
student.setAge(20);
student.setEmail("liming@163.com");
student.setStatus(1);
student.setCreatetime( new Date());
int rows = studentMapper.insert(student);
System.out.println("insert 结果:"+rows);
}
}
三、实体属性名和列名相同
上面“2 开始上手”,实体类属性名和表的列名是相同的,使用MP无需设置,就可以完成CRUD, 在这部分继续实行其他的单表操作。
1. 增加数据
同“2 开始上手”中的测试部分的代码,首先创建实体对象, 给属性赋值,调用studentMapper的insert(),参数是实体类对象, insert()返回值是数据库插入成功的行数。整数值。
//添加记录,并获取新记录的注解
@Test
public void testInsertStudent() {
Student student = new Student();
student.setName("周新");
student.setAge(20);
student.setEmail("liming@163.com");
student.setStatus(1);
student.setCreatetime(new Date());
int rows = studentMapper.insert(student);
// 主键是id,获取新添加记录的id,使用对象的getId()
int newId = student.getId();
System.out.println("insert 结果:" + rows + "|对象的id:"+newId);
}
输出:insert 结果:1|对象的id:8
, id是你插入数据主键和我的不同。
2.修改数据
//根据主键修改对象
@Test
public void testUpdateStudent(){
Student student = new Student();
student.setId(8);
student.setName("新的名字");
student.setAge(30);
//根据主键修改对象, 对象null的属性,不进行修改
int rows = studentMapper.updateById(student);
}
首先给要修改的属性赋值,null的属性,不会参与修改。update set 列名=值不会出现null的字段;条件部分是 where id= 8;
注意:MP判断是否修改字段是判断属性的null,最好实体类Student的属性都是引用类型, 包括Integer age , 这样不给age赋值,就不会更新age字段。如果实体类定义 int age 。
//根据主键修改对象
@Test
public void testUpdateStudent(){
Student student = new Student();
student.setId(8);
student.setName("新的名字");
//student.setAge(30);
//根据主键修改对象, 对象null的属性,不进行修改
int rows = studentMapper.updateById(student);
}
MP的执行sql: UPDATE student SET name=?, age=? WHERE id=?
修改结果是 age 是 0 , 因为Student属性 int age ,这样定义int类型默认初值是 0 。
updateById()是根据主键作为添加更新,还可以根据其他条件更新,例如update(实体对象, Wrapper), Wrapper的使用后面会说到。
3. 删除数据
BaseMapper中删除方法
deleteBatchIds(Collection); 参数是主键的集合,删除多条数据
delete(Wrapper); 根据Wrapper对象的条件,删除数据
deleteById(主键id);根据单一主键,删除数据
deleteByMap(Map<String,Object>); 使用Map作为条件删除数据
//删除数据
@Test
public void testDeleteStudent(){
// sql : DELETE FROM student WHERE id=?
int rows = studentMapper.deleteById(2);
System.out.println("deleteById结果:"+rows);
}
注:deleteById(), 参数是主键值, 删除条件是 where id = 2
@Test
public void testDeleteStudent2(){
Map<String,Object> condition = new HashMap<>();
condition.put("name","周新");
condition.put("age",20);
int rows = studentMapper.deleteByMap(condition);
System.out.println("deleteByMap 结果:"+rows);
}
注:创建Map, 添加条件数据。Map的key是字段名,value是字段的值。调用deleteByMap(); 传入Map对象。 返回值成功删除的行数。
@Test
public void testDeleteStudent3(){
//DELETE FROM student WHERE name = ? OR age > ?
QueryWrapper<Student> wrapper = new QueryWrapper<>();
wrapper.eq("name", "周新")
.or()
.gt("age", 20);
int rows = studentMapper.delete(wrapper);
System.out.println("delete(wrapper) 结果:"+rows);
}
注:Wrapper是抽象类,QueryWrapper是他的子类, 用来封装条件字段和字段值。 eq()表示等于=, or() 是字段之间用 or 连接, gt()是大于。这些只是Wrapper中的几个方法, 参数是字段名,不是属性名。
4. 查询数据
BaseMapper的多个查询方法
selectBatchIds(Collection); 查询集合中多个主键值数据
selectByMap(Map<String,Object>); 根据Map条件查询
selectList(Wrapper); 使用Wrapper对象作为查询条件
selectById(id); 根据主键值查询
selectPage(IPage, Wrapper); 根据Wrapper条件并进行分页
selectCount(Wrapper); 统一记录数量
selectOne(Wrapper); 查询结果是一个对象
使用selectById , selectOne查询数据, 其他查询方法后面有单独的章节,独立讲查询的各种使用方式。
@Test
public void testSelectStudent(){
// SELECT id,name,age,email,status,createtime FROM student WHERE id=?
Student student = studentMapper.selectById(8);
System.out.println("根据id查询结果:"+student);
}
@Test
public void testSelectStudent2(){
QueryWrapper<Student> condition = new QueryWrapper<>();
condition.eq("name","李名");
//SELECT id,name,age,email,status,createtime FROM student WHERE name = ?
Student student = studentMapper.selectOne(condition);
System.out.println("selectOne查询结果:"+student);
}
注:先创建Wrapper对象,添加查询条件, 调用selectOne()方法。 selectOne()的查询结果必须小于或等于一条记录,MP内部是调用的MyBatis的selectOne()方法,多于一个记录,系统会报错,错误提示如下:
org.apache.ibatis.exceptions.TooManyResultsException
网友评论