文章目录
第一部分 Mybatis-Plus 概念
1.1 Mybatis-Plus 介绍
可以先看下MyBatis笔记
Mybatis-Plus 介绍 MyBatis-Plus(简称 MP)是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简 化开发、提高 效率而生。
1.2 特性
- 无侵入 :只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
- 损耗小 :启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作
- 强大的 CRUD 操作 :内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求
- 支持 Lambda 形式调用 :通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错
- 支持主键自动生成 :支持多达 4 种主键策略(内含分布式唯一 ID 生成器 - Sequence),可自由配置,完美解决主键问题
- 支持 ActiveRecord 模式 :支持 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 操作智能分析阻断,也可自定义拦截规则,预防误操作
1.3 支持数据库
任何能使用
mybatis
进行 CRUD, 并且支持标准 SQL 的数据库,具体支持情况如下,如果不在下列表查看分页部分教程 PR 您的支持。
- mysql,oracle,db2,h2,hsql,sqlite,postgresql,sqlserver,Phoenix,Gauss ,clickhouse,Sybase,OceanBase,Firebird,cubrid,goldilocks,csiidb
- 达梦数据库,虚谷数据库,人大金仓数据库,南大通用(华库)数据库,南大通用数据库,神通数据库,瀚高数据库
1.4 框架结构
1.5 代码托管
Gitee (opens new window) | Github(opens new window)
- 贡献代码:代码地址 MyBatis-Plus (opens new window),欢迎提交 Issue 或者 Pull Requests
- 维护文档:文档地址 MyBatis-Plus-Doc (opens new window),欢迎参与翻译和修订
- 代码教程:移步至 Awesome-MyBatis-Plus (opens new window) 查看。
第二部分 快速开始
1.1 基础数据库环境
创建 db 名为 mp
CREATE TABLE user
(
id BIGINT(20) NOT NULL COMMENT '主键ID',
name VARCHAR(30) NULL DEFAULT NULL COMMENT '姓名',
age INT(11) NULL DEFAULT NULL COMMENT '年龄',
email VARCHAR(50) NULL DEFAULT NULL COMMENT '邮箱',
PRIMARY KEY (id)
);
INSERT INTO user (id, name, age, email) VALUES
(1, 'Jone', 18, 'test1@baomidou.com'),
(2, 'Jack', 20, 'test2@baomidou.com'),
(3, 'Tom', 28, 'test3@baomidou.com'),
(4, 'Sandy', 21, 'test4@baomidou.com'),
(5, 'Billie', 24, 'test5@baomidou.com');
对于 Mybatis 整合 MP 有常常有三种用法,分别是 Mybatis+MP、Spring+Mybatis+MP、Spring Boot+Mybatis+MP。
1.2 MyBatis 快速开始
代码结构
使用依赖传递先建立上层工程 mybatis-pluse 引入依赖,再建立子模块
父依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.galaxy</groupId>
<artifactId>mybatis-plus</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>
<modules>
<module>mybatis-demo</module>
</modules>
<dependencies>
<!-- mybatis-plus插件依赖 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus</artifactId>
<version>3.4.0</version>
</dependency>
<!--Mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<!--连接池-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.11</version>
</dependency>
<!--简化bean代码的工具包-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.4</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.6.4</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>11</source>
<target>11</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
子模块 sqlMapConfig.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>
<!--加载外部的properties文件-->
<properties resource="jdbc.properties"></properties>
<!--给实体类的全限定类名给别名-->
<typeAliases>
<!--给单独的实体起别名-->
<!-- <typeAlias type="com.lagou.pojo.User" alias="user"></typeAlias>-->
<!--批量起别名:该包下所有的类的本身的类名:别名还不区分大小写-->
<package name="com.galaxy.pojo"/>
</typeAliases>
<!--environments:运行环境-->
<environments default="development">
<environment id="development">
<!--当前事务交由JDBC进行管理-->
<transactionManager type="JDBC"></transactionManager>
<!--当前使用mybatis提供的连接池-->
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
<!--引入映射配置文件-->
<mappers>
<!-- <mapper resource="UserMapper.xml"></mapper> -->
<package name="com.galaxy.mapper"/>
</mappers>
</configuration>
数据库配置信息
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mp?useUnicode=true&characterEncoding=utf8
jdbc.username=root
jdbc.password=root
日志配置文件 log4j.properties
### direct log messages to stdout ###
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
### direct messages to file mylog.log ###
log4j.appender.file=org.apache.log4j.FileAppender
log4j.appender.file.File=c:/mylog.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
### set log levels - for more verbose logging change 'info' to 'debug' ###
log4j.rootLogger=debug, stdout
查询 mapper UserMapper.xml
注意位置和接口 UserMapper 同位置,因为是 package 扫描
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.galaxy.mapper.UserMapper">
<select id="findAll" parameterType="user" resultType="user">
select * from user
</select>
</mapper>
实体类 User
package com.galaxy.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author lane
* @date 2021年10月16日 下午4:45
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private Long id;
private String name;
private Integer age;
private String email;
}
UserMapper
package com.galaxy.mapper;
import com.galaxy.pojo.User;
import java.util.List;
/**
* @author lane
* @date 2021年10月16日 下午4:45
*/
public interface UserMapper {
List<User> findAll();
}
MPTest
package com.galaxy.test;
import com.galaxy.mapper.UserMapper;
import com.galaxy.pojo.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
/**
* @author lane
* @date 2021年10月16日 下午5:28
*/
public class MPTest {
@Test
public void testMysql() throws IOException {
InputStream inputStream = Resources.getResourceAsStream("sqlMapConfig.xml");
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = sessionFactory.openSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> users = mapper.findAll();
for (int i = 0; i < users.size(); i++) {
User user = users.get(i);
System.out.println(user);
}
}
}
测试结果
17:36:39,995 DEBUG findAll:137 - ==> Preparing: select * from user
17:36:40,042 DEBUG findAll:137 - ==> Parameters:
17:36:40,084 DEBUG findAll:137 - <== Total: 5
User(id=1, name=Jone, age=18, email=test1@baomidou.com)
User(id=2, name=Jack, age=20, email=test2@baomidou.com)
User(id=3, name=Tom, age=28, email=test3@baomidou.com)
User(id=4, name=Sandy, age=21, email=test4@baomidou.com)
User(id=5, name=Billie, age=24, email=test5@baomidou.com)
1.3 MyBatis 整合 MyBatis Plus
整合步骤
- UserMaper 继承 BaseMapper
- MybatisSqlSessionFactoryBuilder 替换 SqlSessionFactoryBuilder
- 如果用户表与类名不一致添加注解 @TableName(“user”)
具体操作
user
/**
* @author lane
* @date 2021年10月16日 下午4:45
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName("user")
public class User {
private Long id;
private String name;
private Integer age;
private String email;
}
UserMapper
/**
* @author lane
* @date 2021年10月16日 下午4:45
*/
public interface UserMapper extends BaseMapper<User> {
List<User> findAll();
}
test
@Test
public void testMysqlMp() throws IOException {
InputStream inputStream = Resources.getResourceAsStream("sqlMapConfig.xml");
SqlSessionFactory sessionFactory = new MybatisSqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = sessionFactory.openSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
// List<User> users = mapper.findAll();
List<User> users = mapper.selectList(null);
users.forEach(user -> {
System.out.println(user);
});
}
测试结果
18:23:44,369 DEBUG selectList:137 - ==> Preparing: SELECT id,name,age,email FROM user
18:23:44,421 DEBUG selectList:137 - ==> Parameters:
18:23:44,454 DEBUG selectList:137 - <== Total: 5
User(id=1, name=Jone, age=18, email=test1@baomidou.com)
User(id=2, name=Jack, age=20, email=test2@baomidou.com)
User(id=3, name=Tom, age=28, email=test3@baomidou.com)
User(id=4, name=Sandy, age=21, email=test4@baomidou.com)
User(id=5, name=Billie, age=24, email=test5@baomidou.com)
BaseMapper 方法
1.4 Spring 整合 MyBatis Plus
创建子模块 mybatis-plus-spring
引入了 Spring 框架,数据源、构建等工作就交给了 Spring 管理。
模块结构
依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>mybatis-plus</artifactId>
<groupId>com.galaxy</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>mybatis-plus-spring</artifactId>
<properties>
<spring.version>5.1.6.RELEASE</spring.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>11</source>
<target>11</target>
<encoding>utf-8</encoding>
</configuration>
</plugin>
</plugins>
</build>
</project>
applicationContext.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"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 引入properties文件-->
<context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
<!--数据源-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!--1. 将sqlSessionFactory对象的创建交给spring-->
<bean id="sqlSessionFactory" class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="configLocation" value="classpath:sqlMapConfig.xml"/>
</bean>
<!--2. mapper映射扫描-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.galaxy.mapper"/>
</bean>
</beans>
jdbc.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mp?useUnicode=true&characterEncoding=utf8
jdbc.username=root
jdbc.password=root
log4j.properties
### direct log messages to stdout ###
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
### direct messages to file mylog.log ###
log4j.appender.file=org.apache.log4j.FileAppender
log4j.appender.file.File=c:/mylog.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
### set log levels - for more verbose logging change 'info' to 'debug' ###
log4j.rootLogger=debug, stdout
sqlMapConfig.xml(可以去掉,但是注意 sql)
<?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>
<!--给实体类的全限定类名给别名-->
<typeAliases>
<!--给单独的实体起别名-->
<!-- <typeAlias type="com.lagou.pojo.User" alias="user"></typeAlias>-->
<!--批量起别名:该包下所有的类的本身的类名:别名还不区分大小写-->
<package name="com.galaxy.pojo"/>
</typeAliases>
</configuration>
UserMapper.xml (注意位置,可以去掉,如果只是单纯的 mp 够用的话)
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.galaxy.mapper.UserMapper">
<select id="findAll" parameterType="user" resultType="user">
select * from user
</select>
</mapper>
User
package com.galaxy.pojo;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author lane
* @date 2021年10月16日 下午4:45
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName("user")
public class User {
private Long id;
private String name;
private Integer age;
private String email;
}
UserMapper
package com.galaxy.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.galaxy.pojo.User;
import java.util.List;
/**
* @author lane
* @date 2021年10月16日 下午4:45
*/
public interface UserMapper extends BaseMapper<User> {
List<User> findAll();
}
测试用例
package com.galaxy.test;
import com.galaxy.mapper.UserMapper;
import com.galaxy.pojo.User;
import lombok.AllArgsConstructor;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.util.List;
/**
* @author lane
* @date 2021年10月16日 下午6:45
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class SpringMPTest {
@Autowired
private UserMapper userMapper;
@Test
public void springMPTest(){
List<User> users = userMapper.selectList(null);
users.forEach(user -> {
System.out.println(user);
});
}
@Test
public void springMPTest2(){
List<User> users = userMapper.findAll();
users.forEach(user -> {
System.out.println(user);
});
}
}
还记得 Spring 的 测试
package com.galaxy.test;
import com.galaxy.mapper.UserMapper;
import com.galaxy.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.List;
/**
* @author lane
* @date 2021年10月16日 下午7:05
*/
public class MainTest {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
UserMapper userMapper = applicationContext.getBean(UserMapper.class);
List<User> users = userMapper.selectList(null);
for (int i = 0; i < users.size(); i++) {
System.out.println(users.get(i));
}
}
}
测试结果
19:03:35,919 DEBUG selectList:137 - ==> Preparing: SELECT id,name,age,email FROM user
19:03:35,959 DEBUG selectList:137 - ==> Parameters:
19:03:35,985 DEBUG selectList:137 - <== Total: 5
19:03:35,986 DEBUG SqlSessionUtils:49 - Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@27f9e982]
User(id=1, name=Jone, age=18, email=test1@baomidou.com)
User(id=2, name=Jack, age=20, email=test2@baomidou.com)
User(id=3, name=Tom, age=28, email=test3@baomidou.com)
User(id=4, name=Sandy, age=21, email=test4@baomidou.com)
User(id=5, name=Billie, age=24, email=test5@baomidou.com)
1.5 Spring Boot 整合 MyBatis Plus
创建 spring boot 项目
依赖手动添加
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.5</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.galaxy</groupId>
<artifactId>mybatis-plus-springboot</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>mybatis-plus-springboot</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--简化代码的工具包-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!--mybatis-plus的springboot支持-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.1.1</version>
</dependency>
<!--mysql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
application.properties
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/mp?useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true&useSSL=false
spring.datasource.username=root
spring.datasource.password=root
# \u52A0\u8F7D\u5168\u5C40\u914D\u7F6E\u6587\u4EF6
#mybatis-plus.config-location=classpath:sqlMapConfig.xml
# \u52A0\u8F7D\u6620\u5C04\u914D\u7F6E\u6587\u4EF6
mybatis-plus.mapper-locations=classpath*:mapper/*.xml
# \u8D77\u522B\u540D
mybatis-plus.type-aliases-package=com.galaxy.pojo
log4j.properties
log4j.rootLogger=info,A1
log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=[%t] [%c]-[%p] %m%n
log4j.logger.com.galaxy.mapper=TRACE
UserMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.galaxy.mapper.UserMapper">
<select id="findById" resultType="user">
select * from user where id = #{id}
</select>
</mapper>
启动类
package com.galaxy;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@MapperScan("com.galaxy.mapper")
public class MybatisPlusSpringbootApplication {
public static void main(String[] args) {
SpringApplication.run(MybatisPlusSpringbootApplication.class, args);
}
}
user
/**
* @author lane
* @date 2021年10月16日 下午4:45
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName("user")
public class User {
private Long id;
private String name;
private Integer age;
private String email;
}
UserMapper
package com.galaxy.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.galaxy.pojo.User;
import java.util.List;
/**
* @author lane
* @date 2021年10月16日 下午4:45
*/
public interface UserMapper extends BaseMapper<User> {
// List<User> findAll();
User findById(int id);
}
测试类
package com.galaxy.mybatisplusspringboot;
import com.galaxy.mapper.UserMapper;
import com.galaxy.pojo.User;
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.List;
@RunWith(SpringRunner.class)
@SpringBootTest
class MybatisPlusSpringbootApplicationTests {
@Autowired
private UserMapper userMapper;
@Test
public void testSpringbootMP(){
List<User> users = userMapper.selectList(null);
users.forEach(user -> System.out.println(user));
System.out.println(userMapper.findById(1));
}
}
测试结果
User(id=1, name=Jone, age=18, email=test1@baomidou.com)
User(id=2, name=Jack, age=20, email=test2@baomidou.com)
User(id=3, name=Tom, age=28, email=test3@baomidou.com)
User(id=4, name=Sandy, age=21, email=test4@baomidou.com)
User(id=5, name=Billie, age=24, email=test5@baomidou.com)
User(id=1, name=Jone, age=18, email=test1@baomidou.com)
第三部分 通用 CRUD
通过继承 BaseMapper 就可以获取到各种各样的单表操作,接下来我们将 详细讲解这些操作。
项目是在 Spring Boot 整合 MyBatis Plus 的基础上进行测试 CRUD
1.1 插入操作
直接调用即可
package com.galaxy.mybatisplusspringboot;
import com.galaxy.mapper.UserMapper;
import com.galaxy.pojo.User;
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.List;
@RunWith(SpringRunner.class)
@SpringBootTest
class MybatisPlusSpringbootApplicationTests {
@Autowired
private UserMapper userMapper;
@Test
public void testInsert(){
User user = new User();
user.setAge(17);
user.setEmail("lane.d@outlook.com");
user.setName("lane");
int i = userMapper.insert(user);
System.out.println("插入行数为"+i);
//MP会在插入之后为我们添加ID
System.out.println("user id :"+user.getId());
}
}
测试结果
插入行数为1
user id :1449560388239454210
修改主键生成策略
先修改数据库表 ID 为自动增长
修改实体类用户 ID 设置为 auto,也可以选择其他类型
/**
* @author lane
* @date 2021年10月16日 下午4:45
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName("user")
public class User {
@TableId(type = IdType.AUTO)
private Long id;
private String name;
private Integer age;
private String email;
}
先删除刚才的数据,因为 ID 不正确,不然会报错
再次执行测试后结果,ID 自动增长为 6
1.2 @TableField 注解
在 MP 中通过 @TableField 注解可以指定字段的一些属性,常常解决的问题有 2 个:
1、对象中的属性名和字段名不一致的问题(非驼峰)
2、对象中的属性字段在表中不存在的问题
修改用户实体类为
/**
* @author lane
* @date 2021年10月16日 下午4:45
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName("user")
public class User {
@TableId(type = IdType.AUTO)
private Long id;
private String name;
@TableField(select = false) //查询的时候,不返回该字段的值
private Integer age;
@TableField(value = "email") //数据库字段名不一致,mail 的数据库字段为 email
private String mail;
@TableField(exist = false) //数据库字段不存在n
private String address;
}
测试下
@Test
public void testSpringbootMP(){
List<User> users = userMapper.selectList(null);
users.forEach(user ->
System.out.println(user));
System.out.println(userMapper.findById(1));
}
测试结果
1、不报错了
2、age 为 null mail 也可以查出来了,address 为 null
3、不影响自已定义的 SQL 查询结果,但是字段不一致还是不会有数据的如 mail 的数据库字段为 email
1.3 更新操作
在 MP 中,更新操作有 2 种,一种是根据 id 更新,另一种是根据条件更新。
根据 id 更新
/**
* 测试更新ById
* @author lane
* @date 2021/10/17 上午10:56
*/
@Test
public void testUpdateById(){
User user = new User();
//更新内容
user.setAge(21);
user.setName("lane2");
//ID
user.setId(6l);
int i = userMapper.updateById(user);
System.out.println("更新行数为"+i);
//MP会在插入之后为我们添加ID
System.out.println("user id :"+user.getId());
}
测试结果
根据条件更新
queryWrapper
/**
* 测试更新
* @author lane
* @date 2021/10/17 上午10:56
*/
@Test
public void testUpdateCondition(){
User user = new User();
//更新内容
user.setAge(23);
user.setName("lane3");
//更新条件
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("id", 6);
int i = userMapper.update(user, queryWrapper);
System.out.println("行数为"+i);
//MP会在插入之后为我们添加ID
System.out.println("user name :"+user.getName());
}
}
测试结果
UpdateWrapper
@Test
public void testUpdateCondition2(){
//更新的条件以及字段
UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
updateWrapper.eq("id", 6)
.set("name","lane4")
.set("age",24);
int i = userMapper.update(null, updateWrapper);
System.out.println("行数为"+i);
}
测试结果
1.4 删除操作
四种删除方法
int deleteById(Serializable id);
int deleteByMap(@Param("cm") Map<String, Object> columnMap);
int delete(@Param("ew") Wrapper<T> wrapper);
int deleteBatchIds(@Param("coll") Collection<? extends Serializable> idList);
测试用例
/**
*
* 测试四种删除方法
* @author lane
* @date 2021/10/17 下午3:11
*/
@Test
public void testDelete(){
//deleteById
int i = userMapper.deleteById(6l);
//deleteByMap
Map<String, Object> map = new HashMap<>();
//多个之间是and的关系
map.put("age",27);
map.put("name","lane27");
userMapper.deleteByMap(map);
//delete
User user = new User();
user.setName("lane28");
user.setAge(28);
QueryWrapper<User> queryWrapper = new QueryWrapper<>(user);
userMapper.delete(queryWrapper);
//deleteBatchIds
userMapper.deleteBatchIds(Arrays.asList(10,11));
}
测试结果
删除之前先添加几条数据
INSERT INTO user (id, name, age, email) VALUES
(1, 'Jone', 18, 'test1@baomidou.com'),
(2, 'Jack', 20, 'test2@baomidou.com'),
(3, 'Tom', 28, 'test3@baomidou.com'),
(4, 'Sandy', 21, 'test4@baomidou.com'),
(5, 'Billie', 24, 'test5@baomidou.com'),
(6, 'lane26', 26, 'lane26@outlook.com'),
(7, 'lane27', 27, 'lane27@outlook.com'),
(8, 'lane28', 28, 'lane28@outlook.com'),
(9, 'lane6', 29, 'lane29@outlook.com'),
(10, 'lane6', 29, 'lane29@outlook.com'),
(11, 'lane6', 29, 'lane29@outlook.com');
运行之后
1.5 查询操作
MP 提供了多种查询操作,包括根据 id 查询、批量查询、查询单条数据、查询列表、分页查询等操作。
测试方法
/**
* 测试查询
* @author lane
* @date 2021/10/17 下午3:40
*/
@Test
public void testSelect(){
System.out.println("selectById");
//selectById 根据 ID 查询
User user = userMapper.selectById(3);
System.out.println(user);
System.out.println("selectBatchIds");
//selectBatchIds
//查询(根据ID 批量查询) @param idList 主键ID列表(不能为 null 以及 empty)
List<User> users = userMapper.selectBatchIds(Arrays.asList(4, 5));
users.forEach(user1 -> System.out.println(user1));
System.out.println("selectByMap");
//selectByMap
Map<String, Object> map = new HashMap<>();
//多个之间是and的关系
map.put("age",27);
map.put("name","lane27");
List<User> usersMap = userMapper.selectByMap(map);
usersMap.forEach(user1 -> System.out.println(user1));
System.out.println("selectList");
//selectList
//根据 entity 条件,查询全部记录 * * @param queryWrapper 实体对象封装操作类(可以为 null)
QueryWrapper<User> queryWrapper = new QueryWrapper();
queryWrapper.gt("age", 27);//age 大于27
List<User> usersWrapper = userMapper.selectList(queryWrapper);
usersWrapper.forEach(user1 -> System.out.println(user1));
System.out.println("selectCount");
//selectCount
//根据 Wrapper 条件,查询总记录数 * * @param queryWrapper 实体对象封装操作类(可以为 null)
Integer count = userMapper.selectCount(queryWrapper);
System.out.println(count);
System.out.println("selectOne");
//selectOne
//根据 entity 条件,查询一条记录 * * @param queryWrapper 实体对象封装操作类(可以为 null)
QueryWrapper<User> queryWrapper2 = new QueryWrapper();
queryWrapper2.eq("name", "Jack");
User user1 = userMapper.selectOne(queryWrapper2);
System.out.println(user1);
}
测试结果
selectById
User(id=3, name=Tom, age=28, mail=test3@baomidou.com, address=null)
selectBatchIds
User(id=4, name=Sandy, age=21, mail=test4@baomidou.com, address=null)
User(id=5, name=Billie, age=24, mail=test5@baomidou.com, address=null)
selectByMap
User(id=7, name=lane27, age=27, mail=lane27@outlook.com, address=null)
selectList
User(id=3, name=Tom, age=28, mail=test3@baomidou.com, address=null)
User(id=8, name=lane28, age=28, mail=lane28@outlook.com, address=null)
User(id=9, name=lane6, age=29, mail=lane29@outlook.com, address=null)
User(id=10, name=lane6, age=29, mail=lane29@outlook.com, address=null)
User(id=11, name=lane6, age=29, mail=lane29@outlook.com, address=null)
selectCount
5
selectOne
User(id=2, name=Jack, age=20, mail=test2@baomidou.com, address=null)
1.6 分页查询
根据 selectPage 方法进行分页查询,需要先配置下分页插件的拦截器
方法定义
/**
* 根据 entity 条件,查询全部记录(并翻页)
*
* @param page 分页查询条件(可以为 RowBounds.DEFAULT)
* @param queryWrapper 实体对象封装操作类(可以为 null)
*/ IPage<T> selectPage(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
拦截器配置
spring boot 方式如下
/**
* @author lane
* @date 2021年10月17日 下午4:14
*/
@Configuration
public class MybatisPlusConfig {
/** 分页插件拦截器
* @author lane
* @date 2021/10/17 下午4:15
* @return com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor
*/
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
}
若仅仅对于 MyBatis 配置如下 sqlMapConfig.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>
<plugins>
<plugin interceptor="com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor"></plugin>
</plugins>
</configuration>
测试方法
/**
* 分页查询
* @author lane
* @date 2021/10/17 下午4:25
*/
@Test
public void testPage(){
QueryWrapper<User> queryWrapper = new QueryWrapper();
queryWrapper.gt("age", 18);
queryWrapper.orderByAsc("age");
//分页信息 当前页面,显示条数
Page<User> page = new Page<User>(1,2);
IPage<User> userIPage = userMapper.selectPage(page, queryWrapper);
System.out.println("当前页 "+userIPage.getCurrent());
System.out.println("总条数 "+userIPage.getTotal());
System.out.println("总页数 "+userIPage.getPages());
System.out.println("信息 "+userIPage.getRecords());
}
测试结果
[main] [com.galaxy.mapper.UserMapper.selectPage]-[DEBUG] ==> Preparing: SELECT COUNT(1) FROM user WHERE age > ?
[main] [com.galaxy.mapper.UserMapper.selectPage]-[DEBUG] ==> Parameters: 18(Integer)
[main] [com.galaxy.mapper.UserMapper.selectPage]-[DEBUG] ==> Preparing: SELECT id,name,age,email AS mail FROM user WHERE age > ? ORDER BY age ASC LIMIT ?,?
[main] [com.galaxy.mapper.UserMapper.selectPage]-[DEBUG] ==> Parameters: 18(Integer), 0(Long), 2(Long)
[main] [com.galaxy.mapper.UserMapper.selectPage]-[DEBUG] <== Total: 2
当前页 1
总条数 10
总页数 5
信息
[User(id=2, name=Jack, age=20, mail=test2@baomidou.com, address=null),
User(id=4, name=Sandy, age=21, mail=test4@baomidou.com, address=null)]
1.7 SQL 注入原理
MP 在启动后会将 BaseMapper 中的一系列的方法注册到 meppedStatements 中
在 MP 中,ISqlInjector 负责 SQL 的注入工作,它是一个接口,AbstractSqlInjector 是它的实现类,实现关 系如下:
在 AbstractSqlInjector 中,主要是由 inspectInject()方法进行注入的
最终调用抽象方法 injectMappedStatement 进行真正的注入:
public enum SqlMethod {
INSERT_ONE("insert", "插入一条数据(选择字段插入)", "<script>\nINSERT INTO %s %s VALUES %s\n</script>"),
DELETE_BY_ID("deleteById", "根据ID 删除一条数据", "<script>\nDELETE FROM %s WHERE %s=#{%s}\n</script>"),
DELETE_BY_MAP("deleteByMap", "根据columnMap 条件删除记录", "<script>\nDELETE FROM %s %s\n</script>"),
DELETE("delete", "根据 entity 条件删除记录", "<script>\nDELETE FROM %s %s\n</script>"),
DELETE_BATCH_BY_IDS("deleteBatchIds", "根据ID集合,批量删除数据", "<script>\nDELETE FROM %s WHERE %s IN (%s)\n</script>"),
LOGIC_DELETE_BY_ID("deleteById", "根据ID 逻辑删除一条数据", "<script>\nUPDATE %s %s WHERE %s=#{%s} %s\n</script>"),
LOGIC_DELETE_BY_MAP("deleteByMap", "根据columnMap 条件逻辑删除记录", "<script>\nUPDATE %s %s %s\n</script>"),
LOGIC_DELETE("delete", "根据 entity 条件逻辑删除记录", "<script>\nUPDATE %s %s %s\n</script>"),
LOGIC_DELETE_BATCH_BY_IDS("deleteBatchIds", "根据ID集合,批量逻辑删除数据", "<script>\nUPDATE %s %s WHERE %s IN (%s) %s\n</script>"),
UPDATE_BY_ID("updateById", "根据ID 选择修改数据", "<script>\nUPDATE %s %s WHERE %s=#{%s} %s\n</script>"),
UPDATE_ALL_COLUMN_BY_ID("updateAllColumnById", "根据ID 选择修改数据", "<script>\nUPDATE %s SET %s WHERE %s=#{%s} %s\n</script>"),
UPDATE("update", "根据 whereEntity 条件,更新记录", "<script>\nUPDATE %s %s %s\n</script>"),
LOGIC_UPDATE_BY_ID("updateById", "根据ID 修改数据", "<script>\nUPDATE %s %s WHERE %s=#{%s} %s\n</script>"),
SELECT_BY_ID("selectById", "根据ID 查询一条数据", "SELECT %s FROM %s WHERE %s=#{%s}"),
SELECT_BY_MAP("selectByMap", "根据columnMap 查询一条数据", "<script>\nSELECT %s FROM %s %s\n</script>"),
SELECT_BATCH_BY_IDS("selectBatchIds", "根据ID集合,批量查询数据", "<script>\nSELECT %s FROM %s WHERE %s IN (%s)\n</script>"),
SELECT_ONE("selectOne", "查询满足条件一条数据", "<script>\nSELECT %s FROM %s %s\n</script>"),
SELECT_COUNT("selectCount", "查询满足条件总记录数", "<script>\nSELECT COUNT(%s) FROM %s %s\n</script>"),
SELECT_LIST("selectList", "查询满足条件所有数据", "<script>\nSELECT %s FROM %s %s\n</script>"),
SELECT_PAGE("selectPage", "查询满足条件所有数据(并翻页)", "<script>\nSELECT %s FROM %s %s\n</script>"),
SELECT_MAPS("selectMaps", "查询满足条件所有数据", "<script>\nSELECT %s FROM %s %s\n</script>"),
SELECT_MAPS_PAGE("selectMapsPage", "查询满足条件所有数据(并翻页)", "<script>\nSELECT %s FROM %s %s\n</script>"),
SELECT_OBJS("selectObjs", "查询满足条件所有数据", "<script>\nSELECT %s FROM %s %s\n</script>"),
LOGIC_SELECT_BY_ID("selectById", "根据ID 查询一条数据", "SELECT %s FROM %s WHERE %s=#{%s} %s"),
LOGIC_SELECT_BATCH_BY_IDS("selectBatchIds", "根据ID集合,批量查询数据", "<script>\nSELECT %s FROM %s WHERE %s IN (%s) %s\n</script>");
}
第四部分 配置信息
1.1 基本配置
在 MP 中有大量的配置,其中有一部分是 Mybatis 原生的配置,另一部分是 MP 的配置,详情:
configLocation
MyBatis 配置文件 sqlMapConfig.xml 位置
Spring Boot:
mybatis-plus.config-location = classpath:sqlMapConfig.xml
Spring MVC:
<bean id="sqlSessionFactory" class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean">
<property name="configLocation" value="classpath:sqlMapConfig.xml"/>
</bean>
mapperLocations
MyBatis Mapper 所对应的 XML 文件位置如 resources/mapper/ UserMapper.xml
Spring Boot:
# Mapper 自定义SQL所对应的 XML文件位置
#classpath* 和classpath区别是包括所有的资源二classpath只包括当前项目
mybatis-plus.mapper-locations=classpath*:mapper/*.xml
Spring MVC:
<bean id="sqlSessionFactory" class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean">
<property name="mapperLocations" value="classpath*:mybatis/*.xml"/>
</bean>
Maven 多模块项目的扫描路径需以 classpath*: 开头 (即加载多个 jar 包下的 XML 文件)
测试下 UserMapper.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.galaxy.mapper.UserMapper">
<select id="findById" resultType="user">
select * from user where id = #{id}
</select>
</mapper>
typeAliasesPackage
MyBaits 别名包扫描路径,通过该属性可以给包中的类注册别名,注册后在 Mapper 对应的 XML 文件 中可以直接使用类名,而不用使用全限定的类名(即 XML 中调用的时候不用包含包名)。
Spring Boot:
#实体类起别名
mybatis-plus.type-aliases-package=com.galaxy.pojo
Spring MVC:
<bean id="sqlSessionFactory" class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean">
<property name="typeAliasesPackage" value="com.baomidou.mybatisplus.samples.quickstart.entity"/>
</bean>
1.2 进阶配置
mapUnderscoreToCamelCase
是否开启自动驼峰命名规则(camel case)映射,即从经典数据库列名 A_COLUMN(下划线命名) 到 经典 Java 属性名 aColumn(驼峰命名) 的类似映射。
column: user_name
property :userName
则无需使用 @TableField 注解指定数据库字段名,默认 MP 开启自动驼峰
注意:
此属性在 MyBatis 中原默认值为 false,在 MyBatis-Plus 中为 true
SpringBoot:
#关闭自动驼峰映射,该参数不能和mybatis-plus.config-location同时存在
mybatis-plus.configuration.map-underscore-to-camel-case=false
cacheEnabled
全局地开启或关闭配置文件中的所有映射器已经配置的任何缓存,默认为 true。
spring boot:
mybatis-plus.configuration.cache-enabled=false
idType
全局默认主键类型,设置后,即可省略实体对象中的 @TableId(type = IdType.AUTO)配置
SpringBoot:
mybatis-plus.global-config.db-config.id-type=auto
SpringMVC:
<!--这里使用MP提供的sqlSessionFactory,完成了Spring与MP的整合-->
<bean id="sqlSessionFactory" class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="globalConfig">
<bean class="com.baomidou.mybatisplus.core.config.GlobalConfig">
<property name="dbConfig"> <bean class="com.baomidou.mybatisplus.core.config.GlobalConfig$DbConfig">
<property name="idType" value="AUTO"/>
</bean>
</property>
</bean>
</property>
</bean>
tablePrefix
表名前缀,全局配置后可省略 @TableName()配置。
SpringBoot:
mybatis-plus.global-config.db-config.table-prefix=tb_
SpringMVC:
<bean id="sqlSessionFactory"
class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="globalConfig">
<bean class="com.baomidou.mybatisplus.core.config.GlobalConfig">
<property name="dbConfig">
<bean
class="com.baomidou.mybatisplus.core.config.GlobalConfig$DbConfig">
<property name="idType" value="AUTO"/>
<property name="tablePrefix" value="tb_"/>
</bean> </property>
</bean>
</property> </bean>
第五部分 条件构造器
1.1 allEq
allEq(Map<R, V> params)
allEq(Map<R, V> params, boolean null2IsNull)
allEq(boolean condition, Map<R, V> params, boolean null2IsNull)
测试用例
/**
* 测试allEq
* @author lane
* @date 2021/10/17 下午7:11
*/
@Test
public void testAllEq(){
Map<String,Object> map = new HashMap<>();
map.put("age",27);
map.put("name","lane27");
map.put("email",null);
QueryWrapper<User> queryWrapper = new QueryWrapper();
//条件查询
queryWrapper.allEq(map);//WHERE name = ? AND age = ? AND email IS NULL
//为false时候忽略条件中的null值
queryWrapper.allEq(map,false);//where name = ? AND age = ?
//condition为true时候才进行条件查询
// queryWrapper.allEq(true,map,true);
//SELECT id,name,age,email AS mail FROM user WHERE name = ? AND age = ? AND email IS NULL
List<User> users = userMapper.selectList(queryWrapper);
users.forEach(user -> System.out.println(user));
}
1.2 基本比较操作
eq
等于 =
ne
不等于 <>
gt
大于 >
ge
大于等于 >=
lt
小于 <
le
小于等于 <=
between
BETWEEN 值 1 AND 值 2
notBetween
NOT BETWEEN 值 1 AND 值 2
in 字段 IN (value.get(0), value.get(1), …)
notIn 字段 NOT IN (v0, v1, …)
测试代码
/**
* 测试基本条件
* @author lane
* @date 2021/10/17 下午7:11
*/
@Test
public void testCondition(){
QueryWrapper<User> queryWrapper = new QueryWrapper();
//条件查询
queryWrapper.gt("age",18 )
.eq("email", "lane29@outlook.com")
.in("name", "lane28","lane6")
.orderByAsc("id");
List<User> users = userMapper.selectList(queryWrapper);
users.forEach(user -> System.out.println(user));
}
测试结果
[main] [com.galaxy.mapper.UserMapper.selectList]-[DEBUG] ==> Preparing: SELECT id,name,age,email AS mail FROM user WHERE age > ? AND email = ? AND name IN (?,?) ORDER BY id ASC
[main] [com.galaxy.mapper.UserMapper.selectList]-[DEBUG] ==> Parameters: 18(Integer), lane29@outlook.com(String), lane28(String), lane6(String)
[main] [com.galaxy.mapper.UserMapper.selectList]-[DEBUG] <== Total: 3
User(id=9, name=lane6, age=29, mail=lane29@outlook.com, address=null)
User(id=10, name=lane6, age=29, mail=lane29@outlook.com, address=null)
User(id=11, name=lane6, age=29, mail=lane29@outlook.com, address=null)
1.3 模糊查询
like
LIKE ‘% 值 %’ 例: like(“name”, “王”)
—> name like ‘% 王 %’
notLike
NOT LIKE ‘% 值 %’ 例: notLike(“name”, “王”)
—> name not like ‘% 王 %’
likeLeft
LIKE ‘% 值’ 例: likeLeft(“name”, “王”)
—> name like ‘% 王’
likeRight
LIKE ‘值 %’ 例: likeRight(“name”, “王”)
—> name like ‘王 %’
1.4 排序
orderBy
排序:ORDER BY 字段, …
例: orderBy(true, true, “id”, “name”)
—> order by id ASC,name ASC
orderByAsc
排序:ORDER BY 字段, … ASC 例: orderByAsc(“id”, “name”)
—> order by id ASC,name ASC
orderByDesc
排序:ORDER BY 字段, … DESC 例: orderByDesc(“id”, “name”)
—> order by id DESC,name DESC
1.5 逻辑查询
or
queryWrapper.eq(“age”, 28).or().eq(“age”,“18”);
and
queryWrapper.eq(“name”, “Jack”).eq(“age”,“18”);
1.6 select
在 MP 查询中,默认查询所有的字段,如果有需要也可以通过 select 方法进行指定字段。
测试代码
/**
* 测试sort or select
* @author lane
* @date 2021/10/17 下午7:11
*/
@Test
public void testOr(){
QueryWrapper<User> queryWrapper = new QueryWrapper();
//条件查询or WHERE age = ? OR age = ?
queryWrapper.eq("age", 28).or().eq("age","18");
//or() desc select
// SELECT name,age FROM user WHERE age = ? OR age = ? ORDER BY age DESC
queryWrapper.eq("age", 28).or()
.eq("age","18")
.orderByDesc("age")
.select("name","age");
List<User> users = userMapper.selectList(queryWrapper);
users.forEach(user -> System.out.println(user));
}
第六部分 ActiveRecord
1.1 什么是 ActiveRecord
ActiveRecord 属于 ORM(对象关系映射)层,由 Rails 最早提出,遵循标准的 ORM 模型:表映射 到记录,记录映射到对象,字段映射到对象属性。配合遵循的命名和配置惯例,能够很大程度的快 速实现模型的操作,而且简洁易懂。
ActiveRecord 的主要思想是:
每一个数据库表对应创建一个类,类的每一个对象实例对应于数据库中表的一行记录;通常 表的每个字段在类中都有相应的 Field; ActiveRecord 同时负责把自己持久化,在 ActiveRecord 中封装了对数据库的访问,即 CURD;; ActiveRecord 是一种领域模型(Domain Model),封装了部分业务逻辑;
1.2 开启 AR 之旅
在 MP 中,开启 AR 非常简单,只需要将实体对象继承 Model 即可。Mapper 继承 BaseMapper 接口
代码实现
User
/**
* @author lane
* @date 2021年10月16日 下午4:45
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName("user")
public class User extends Model<User> {
@TableId(type = IdType.AUTO)
private Long id;
private String name;
// @TableField(select = false) //不想查出该值
private Integer age;
@TableField(value = "email") //数据库字段名不一致
private String mail;
@TableField(exist = false) //数据库字段不存在
private String address;
}
测试代码
package com.galaxy.mybatisplusspringboot;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.galaxy.pojo.User;
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.List;
/**
* @author lane
* @date 2021年10月18日 上午10:28
*/
@RunWith(SpringRunner.class)
@SpringBootTest
public class TestAR {
/*
在AR模式下,完成根据主键查询
*/
@Test
public void testARSelectById(){
User user = new User();
user.setId(12L);
User user1 = user.selectById();
System.out.println(user1);
}
/*
在AR模式下,完成添加操作
*/
@Test
public void testARInsert(){
User user = new User();
user.setName("lane18");
user.setAge(18);
user.setMail("lane18@outlook.com");
boolean insert = user.insert();
System.out.println(insert);
}
/*
在AR模式下,完成更新操作
*/
@Test
public void testARUpate(){
User user = new User();
User user1 = user.selectById(12L);
user.setId(12L);
user.setName("lane12");
boolean insert = user.updateById();
System.out.println(insert);
}
/*
在AR模式下,完成删除操作
*/
@Test
public void testARDelete(){
User user = new User();
//user.setId(16L);
boolean b = user.deleteById(16L);
System.out.println(b);
}
/*
在AR模式下,根据条件进行查询
*/
@Test
public void testARFindByWrapper(){
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.ge("age","20");
User user = new User();
List<User> users = user.selectList(queryWrapper);
for (User user1 : users) {
System.out.println(user1);
}
}
}
和原先的 mapper 操作几乎一致,注意必须继承接口 BaseMapper 才行,哪怕不使用
第七部分 插件
1.1 MyBatis 自定义插件
MyBatis 允许你在已映射语句执行过程中的某一点进行拦截调用。默认情况下,MyBatis 允许使用插件 来拦截的方法调用包括:
- Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
- ParameterHandler (getParameterObject, setParameters)
- ResultSetHandler (handleResultSets, handleOutputParameters)
- StatementHandler (prepare, parameterize, batch, update, query)
我们看到了可以拦截 Executor 接口的部分方法,比如 update,query,commit,rollback 等方法,还有 其他接口的一些方法等。
总体概括为:
- 拦截执行器的方法
- 拦截参数的处理
- 拦截结果集的处理
- 拦截 Sql 语法构建的处理
代码示例
拦截器插件
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.*;
import java.util.Properties;
@Intercepts({@Signature(
type= Executor.class,
method = "update",
args = {MappedStatement.class,Object.class})})
public class MyInterceptor implements Interceptor {
@Override public Object intercept(Invocation invocation) throws Throwable {
//拦截方法,具体业务逻辑编写的位置
return invocation.proceed(); }
@Override public Object plugin(Object target) {
//创建target对象的代理对象,目的是将当前拦截器加入到该对象中
return Plugin.wrap(target, this);
}
@Override public void setProperties(Properties properties) {
//属性设置
}
}
插件配置
注入到 Spring 容器:
/** * 自定义拦截器 */
@Bean
public MyInterceptor myInterceptor(){
return new MyInterceptor();
}
或者通过 xml 配置,sqlMapConfig.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> <plugins>
<plugin interceptor="com.galaxy.plugins.MyInterceptor"></plugin>
</plugins>
</configuration>
1.2 MP 执行分析插件
在 MP 中提供了对 SQL 执行的分析的插件
注意:该插件仅适用于开 发环境,不适用于生产环境。
性能分析拦截器,用于输出每条 SQL 语句及其执行时间,可以设置最大执行时间,超过时间会抛出异 常。
SpringBoot 配置:
@Configuration
public class MybatisPlusConfig {
/*
分页插件
*/
/* @Bean
public PaginationInterceptor paginationInterceptor(){
return new PaginationInterceptor();
}*/
/*
性能分析插件
*/
@Bean
public PerformanceInterceptor performanceInterceptor(){
PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor();
// 设置sql语句的最大执行时间
performanceInterceptor.setMaxTime(100);
// 设置sql是否格式化显示
performanceInterceptor.setFormat(true);
return performanceInterceptor;
}
/*
乐观锁插件
*/
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor(){
return new OptimisticLockerInterceptor();
}
/*
自定义的sql注入器
*/
@Bean
public MySqlInjector mySqlInjector(){
return new MySqlInjector();
}
}
1.3 乐观锁插件
当要更新一条记录的时候,希望这条记录没有被别人更新
乐观锁实现方式:
取出记录时,获取当前 version 更新时,带上这个 version 执行更新时, set version = newVersion where version = oldVersion
如果 version 不对,就更新失败
spring xml:
<bean class="com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor"/>
spring boot:
@Bean public OptimisticLockerInterceptor optimisticLockerInterceptor() {
return new OptimisticLockerInterceptor(); }
实体类
为表添加 version 字段,并且设置初始值为 1:
需要为实体字段添加 @Version 注解。
第八部分 Sql 注入器
1.1 扩充 BaseMapper 中的方法
MyBaseMapper
package com.galaxy.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.galaxy.pojo.User;
import java.util.List;
/**
* @author lane
* @date 2021年10月18日 下午12:01
*/
/*
通用mapper接口,以后创建其他mapper接口时,不再继承BaseMapper,而是继承MyBaseMapper
*/
public interface MyBaseMapper<T> extends BaseMapper<T> {
/*
查询所有用户
*/
public List<User> findAll();
}
FindAll
package com.galaxy.injector;
import com.baomidou.mybatisplus.core.injector.AbstractMethod;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlSource;
/**
* @author lane
* @date 2021年10月18日 下午12:02
*/
public class FindAll extends AbstractMethod {
@Override
public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
String sql = "select * from " + tableInfo.getTableName();
SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql, modelClass);
return this.addSelectMappedStatement(mapperClass, "findAll", sqlSource, modelClass, tableInfo);
}
}
MySqlInjector
package com.galaxy.injector;
import com.baomidou.mybatisplus.core.injector.AbstractMethod;
import com.baomidou.mybatisplus.core.injector.DefaultSqlInjector;
import java.util.List;
/**
* @author lane
* @date 2021年10月18日 下午12:03
*/
/*
自定义sql注入器
*/
public class MySqlInjector extends DefaultSqlInjector {
@Override
public List<AbstractMethod> getMethodList() {
List<AbstractMethod> methodList = super.getMethodList();
// 扩充自定义方法
methodList.add(new FindAll());
return methodList;
}
}
MybatisPlusConfig
package com.galaxy.config;
import com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import com.baomidou.mybatisplus.extension.plugins.PerformanceInterceptor;
import com.galaxy.injector.MySqlInjector;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author lane
* @date 2021年10月17日 下午4:14
*/
@Configuration
public class MybatisPlusConfig {
/** 分页插件拦截器
* @author lane
* @date 2021/10/17 下午4:15
* @return com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor
*/
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
/*
性能分析插件
*/
/* @Bean
public PerformanceInterceptor performanceInterceptor(){
PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor();
// 设置sql语句的最大执行时间
performanceInterceptor.setMaxTime(100);
// 设置sql是否格式化显示
performanceInterceptor.setFormat(true);
return performanceInterceptor;
}*/
/*
乐观锁插件
*/
/* @Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor(){
return new OptimisticLockerInterceptor();
}*/
/*
自定义的sql注入器
*/
@Bean
public MySqlInjector mySqlInjector(){
return new MySqlInjector();
}
}
第九部分 自动填充功能
有些时候我们可能会有这样的需求,插入或者更新数据时,希望有些字段可以自动填充数据,比如密 码、version 等。在 MP 中提供了这样的功能,可以实现自动填充。
1.1 添加 @TableField 注解
@TableField(fill = FieldFill.INSERT)
//插入数据时进行填充
private String version;
FieldFill 提供了多种模式选择:
public enum FieldFill {
/** * 默认不处理 */ DEFAULT, /** * 插入时填充字段 */ INSERT,
/** * 更新时填充字段 */ UPDATE, /** * 插入和更新时填充字段 */ INSERT_UPDATE
}
1.2 编写 MyMetaObjectHandler
package com.galaxy.handler;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
/**
* @author lane
* @date 2021年10月18日 下午12:17
*/
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
Object version = getFieldValByName("version", metaObject);
if(null == version){
// 该属性为空,可以进行填充
setFieldValByName("version",1,metaObject);
}
}
@Override
public void updateFill(MetaObject metaObject) {
}
}
第十部分 逻辑删除
1.1 逻辑删除介绍
逻辑删除就是将数据标记为删 除,而并非真正的物理删除(非 DELETE 操作),查询时需要携带状态条件,确保被标记的数据不被查询 到。这样做的目的就是避免数据被真正的删除。
1.2 逻辑删除实现
1、修改表结构
为 user 表增加 deleted 字段,用于表示数据是否被删除,1 代表删除,0 代表未删除。
ALTER TABLE `user` ADD COLUMN `deleted` int(1) NULL DEFAULT 0
COMMENT '1代表删除,0代表未删除' AFTER email
修改 User 实体
增加 deleted 属性并且添加 @TableLogic 注解:
@TableLogic
private Integer deleted;
2、配置
application.properties:
# 逻辑已删除值(默认为 1)
mybatis-plus.global-config.db-config.logic-delete-value=1
# 逻辑未删除值(默认为 0)
mybatis-plus.global-config.db-config.logic-not-delete-value=0
3、测试
/**
* 测试逻辑删除
* @author lane
* @date 2021/10/18 下午12:34
*/
@Test
public void testDeleteById(){
// UPDATE user SET deleted=1 WHERE id=? AND deleted=0
this.userMapper.deleteById(2L);
}
/**
* 测试逻辑删除
* @author lane
* @date 2021/10/18 下午12:34
*/
@Test
public void testSelectById(){
// SELECT id,name,age,email AS mail,deleted FROM user WHERE id=? AND deleted=0
this.userMapper.selectById(2L);
}
第十一部分 代码生成器
AutoGenerator 是 MyBatis-Plus 的代码生成器,通过 AutoGenerator 可以快速生成 Entity、 Mapper、Mapper XML、Service、Controller 等各个模块的代码,极大的提升了开发效率。
1.1 创建工程
依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.5.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.galaxy</groupId>
<artifactId>mybatis-plus-geneator</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>mybatis-plus-geneator</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--mybatis-plus的springboot支持-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.1.1</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.4.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
<!--mysql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
自动生成代码
package com.galaxy.generator;
import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
/**
* mysql 代码生成器演示例子
* @author lane
* @date 2021年10月18日 下午12:46
*/
public class MysqlGenerator {
/**
* <p>
* 读取控制台内容
* </p>
*/
public static String scanner(String tip) {
Scanner scanner = new Scanner(System.in);
StringBuilder help = new StringBuilder();
help.append("请输入" + tip + ":");
System.out.println(help.toString());
if (scanner.hasNext()) {
String ipt = scanner.next();
if (StringUtils.isNotBlank(ipt)) {
return ipt;
}
}
throw new MybatisPlusException("请输入正确的" + tip + "!");
}
/**
* RUN THIS
*/
public static void main(String[] args) {
// 代码生成器
AutoGenerator mpg = new AutoGenerator();
// 全局配置
GlobalConfig gc = new GlobalConfig();
final String projectPath = System.getProperty("user.dir");
gc.setOutputDir(projectPath + "/src/main/java");
gc.setAuthor("zimu");
gc.setOpen(false);
mpg.setGlobalConfig(gc);
// 数据源配置
DataSourceConfig dsc = new DataSourceConfig();
dsc.setUrl("jdbc:mysql://127.0.0.1:3306/mp?useUnicode=true&useSSL=false&characterEncoding=utf8");
// dsc.setSchemaName("public");
dsc.setDriverName("com.mysql.jdbc.Driver");
dsc.setUsername("root");
dsc.setPassword("root");
mpg.setDataSource(dsc);
// 包配置
final PackageConfig pc = new PackageConfig();
pc.setModuleName(scanner("模块名"));
pc.setParent("com.galaxy.auto.generator");
mpg.setPackageInfo(pc);
// 自定义配置
InjectionConfig cfg = new InjectionConfig() {
@Override
public void initMap() {
// to do nothing
}
};
List<FileOutConfig> focList = new ArrayList<FileOutConfig>();
focList.add(new FileOutConfig("/templates/mapper.xml.ftl") {
@Override
public String outputFile(TableInfo tableInfo) {
// 自定义输入文件名称
return projectPath + "/src/main/resources/mapper/" + pc.getModuleName()
+ "/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
}
});
cfg.setFileOutConfigList(focList);
mpg.setCfg(cfg);
mpg.setTemplate(new TemplateConfig().setXml(null));
// 策略配置
StrategyConfig strategy = new StrategyConfig();
strategy.setNaming(NamingStrategy.underline_to_camel);
strategy.setColumnNaming(NamingStrategy.underline_to_camel);
// strategy.setSuperEntityClass("com.baomidou.mybatisplus.samples.generator.common.BaseEntity");
strategy.setEntityLombokModel(true);
// strategy.setSuperControllerClass("com.baomidou.mybatisplus.samples.generator.common.BaseController");
strategy.setInclude(scanner("表名"));
strategy.setSuperEntityColumns("id");
strategy.setControllerMappingHyphenStyle(true);
strategy.setTablePrefix(pc.getModuleName() + "_");
mpg.setStrategy(strategy);
// 选择 freemarker 引擎需要指定如下加,注意 pom 依赖必须有!
mpg.setTemplateEngine(new FreemarkerTemplateEngine());
mpg.execute();
}
}
测试结果
第十二部分 IDEA 快速开发插件
1.1 MybatisX
MybatisX 是一款基于 IDEA 的快速开发插件,为效率而生。
安装方法:打开 IDEA,进入 File -> Settings -> Plugins -> Browse Repositories,输入 并安装。
功能:
Java 与 XML 调回跳转
Mapper 方法自动生成 XML
1.2 MyBatisPlus
安装方式
preference plugins 搜索 MyBatisPlus
作用
generator code
live template
from java to xml or from xml to java
具体使用
参考 :https://github.com/kana112233/mybatis-plus-plugin/wiki
代码导航
生成代码
配置数据库信息 other config database
自动生成代码 other code generator
代码模板
在 Java 类中输入以 m 开头可以得到以下模板代码 madd
, mupdate
, mdelete
, mpage
在 xml 文件中输入 m 开头的可以得到以下模板代码 mselect、mupdate
、mdelete
、 minsert
总结
通过对 MyBatis-Plus 的学习,对 MyBatis、Spring、Spring Boot 的理解加深了很多很多,突然感觉自己懂了
MyBatis 原来就是对 JDBC 的封装 核心 SqlMapConfig.xml
Spring 就是对象交给 Spring 的 Bean 容器进行管理 核心 aplicationContext.xml
Spring Boot 就是方便你去集成各种框架而不担心版本问题 核心 application.properties
代码参考 https://github.com/LaneDu/lane-mybatis-plus-11.1
先学习的 MyBatis 笔记