【Mybatis】关于Mybatis-Plus

1、相关概念

1.1、特性

  • ⽆侵⼊:只做增强不做改变,引⼊它不会对现有⼯程产⽣影响,如丝般顺滑
  • 损耗⼩:启动即会⾃动注⼊基本 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.2、架构

2、快速入门

2.1、安装

        MyBatis-Plus 3.0 版本基于 JDK8,提供了 lambda 形式的调⽤,所以安装集成 MP3.0 要求如下:

  • JDK 8+
  • Maven or Gradle

SpringBoot项目:

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.4.0</version>
</dependency>

Spring MVC项目:

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus</artifactId>
    <version>3.4.0</version>
</dependency>

2.2、创建数据库与表

创建表结构:

-- 创建测试表
DROP TABLE IF EXISTS tb_user;
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');

2.3、创建工程

<dependencies>
	<dependency>
		<groupid>com.baomidou</groupid>
		<artifactid>mybatis-plus</artifactid>
		<version>3.1.1</version>
	</dependency>
	<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>
	<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>1.8
					<target>1.8</target>
				</configuration>
			</plugin>
		</plugins>
	</build>

2.4、Mybatis + MP

即纯Mybatis与Mybatis-Plus整合

2.4.1、创建子Module

<?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>blnp-mybatis-plus</artifactid>
		<groupid>com.blnp.net.mp</groupid>
		<version>1.0-SNAPSHOT</version>
	</parent>

	<modelversion>4.0.0</modelversion>
	<artifactid>blnp-mybatis-plus-simple</artifactid>
</project>

log4j.properties:

log4j.rootLogger=DEBUG,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

2.4.2、Mybatis 实现查询User

第⼀步,编写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>
    <properties resource="jdbc.properties"></properties>
    <!--environments: 运⾏环境-->
    <environments default="development">
        <environment id="development">
            <!--当前的事务事务管理器是JDBC-->
            <transactionManager type="JDBC"></transactionManager>
            <!--数据源信息 POOLED:使⽤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="mapper/UserMapper.xml"></mapper>
    </mappers>
</configuration>

第⼆步,编写User实体对象:(这⾥使⽤lombok进⾏了进化bean操作)

@Data // getter setter @toString
@NoArgsConstructor
@AllArgsConstructor
public class User {
    private Long id;
    private String name;
    private Integer age;
    private String email;
}

第三步,编写UserMapper接⼝:

public interface UserMapper {
    List < User > findAll();
}

第四步,编写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.blnp.net.mapper.UserMapper">
    <!-- 查询所有 -->
    <select id="findAll" resultType="com.blnp.net.pojo.User">
        select * from user
    </select>
</mapper>

第五步,编写TestMybatis测试⽤例:

public class MPTest {

    @Test
    public void test1() throws IOException {
        InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
        SqlSessionFactory sqlSessionFactory = new
        SqlSessionFactoryBuilder().build(resourceAsStream);
        SqlSession sqlSession = sqlSessionFactory.openSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        List < User > all = mapper.findAll();
        for(User user: all) {
            System.out.println(user);
        }
    }
}

测试结果:

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)

注:如果实体类名称和表名称不⼀致,可以在实体类上添加注解@TableName("指定数据库表名")

2.4.3、Mybatis + MP 实现查询User

第⼀步,将UserMapper继承BaseMapper,将拥有了BaseMapper中的所有⽅法:

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.blnp.net.pojo.User;

public interface UserMapper extends BaseMapper<User> {

}

第⼆步,使⽤MP中的MybatisSqlSessionFactoryBuilder进程构建:

@Test
public void test2() throws IOException {
    InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
    //这⾥使⽤的是MP中的MybatisSqlSessionFactoryBuilder
    SqlSessionFactory sqlSessionFactory = new MybatisSqlSessionFactoryBuilder().build(resourceAsStream);
    SqlSession sqlSession = sqlSessionFactory.openSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    // 可以调⽤BaseMapper中定义的⽅法
    List < User > all = mapper.selectList(null);
    for(User user: all) {
        System.out.println(user);
    }
}
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)

注意:如果实体类名称和表名称不⼀致,可以在实体类上添加注解@TableName("指定数据库表名")

  • 由于使⽤了 MybatisSqlSessionFactoryBuilder进⾏了构建,继承的BaseMapper中的⽅法就载⼊到了SqlSession中,所以就可以直接使⽤相关的⽅法;

2.5、Mybatis + Spring + MP

引⼊了Spring框架,数据源、构建等⼯作就交给了Spring管理。

2.5.1、创建子Module

<?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>blnp-mybatis-plus</artifactId>
        <groupId>com.blnp.mp</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>blnp-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>
</project>

2.5.2、实现查询User

第⼀步,编写jdbc.properties

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/mp?serverTimezone=GMT%2B8&useSSL=false
jdbc.username=root
jdbc.password=root

第⼆步,编写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"/>
    <!--dataSource-->
    <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>
    <!--这⾥使⽤MP提供的sqlSessionFactory,完成spring与mp的整合-->
    <bean id="sqlSessionFactory" class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
    </bean>
    <!--扫描mapper接⼝,使⽤的依然是mybatis原⽣的扫描器-->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.blnp.mapper"/>
    </bean>
</beans>

第三步,编写User对象以及UserMapper接⼝:

@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
    private Long id;
    private String name;
    private Integer age;
    private String email;
}


public interface UserMapper extends BaseMapper < User > {
    List < User > findAll();
}

第四步,编写测试⽤例:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class TestSpringMP {
    @Autowired
    private UserMapper userMapper;
    @Test
    public void test2() throws IOException {
        List < User > users = this.userMapper.selectList(null);
        for(User user: users) {
            System.out.println(user);
        }
    }

2.6、Mybatis + SpringBoot + MP

2.6.1、导入依赖

<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>
	<dependency>
		<groupid>com.baomidou</groupid>
		<artifactid>mybatis-plus-boot-starter</artifactid>
		<version>3.1.1</version>
	</dependency>
	<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>

2.6.2、编写配置文件

log4j.properties:

log4j.rootLogger=DEBUG,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

编写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=tr
ue&useSSL=false
spring.datasource.username=root
spring.datasource.password=root

2.6.3、创建对象

编写pojo

@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
    private Long id;
    private String name;
    private Integer age;
    private String email;
}
}

编写mapper

public interface UserMapper extends BaseMapper < User > {}

编写启动类

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;

@MapperScan("com.blnp.mp.mapper") //设置mapper接⼝的扫描包
@SpringBootApplication
public class MyApplication {
    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }
}

2.6.4、编写测试用例

import com.blnp.mp.mapper.UserMapper;
import com.blnp.mp.pojo.User;
import org.junit.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
public class UserMapperTest {
    @Autowired
    private UserMapper userMapper;
    @Test
    public void testSelect() {
        List < User > userList = userMapper.selectList(null);
        for(User user: userList) {
            System.out.println(user);
        }
    }
}
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)

3、通用CURD

3.1、插入操作

测试方法:

package com.blnp.net.test;

import com.blnp.net.dao.IUserMapper;
import com.blnp.net.entity.UserEntity;
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;

/**
 * <p></p>
 *
 * @author lyb 2045165565@qq.com
 * @version 1.0
 * @since 2024/8/26 20:22
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class TestSpringMP {

    @Autowired
    private IUserMapper userMapper;

    @Test
    public void test(){
        List<UserEntity> users = userMapper.selectList(null);
        for (UserEntity user : users) {
            System.out.println(user);
        }
    }

    @Test
    public void testInsert() {
        UserEntity user = new UserEntity();
        user.setAge(18);
        user.setEmail("test@blnp.cn");
        user.setName("子慕");

        //返回的result是受影响的⾏数,并不是⾃增后的id
        int result = userMapper.insert(user);
        System.out.println(result);
        System.out.println(user.getId());
    }

}

执行结果如下所示:

        可以看到,数据已经写⼊到了数据库,但是,id的值不正确,我们期望的是数据库⾃增⻓,实际是MP⽣成了id的值写⼊到了数据库。因此我们需要对ID配置生成策略!mybatis-plus支持的ID策略有以下几种:

package com.baomidou.mybatisplus.annotation;

import lombok.Getter;

/**
 * 生成ID类型枚举类
 *
 * @author hubin
 * @since 2015-11-10
 */
@Getter
public enum IdType {
    /**
     * 数据库ID自增
     */
    AUTO(0),
    /**
     * 该类型为未设置主键类型(注解里等于跟随全局,全局里约等于 INPUT)
     */
    NONE(1),
    /**
     * 用户输入ID
     * <p>该类型可以通过自己注册自动填充插件进行填充</p>
     */
    INPUT(2),

    /* 以下3种类型、只有当插入对象ID 为空,才自动填充。 */
    /**
     * 分配ID (主键类型为number或string),
     * 默认实现类 {@link com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator}(雪花算法)
     *
     * @since 3.3.0
     */
    ASSIGN_ID(3),
    /**
     * 分配UUID (主键类型为 string)
     * 默认实现类 {@link com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator}(UUID.replace("-",""))
     */
    ASSIGN_UUID(4),
    /**
     * @deprecated 3.3.0 please use {@link #ASSIGN_ID}
     */
    @Deprecated
    ID_WORKER(3),
    /**
     * @deprecated 3.3.0 please use {@link #ASSIGN_ID}
     */
    @Deprecated
    ID_WORKER_STR(3),
    /**
     * @deprecated 3.3.0 please use {@link #ASSIGN_UUID}
     */
    @Deprecated
    UUID(4);

    private final int key;

    IdType(int key) {
        this.key = key;
    }
}

实体类修改

    @TableId(type = IdType.AUTO)
    private Long id;

关于@TableField 注解的用途:

        在MP中通过@TableField注解可以指定字段的⼀些属性,常常解决的问题有2个:

  1. 对象中的属性名和字段名不⼀致的问题(⾮驼峰)
  2. 对象中的属性字段在表中不存在的问题
package com.blnp.net.entity;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * <p></p>
 *
 * @author lyb 2045165565@qq.com
 * @version 1.0
 * @since 2024/8/26 19:38
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName("user")
public class UserEntity {

    @TableId(type = IdType.AUTO)
    private Long id;
    /**
     *  表示该大字段不加入查询
     **/
    @TableField(select = false)
    private String name;
    /**
     *  表示该字段在数据库表中不存在
     **/
    @TableField(exist = false)
    private Integer age;
    /**
     *  解决字段名不一致问题
     **/
    @TableField(value = "mail")
    private String email;
}

注意事项:

         这里可能有的人配置ID策略后,测试新增时程序抛出以下错误:

org.springframework.dao.DataIntegrityViolationException: 
### Error updating database.  Cause: java.sql.SQLException: #HY000
### The error may exist in com/blnp/net/dao/IUserMapper.java (best guess)
### The error may involve com.blnp.net.dao.IUserMapper.insert-Inline
### The error occurred while setting parameters
### SQL: INSERT INTO user  ( name, age, email )  VALUES  ( ?, ?, ? )
### Cause: java.sql.SQLException: #HY000
; #HY000; nested exception is java.sql.SQLException: #HY000

        问题原因其实是insert语句没有设置ID值,导致ID字段为空。此时可以确认下表结构ID字段是否有设置自动增长,没有则勾选上即可。

3.2、更新操作

        在MP中,更新操作有2种,⼀种是根据id更新,另⼀种是根据条件更新。

根据ID更新:

@Test
public void testUpdateById() {
    UserEntity user = new UserEntity();
    user.setName("西瓜");
    user.setId(6L); //主键
    user.setAge(21); //更新的字段

    //根据id更新,更新不为null的字段
    this.userMapper.updateById(user);
}

根据条件更新:

@Test
public void testUpdate() {
    UserEntity user = new UserEntity();
    user.setAge(22); //更新的字段
    //更新的条件
    QueryWrapper<UserEntity> wrapper = new QueryWrapper<>();
    wrapper.eq("id", 6);
    //执⾏更新操作
    int result = this.userMapper.update(user, wrapper);
    System.out.println("result = " + result);
}

        或者,通过UpdateWrapper进⾏更新:

@Test
public void testUpdateWrapper() {
    //更新的条件以及字段
    UpdateWrapper<UserEntity> wrapper = new UpdateWrapper<>();
    wrapper.eq("id", 6).set("age", 23);
    //执⾏更新操作
    int result = this.userMapper.update(null, wrapper);
    System.out.println("result = " + result);
}

3.3、删除操作

@Test
public void testDeleteById() {
    //执行删除操作
    int result = this.userMapper.deleteById(6L);
    System.out.println("result = " + result);
}

@Test
public void testDeleteByMap() {
    Map<String, Object> columnMap = new HashMap<>();
    columnMap.put("age",21);
    columnMap.put("name","⼦慕");
    //将columnMap中的元素设置为删除的条件,多个之间为and关系
    int result = this.userMapper.deleteByMap(columnMap);
    System.out.println("result = " + result);
}

@Test
public void testDeleteByMapWrapper() {
    UserEntity user = new UserEntity();
    user.setAge(20);
    user.setName("慕");
    //将实体对象进⾏包装,包装为操作条件
    QueryWrapper<UserEntity> wrapper = new QueryWrapper<>(user);
    int result = this.userMapper.delete(wrapper);
    System.out.println("result = " + result);
}

@Test
public void testDeleteByBatch() {
    //根据id集合批量删除
    int result = this.userMapper.deleteBatchIds(Arrays.asList(1L,10L,20L));
    System.out.println("result = " + result);
}

3.4、查询操作

@Test
public void testSelectById() {
    //根据id查询数据
    UserEntity user = this.userMapper.selectById(2L);
    System.out.println("result = " + user);
}

@Test
public void testSelectBatchIds() {
    //根据id集合批量查询
    List<UserEntity> users = this.userMapper.selectBatchIds(Arrays.asList(2L, 3L, 10L));
    for (UserEntity user : users) {
        System.out.println(user);
    }
}

@Test
public void testSelectOne() {
    QueryWrapper<UserEntity> wrapper = new QueryWrapper<UserEntity>();
    wrapper.eq("name", "jack");
    //根据条件查询⼀条数据,如果结果超过⼀条会报错
    UserEntity user = this.userMapper.selectOne(wrapper);
    System.out.println(user);
}

@Test
public void testSelectCount() {
    QueryWrapper<UserEntity> wrapper = new QueryWrapper<UserEntity>();
    wrapper.gt("age", 23); //年龄⼤于23岁
    //根据条件查询数据条数
    Integer count = this.userMapper.selectCount(wrapper);
    System.out.println("count = " + count);
}

@Test
public void testSelectList() {
    QueryWrapper<UserEntity> wrapper = new QueryWrapper<UserEntity>();
    wrapper.gt("age", 23); //年龄⼤于23岁
    //根据条件查询数据
    List<UserEntity> users = this.userMapper.selectList(wrapper);
    for (UserEntity user : users) {
        System.out.println("user = " + user);
    }
}

@Test
public void testSelectPage() {
    QueryWrapper<UserEntity> wrapper = new QueryWrapper<UserEntity>();
    wrapper.gt("age", 20); //年龄⼤于20岁
    Page<UserEntity> page = new Page<>(1,1);
    //根据条件查询数据
    IPage<UserEntity> iPage = this.userMapper.selectPage(page, wrapper);
    System.out.println("数据总条数:" + iPage.getTotal());
    System.out.println("总⻚数:" + iPage.getPages());
    List<UserEntity> users = iPage.getRecords();
    for (UserEntity user : users) {
        System.out.println("user = " + user);
    }
}

3.5、SQL注入的原理

        在MP中,ISqlInjector负责SQL的注⼊⼯作,它是⼀个接⼝,AbstractSqlInjector是它的实现类,实现关系如下:

        在AbstractSqlInjector中,主要是由inspectInject()⽅法进⾏注⼊的,如下:在实现⽅法中, methodList.forEach(m -> m.inject(builderAssistant, mapperClass,modelClass, tableInfo)); 是关键,循环遍历⽅法,进⾏注⼊。最终调⽤抽象⽅法injectMappedStatement进⾏真正的注⼊:

@Override
    public void inspectInject(MapperBuilderAssistant builderAssistant, Class<?> mapperClass) {
        Class<?> modelClass = extractModelClass(mapperClass);
        if (modelClass != null) {
            String className = mapperClass.toString();
            Set<String> mapperRegistryCache = GlobalConfigUtils.getMapperRegistryCache(builderAssistant.getConfiguration());
            if (!mapperRegistryCache.contains(className)) {
                List<AbstractMethod> methodList = this.getMethodList(mapperClass);
                if (CollectionUtils.isNotEmpty(methodList)) {
                    TableInfo tableInfo = TableInfoHelper.initTableInfo(builderAssistant, modelClass);
                    // 循环注入自定义方法
                    methodList.forEach(m -> m.inject(builderAssistant, mapperClass, modelClass, tableInfo));
                } else {
                    logger.debug(mapperClass.toString() + ", No effective injection method was found.");
                }
                mapperRegistryCache.add(className);
            }
        }
    }

        以SelectByID为例,查看源代码如下:

package com.baomidou.mybatisplus.core.injector.methods;

import com.baomidou.mybatisplus.core.enums.SqlMethod;
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;
import org.apache.ibatis.scripting.defaults.RawSqlSource;

/**
 * 根据ID 查询一条数据
 *
 * @author hubin
 * @since 2018-04-06
 */
public class SelectById extends AbstractMethod {

    @Override
    public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
        SqlMethod sqlMethod = SqlMethod.SELECT_BY_ID;
        SqlSource sqlSource = new RawSqlSource(configuration, String.format(sqlMethod.getSql(),
            sqlSelectColumns(tableInfo, false),
            tableInfo.getTableName(), tableInfo.getKeyColumn(), tableInfo.getKeyProperty(),
            tableInfo.getLogicDeleteSql(true, true)), Object.class);
        return this.addSelectMappedStatementForTable(mapperClass, getMethod(sqlMethod), sqlSource, tableInfo);
    }
}

        可以看到,⽣成了SqlSource对象,再将SQL通过addSelectMappedStatement⽅法添加到meppedStatements中。

4、具体配置

4.1、基本配置

4.1.1、configLocation

        MyBatis 配置⽂件位置,如果有单独的 MyBatis 配置,请将其路径配置到 configLocation 中。MyBatis Configuration 的具体内容请参考MyBatis 官⽅⽂档

Springboot:

mybatis-plus.config-location = classpath:mybatis-config.xml

SpringMVC:

<bean id="sqlSessionFactory" class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean">
    <property name="configLocation" value="classpath:mybatis-config.xml"/>
</bean>

 4.1.2、mapperLocations

        MyBatis Mapper 所对应的 XML ⽂件位置,如果您在 Mapper 中有⾃定义⽅法(XML 中有⾃定义实现),需要进⾏该配置,告诉 Mapper 所对应的 XML ⽂件位置。

Springboot:

mybatis-plus.mapper-locations = classpath*:mybatis/*.xml

SpringMVC:

<bean id="sqlSessionFactory" class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean">
    <property name="mapperLocations" value="classpath*:mybatis/*.xml"/>
</bean>

注意事项:Maven 多模块项⽬的扫描路径需以  classpath*: 开头(即加载多个 jar 包下的 XML ⽂件)。

4.1.3、typeAliasesPackage

        MyBaits 别名包扫描路径,通过该属性可以给包中的类注册别名,注册后在 Mapper 对应的 XML ⽂件中可以直接使⽤类名,⽽不⽤使⽤全限定的类名(即 XML 中调⽤的时候不⽤包含包名)。

Springboot:

mybatis-plus.type-aliases-package = com.blnp.net.mp.pojo

SpringMVC:

<bean id="sqlSessionFactory" class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean">
    <property name="typeAliasesPackage" value="com.baomidou.mybatisplus.samples.quickstart.entity"/>
</bean>

4.2、进阶配置

4.2.1、mapUnderscoreToCamelCase

  • 类型:Boolean
  • 默认值:true

        是否开启⾃动驼峰命名规则(camel case)映射,即从经典数据库列名 A_COLUMN(下划线命名) 到经典 Java 属性名 aColumn(驼峰命名) 的类似映射。

        此属性在 MyBatis 中原默认值为 false,在 MyBatis-Plus 中,此属性也将⽤于⽣成最终的 SQL 的 select body。如果您的数据库命名符合规则⽆需使⽤ @TableField 注解指定数据库字段名。

#关闭⾃动驼峰映射,该参数不能和mybatis-plus.config-location同时存在
mybatis-plus.configuration.map-underscore-to-camel-case=false

4.2.2、cacheEnabled

  • 类型:Boolean
  • 默认值:true

        全局地开启或关闭配置⽂件中的所有映射器已经配置的任何缓存,默认为 true。

mybatis-plus.configuration.cache-enabled=false

4.3、DB策略配置

4.3.1、idType

  • 类型:com.baomidou.mybatisplus.annotation.IdType
  • 默认值:ID_WORKER

        全局默认主键类型,设置后,即可省略实体对象中的@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>

4.3.2、tablePrefix

  • 类型:String
  • 默认值:null

        表名前缀,全局配置后可省略@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>

5、条件构造器

5.1、allEq

相关API

allEq(Map<R, V> params)
allEq(Map<R, V> params, boolean null2IsNull)
allEq(boolean condition, Map<R, V> params, boolean null2IsNull)
  • params:key 为数据库字段名, value 为字段值
  • null2IsNull : 为true 则在map 的value 为null 时调⽤ isNull ⽅法,为false 时则忽略value 为null 的
allEq(BiPredicate<R, V> filter, Map<R, V> params)
allEq(BiPredicate<R, V> filter, Map<R, V> params, boolean null2IsNull)
allEq(boolean condition, BiPredicate<R, V> filter, Map<R, V> params, boolean null2IsNull)
  • filter:过滤函数,是否允许字段传⼊⽐对条件中
  • params 与 null2IsNull 同上

示例1:

        allEq((k,v) -> k.indexOf("a") > 0, {id:1,name:"⽼王",age:null})  -->  name = '⽼王' and age is null

示例2:

        allEq((k,v) -> k.indexOf("a") > 0, {id:1,name:"⽼王",age:null},false)  --> name = '⽼王'

@Test
public void testWrapper() {
    QueryWrapper<UserEntity> wrapper = new QueryWrapper<>();

    //设置条件
    Map<String,Object> params = new HashMap<>();
    params.put("name", "jack");
    params.put("age", "20");

    // wrapper.allEq(params);
    // SELECT * FROM user WHERE password IS NULL AND name = ? AND age = ?

    // wrapper.allEq(params,false);
    // SELECT * FROM user WHERE name = ? AND age = ?

    // wrapper.allEq((k, v) -> (k.equals("name") || k.equals("age")),params);
    // SELECT * FROM user WHERE name = ? AND age = ?

    List<UserEntity> users = this.userMapper.selectList(wrapper);
    for (UserEntity user : users) {
        System.out.println(user);
    }
}

5.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)
@Test
public void testWrapperQuery() {
    QueryWrapper<UserEntity> wrapper = new QueryWrapper<>();
    //SELECT id,name,age,email FROM tb_user WHERE password = ? AND age >= ? AND name IN (?,?,?)
    wrapper.eq("email", "test2@baomidou.com")
            .ge("age", 20)
            .in("name", "jack", "jone", "tom");
    List<UserEntity> users = this.userMapper.selectList(wrapper);
    for (UserEntity user : users) {
        System.out.println(user);
    }
}

5.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 '王%'
@Test
public void testWrapperLike() {
    QueryWrapper<UserEntity> wrapper = new QueryWrapper<>();
    //SELECT id,user_name,password,name,age,email FROM tb_user WHERE name LIKE ?
    //Parameters: %⼦%(String)
    wrapper.like("name", "⼦");
    List<UserEntity> users = this.userMapper.selectList(wrapper);
    for (UserEntity user : users) {
        System.out.println(user);
    }
}

5.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
@Test
public void testWrapperOrder() {
    QueryWrapper<UserEntity> wrapper = new QueryWrapper<>();
    //SELECT id,user_name,password,name,age,email FROM tb_user ORDER BY age DESC
    wrapper.orderByDesc("age");
    List<UserEntity> users = this.userMapper.selectList(wrapper);
    for (UserEntity user : users) {
        System.out.println(user);
    }
}

5.5、逻辑查询

  • or
    • 拼接 OR
    • 主动调⽤or 表示紧接着下⼀个⽅法不是⽤and 连接!(不调⽤or 则默认为使⽤and 连接)
  • and
    • AND 嵌套
    • 例: and(i -> i.eq("name", "李⽩").ne("status", "活着")) ---> and (name = '李⽩' and status <> '活着')
@Test
public void testWrapperAnd() {
    QueryWrapper<UserEntity> wrapper = new QueryWrapper<>();
    //SELECT id,user_name,password,name,age,email FROM tb_user WHERE name= ? OR age = ?
    wrapper.eq("name","jack").or().eq("age", 24);
    List<UserEntity> users = this.userMapper.selectList(wrapper);
    for (UserEntity user : users) {
        System.out.println(user);
    }
}

5.6、Select

        在MP查询中,默认查询所有的字段,如果有需要也可以通过select⽅法进⾏指定字段。

@Test
public void testWrapperSelect() {
    QueryWrapper<UserEntity> wrapper = new QueryWrapper<>();
    //SELECT id,name,age FROM tb_user WHERE name = ? OR age = ?
    wrapper.eq("name", "jack")
            .or()
            .eq("age", 24)
            .select("id", "name", "age");
    List<UserEntity> users = this.userMapper.selectList(wrapper);
    for (UserEntity user : users) {
        System.out.println(user);
    }
}

6、ActiveRecord

6.1、开启AR功能

        在MP中,开启AR⾮常简单,只需要将实体对象继承Model即可。

@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName("user")
public class UserEntity extends Model<UserEntity> {

    @TableId(type = IdType.AUTO)
    private Long id;
    /**
     *  表示该大字段不加入查询
     **/
    private String name;
    /**
     *  表示该字段在数据库表中不存在
     **/
    private Integer age;
    /**
     *  解决字段名不一致问题
     **/
    private String email;
}

6.2、根据主键查询

@Test
public void testAR() {
    UserEntity user = new UserEntity();
    user.setId(2L);
    UserEntity user2 = user.selectById();
    System.out.println(user2);
}

6.3、新增数据

@Test
public void testARInsert() {
    UserEntity user = new UserEntity();
    user.setName("应颠");
    user.setAge(30);
    user.setEmail("yingdian@blnp.cn");
    boolean insert = user.insert();
    System.out.println(insert);
}

6.4、更新操作

@Test
public void testARUpdate() {
    UserEntity user = new UserEntity();
    user.setId(8L);
    user.setAge(35);
    boolean update = user.updateById();
    System.out.println(update);
}

6.5、删除操作

@Test
public void testARDelete() {
    UserEntity user = new UserEntity();
    user.setId(7L);
    boolean delete = user.deleteById();
    System.out.println(delete);
}

6.6、根据条件查询

@Test
public void testARFindById() {
    UserEntity user = new UserEntity();
    QueryWrapper<UserEntity> userQueryWrapper = new QueryWrapper<>();
    userQueryWrapper.le("age","20");
    List<UserEntity> users = user.selectList(userQueryWrapper);
    for (UserEntity user1 : users) {
        System.out.println(user1);
    }
}
  • 11
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值