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);
}