1 mybatis-plus简介
- MyBatis-Plus是一个MyBatis的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生
- 在mybatis-plus中,我们只需要定义DAO接口,然后继承BaseMapper类即可,此前在DAO中定义的方法,以及映射文件,都不需要自己创建,所有操作都由Mybatis-plus自动完成
- mybatis-plus同时进行了一些默认设置,默认开启驼峰标识,默认不开启日志,如果需要获取插入的数据的主键的值,直接获取即可,该标识也已经开启
- 特性
- 无侵入:只做增强不做改变,引入它不会对现有工程产生影响
- 损耗小:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作
- 强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求
- 支持 Lambda 形式调用:通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错
- 支持主键自动生成:支持多达 4 种主键策略,可自由配置,完美解决主键问题
- 支持 ActiveRecord 模式:实体类只需继承 Model 类即可进行强大的 CRUD 操作
- 支持自定义全局通用操作:支持全局通用方法注入( Write once, use anywhere )
- 内置代码生成器:采用代码或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 层代码,支持模板引擎,更有超多自定义配置可以使用
- 内置分页插件:基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通 List 查询
- 分页插件支持多种数据库:支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer 等多种数据库
- 内置性能分析插件:可输出 Sql 语句以及其执行时间,建议开发测试时启用该功能,能快速揪出慢查询
- 内置全局拦截插件:提供全表 delete 、 update 操作智能分析阻断,也可自定义拦截规则,预防误操作
2 mybatis-plus环境搭建
- 导入pom依赖
<dependencies>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus</artifactId>
<version>3.3.1</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.21</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.19</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>5.2.3.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
- mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<setting name="logImpl" value="LOG4J"/>
</settings>
</configuration>
- log4j.properties
# 全局日志配置
log4j.rootLogger=INFO, stdout
# MyBatis 日志配置
log4j.logger.com.mashibing=truce
# 控制台输出
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
- db.properties
driverClassname=com.mysql.cj.jdbc.Driver
username=root
password=c50hst
url=jdbc:mysql://localhost:3306/demo?serverTimezone=UTC
- spring.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<context:property-placeholder location="classpath:db.properties"></context:property-placeholder>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${driverClassname}"></property>
<property name="url" value="${url}"></property>
<property name="username" value="${username}"></property>
<property name="password" value="${password}"></property>
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
<bean id="sqlSessionFactoryBean" class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="configLocation" value="classpath:mybatis-config.xml"></property>
<property name="typeAliasesPackage" value="com.mashibing.bean"></property>
</bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.mashibing.dao"></property>
</bean>
</beans>
- Emp.java
package com.mashibing.bean;
import com.baomidou.mybatisplus.annotation.TableName;
import java.util.Date;
@TableName("tbl_emp")
public class Emp {
private Integer empno;
private String eName;
private String job;
private Integer mgr;
private Date hiredate;
private Double sal;
private Double comm;
private Integer deptno;
public Emp() {
}
public Integer getEmpno() {
return empno;
}
public void setEmpno(Integer empno) {
this.empno = empno;
}
public String geteName() {
return eName;
}
public void seteName(String eName) {
this.eName = eName;
}
public String getJob() {
return job;
}
public void setJob(String job) {
this.job = job;
}
public Integer getMgr() {
return mgr;
}
public void setMgr(Integer mgr) {
this.mgr = mgr;
}
public Date getHiredate() {
return hiredate;
}
public void setHiredate(Date hiredate) {
this.hiredate = hiredate;
}
public Double getSal() {
return sal;
}
public void setSal(Double sal) {
this.sal = sal;
}
public Double getComm() {
return comm;
}
public void setComm(Double comm) {
this.comm = comm;
}
public Integer getDeptno() {
return deptno;
}
public void setDeptno(Integer deptno) {
this.deptno = deptno;
}
@Override
public String toString() {
return "Emp{" +
"empno=" + empno +
", ename='" + eName + '\'' +
", job='" + job + '\'' +
", mgr=" + mgr +
", hiredate=" + hiredate +
", sal=" + sal +
", comm=" + comm +
", deptno=" + deptno +
'}';
}
}
- 建立tbl_emp表
CREATE TABLE `tbl_emp` (
`EMPNO` int(4) NOT NULL AUTO_INCREMENT,
`E_NAME` varchar(10) DEFAULT NULL,
`JOB` varchar(9) DEFAULT NULL,
`MGR` int(4) DEFAULT NULL,
`HIREDATE` date DEFAULT NULL,
`SAL` double(7,2) DEFAULT NULL,
`COMM` double(7,2) DEFAULT NULL,
`DEPTNO` int(4) DEFAULT NULL,
PRIMARY KEY (`EMPNO`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
- EmpDao.java
package com.mashibing.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.mashibing.bean.Emp;
public interface EmpDao extends BaseMapper<Emp> {
}
3 mybatis自带的增删改查
- mybatis自带了一些增删改查方法,如果需要自己定义语句,和mybatis中方式一模一样
3.1 插入
- MyTest.java
import com.mashibing.bean.Emp;
import com.mashibing.dao.EmpDao;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.Date;
public class MyTest {
ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
private EmpDao empDao = context.getBean("empDao", EmpDao.class);
@Test
public void testInsert() {
Emp emp = new Emp();
emp.seteName("zhangsan");
emp.setJob("Teacher");
emp.setMgr(100);
emp.setSal(1000.0);
emp.setComm(500.0);
emp.setHiredate(new Date());
emp.setDeptno(10);
int insert = empDao.insert(emp);
System.out.println(insert);
}
}
- 上述代码运行通过之后,控制台会打印警告信息,提示没有@TableId的注解,原因就在于定义实体类的时候并没有声明其中的主键是哪个列,以及使用什么样的主键生成策略
public class Emp {
...
@TableId(value = "empno",type = IdType.AUTO)
private Integer empno;
...
}
- 插入时,mybatis-plus会根据传入的实体类中非空属性的个数来动态的调整sql语句插入的字段数量
Emp emp = new Emp();
emp.seteName("zhangsan");
emp.setJob("Teacher");
emp.setMgr(100);
int insert = empDao.insert(emp);
System.out.println(insert);
System.out.println(emp.getEmpno());
3.2 修改
- MyTest.java
Emp emp = new Emp();
emp.setEmpno(1);
emp.seteName("lisi");
emp.setJob("student");
emp.setMgr(100);
int update = empDao.updateById(emp);
System.out.println(update);
3.3 删除操作
- MyTest.java
int i = empDao.deleteById(1);
System.out.println(i);
int i1 = empDao.deleteBatchIds(Arrays.asList(2, 3, 4));
System.out.println(i1);
QueryWrapper queryWrapper = new QueryWrapper();
queryWrapper.in("empno", Arrays.asList(5, 6, 7));
int delete = empDao.delete(queryWrapper);
System.out.println(delete);
Map<String, Object> map = new HashMap<>();
map.put("empno", 9);
int i2 = empDao.deleteByMap(map);
System.out.println(i2);
3.4 查询操作
- MyTest.java
Emp emp = empDao.selectById(1);
System.out.println(emp);
QueryWrapper<Emp> queryWrapper = new QueryWrapper<Emp>();
queryWrapper.eq("empno", 2).eq("e_name", "zhangsan");
Emp emp1 = empDao.selectOne(queryWrapper);
System.out.println(emp1);
List<Emp> list = empDao.selectBatchIds(Arrays.asList(1, 2, 3));
for (Emp emp2 : list) {
System.out.println(emp2);
}
Map<String, Object> map = new HashMap<String, Object>();
map.put("e_name", "zhangsan");
map.put("sal", 1000.0);
List<Emp> emps = empDao.selectByMap(map);
for (Emp emp3 : emps) {
System.out.println(emp3);
}
Page<Emp> empPage = empDao.selectPage(new Page<Emp>(2, 5), null);
List<Emp> records = empPage.getRecords();
System.out.println(records);
QueryWrapper<Emp> queryWrapper1 = new QueryWrapper<Emp>();
queryWrapper1.eq("e_name", "zhangsan");
Integer integer = empDao.selectCount(queryWrapper1);
System.out.println(integer);
List<Emp> emps1 = empDao.selectList(null);
for (Emp emp2 : emps) {
System.out.println(emp2);
}
List<Map<String, Object>> maps = empDao.selectMaps(null);
System.out.println(maps);
4 Mybatis-plus的相关配置
- mybatis一般在mybatis-config.xml中添加标签,来设置全局的默认策略,在MP中也具备相同的功能,同时也可以在spring.xml文件中进行全局配置
- 具体参数含义在https://mp.baomidou.com/config/中说明
- spring.xml
<bean id="sqlSessionFactory" class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean">
<property name="configuration" ref="configuration"/>
<property name="globalConfig" ref="globalConfig"/>
......
</bean>
<bean id="configuration" class="com.baomidou.mybatisplus.core.MybatisConfiguration">
<property name="logImpl" value="org.apache.ibatis.logging.log4j.Log4jImpl"></property>
......
</bean>
<bean id="globalConfig" class="com.baomidou.mybatisplus.core.config.GlobalConfig">
<property name="dbConfig" ref="dbConfig"/>
<property name="banner" value="false"/>
<property name="plugins">
<array>
<bean class="com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor"></bean>
</array>
</property>
......
</bean>
<bean id="dbConfig" class="com.baomidou.mybatisplus.core.config.GlobalConfig.DbConfig">
<property name="tablePrefix" value="tbl_"></property>
<property name="idType" ref="idType"></property>
......
</bean>
<util:constant id="idType" static-field="com.baomidou.mybatisplus.annotation.IdType.AUTO"></util:constant>
5 条件构造器Wrapper
- 看官网学习即可,一般建议还是写sql语句即可
- UpdateWrapper与QueryWrapper的区别在于一个用于拼接更新的条件,一个用于拼接查询和删除的条件
6 代码生成器
- 功能与mybatis逆向工程相同,比mybatis的逆向工程好用
- mybatis与mybatis-plus逆向工程区别
- MyBatis-plus是根据java代码开生成代码的,而Mybatis是根据XML文件的配置来生成的
- MyBatis-plus能够生成实体类、Mapper接口、Mapper映射文件,Service层,Controller层,而Mybatis只能生成实体类,Mapper接口,Mapper映射文件
6.1 生成过程
- 添加pom依赖
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.3.1.tmp</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.16</version>
</dependency>
- 添加模板引擎依赖,MyBatis-Plus支持 Velocity(默认)、Freemarker、Beetl
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>2.2</version>
</dependency>
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.30</version>
</dependency>
<dependency>
<groupId>com.ibeetl</groupId>
<artifactId>beetl</artifactId>
<version>3.1.1.RELEASE</version>
</dependency>
- 每次对maven的pom依赖做修改,编译器版本都会改变,可以加入如下配置防止编译器版本频繁变化
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
- 编写生成类
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.NamingStrategy;
public class MyTest {
public static void main(String[] args) {
testGenerator();
}
public static void testGenerator() {
GlobalConfig globalConfig = new GlobalConfig();
globalConfig.setActiveRecord(true)
.setAuthor("lian")
.setOutputDir("/Users/wusihan/IdeaProjects/mybatis-plus-generator/src/main/java")
.setFileOverride(true)
.setIdType(IdType.AUTO)
.setServiceName("%sService")
.setBaseResultMap(true)
.setBaseColumnList(true);
DataSourceConfig dataSourceConfig = new DataSourceConfig();
dataSourceConfig.setDriverName("com.mysql.cj.jdbc.Driver")
.setUrl("jdbc:mysql://localhost:3306/demo?serverTimezone=UTC")
.setUsername("root").setPassword("c50hst");
StrategyConfig strategyConfig = new StrategyConfig();
strategyConfig.setCapitalMode(true)
.setNaming(NamingStrategy.underline_to_camel)
.setTablePrefix("tbl_")
.setInclude("tbl_emp");
PackageConfig packageConfig = new PackageConfig();
packageConfig.setParent("com.mashibing")
.setMapper("mapper")
.setService("service")
.setController("controller")
.setEntity("bean")
.setXml("mapper");
AutoGenerator autoGenerator = new AutoGenerator();
autoGenerator.setGlobalConfig(globalConfig).setDataSource(dataSourceConfig).setStrategy(strategyConfig)
.setPackageInfo(packageConfig);
autoGenerator.execute();
}
}
7 插件扩展
- 除了分页插件,其他插件都没什么用
7.1 分页插件
- 上面已经介绍
7.2 乐观锁插件
- 修改实体类添加version域,在其上使用@Version注解,并在表中添加version字段
- 添加插件配置
<bean class="com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor"></bean>
- 测试类
@Test
public void testOptimisticLocker(){
Emp emp = new Emp();
emp.setEmpno(1);
emp.seteName("zhang");
emp.setSal(25.0);
emp.setComm(35.0);
emp.setVersion(15);
empDao.updateById(emp);
}
7.3 SQL执行分析插件,避免出现全表更新和删除
- 添加插件配置
<bean class="com.baomidou.mybatisplus.extension.plugins.SqlExplainInterceptor">
<property name="sqlParserList">
<list>
<bean class="com.baomidou.mybatisplus.extension.parsers.BlockAttackSqlParser"></bean>
</list>
</property>
</bean>
- 测试类
@Test
public void testSqlExplain(){
int delete = empDao.delete(null);
System.out.println(delete);
}
7.4 非法sql检查插件,可以阻断没有where条件的语句
- 添加插件配置
<bean class="com.baomidou.mybatisplus.extension.plugins.IllegalSQLInterceptor">
</bean>
- 测试类
@Test
public void testSqlIllegal(){
QueryWrapper<Emp> queryWrapper = new QueryWrapper<>();
queryWrapper.or();
List<Emp> list = empDao.selectList(queryWrapper);
for (Emp emp : list) {
System.out.println(emp);
}
}
8 SQL注入器
- 可以将配置在xml中的语句使用注入的方式注入到全局中,就不需要再编写sql语句
- 没什么用,正常直接写在dao中就行了没必要这么麻烦
9 公共字段填充
- 可以不必自己写代码,就为实体类属性提供一个默认值,一般用于对表中时间戳字段的填充一个默认值,因为所有创建时间的方法都一致,防止业务程序中大量冗余代码,效果等同于在表上设置默认值为当前时间戳
9.1 使用流程
- 自定义一个MetaObjectHandler
package com.mashibing.fill;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
public class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
this.strictInsertFill(metaObject, "eName", String.class, "wusihan");
}
@Override
public void updateFill(MetaObject metaObject) {
this.strictUpdateFill(metaObject, "eName", String.class, "wusihan");
}
}
- 修改spring.xml配置文件
...
<bean id="globalConfig" class="com.baomidou.mybatisplus.core.config.GlobalConfig">
<property name="metaObjectHandler" ref="myMeta"></property>
</bean>
...
<bean id="sqlSessionFactoryBean" class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean">
<property name="globalConfig" ref="globalConfig"></property>
...
</bean>
...
- 为实体类中需要使用公共字段填充的属性添加注释
@TableField(fill= FieldFill.UPDATE)
private String eName;
- 测试类
@Test
public void testMeta(){
Emp emp = new Emp();
emp.setEmpno(123);
int insert = empDao.insert(new Emp());
System.out.println(insert);
}