1.mybatis plus 简介

1.1 MyBatis Plus 介绍

MyBatis-Plus(简称 MP),是一个MyBatis的增强工具包,只做增强不做改变.为简化开发工作、提高生产率而生

1.2 代码及文档发布地址

官方地址:

http://mp.baomidou.com

代码发布地址:

Github: https://github.com/baomidou/mybatis-plus

Gitee: https://gitee.com/baomidou/mybatis-plus

文档发布地址:

http://mp.baomidou.com/#/?id=%E7%AE%80%E4%BB%8B

2.集成MP

2.1 创建测试表

-- 创建库

CREATE DATABASE mp;

-- 使用库

USE mp;

-- 创建表

CREATE TABLE tbl_employee(

 id INT(11) PRIMARY KEY AUTO_INCREMENT,

 last_name VARCHAR(50),

 email VARCHAR(50),

 gender CHAR(1),

 age int

);

INSERT INTO tbl_employee(last_name,email,gender,age) VALUES('Tom','tom@atguigu.com',1,22);

INSERT INTO tbl_employee(last_name,email,gender,age) VALUES('Jerry','jerry@atguigu.com',0,25);

INSERT INTO tbl_employee(last_name,email,gender,age) VALUES('Black','black@atguigu.com',1,30);

INSERT INTO tbl_employee(last_name,email,gender,age) VALUES('White','white@atguigu.com',0,35);

注意:这里我们的主键是自增的

2.2 创建JavaBean

public class Employee {

private Integer id ; 

private String lastName; 

private String email ;

private Integer gender ;

private Integer age ;

public Integer getId() {

return id; 

}

public void setId(Integer id) {

this.id = id; 

}

public String getLastName() {

return lastName; 

public void setLastName(String lastName) {

this.lastName = lastName; 

}

public String getEmail() {

return email; 

}

public void setEmail(String email) {

this.email = email; 

}

public Integer getGender() {

return gender; 

}

public void setGender(Integer gender) {

this.gender = gender; 

}

public Integer getAge() {

return age; 

}

public void setAge(Integer age) {

this.age = age; 

}

@Override

public String toString() {

return "Employee [id=" + id + ", lastName=" + lastName + ", email=" + email

\+ ", gender=" + gender + ", age="

\+ age + "]"; 

}

2.3 依赖配置

1、 在 pom.xml 中加入对 MP、Spring、连接池、Junit、Mysql 驱动等依赖

<!-- mp 依赖 -->
<dependency>
 <groupId>com.baomidou</groupId> 
 <artifactId>mybatis-plus</artifactId>
 <version>2.3</version>
</dependency>

<!--junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.9</version>
</dependency>

<!-- log4j -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>

<!-- c3p0 -->
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.2</version>
</dependency>

<!-- mysql -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.37</version>
</dependency>

<!-- spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.10.RELEASE</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>4.3.10.RELEASE</version>
</dependency>

特别说明: Mybatis 及 Mybatis-Spring 依赖请勿加入项目配置,以免引起版本冲突!!!Mybatis-Plus 会自动帮你维护!

2、加入 MyBatis 的全局配置文件

<?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>

 </configuration>

3、 加入 log4j.xml

<?xml version="1.0" encoding="UTF-8" ?>

<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">

<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">

<appender name="STDOUT" class="org.apache.log4j.ConsoleAppender">

 <param name="Encoding" value="UTF-8" />

 <layout class="org.apache.log4j.PatternLayout">

 <param name="ConversionPattern" value="%-5p %d{MM-dd 

HH:mm:ss,SSS} %m (%F:%L) \n" />

 </layout>

</appender>

<logger name="java.sql">

 <level value="debug" />

</logger>

<logger name="org.apache.ibatis">

 <level value="info" />

</logger>

<root>

 <level value="debug" />

 <appender-ref ref="STDOUT" />

</root>

</log4j:configuration>

4)、加入 db.properties 连接信息配置

jdbc.driver=com.mysql.jdbc.Driver

jdbc.url=jdbc:mysql://localhost:3306/mp

jdbc.username=root

jdbc.password=1234

5、加入 spring 的配置文件 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"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:mybatis-spring="http://mybatis.org/schema/mybatis-spring"
xsi:schemaLocation="http://mybatis.org/schema/mybatis-spring 
http://mybatis.org/schema/mybatis-spring-1.2.xsd
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-4.0.xsd
http://www.springframework.org/schema/tx 
http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">

<!-- 数据源 -->
<context:property-placeholder location="classpath:db.properties"/>
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
    
<property name="driverClass" value="${jdbc.driver}"></property>
<property name="jdbcUrl" value="${jdbc.url}"></property>
<property name="user" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>

</bean>

<!-- 事务管理器 -->
<bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

<property name="dataSource" ref="dataSource"></property>

</bean>

<!-- 基于注解的事务管理 -->
<tx:annotation-driven transaction-manager="dataSourceTransactionManager"/>

<!-- 配置 SqlSessionFactoryBean -->
<bean id="sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean">

<!-- 数据源 -->
<property name="dataSource" ref="dataSource"></property>
<property name="configLocation"  value="classpath:mybatis-config.xml"></property>
<!-- 别名处理 -->
<property name="typeAliasesPackage" value="com.atguigu.mp.beans"></property>

</bean>

<!--配置 mybatis 扫描 mapper 接口的路径-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    
<property name="basePackage" 
value="com.atguigu.mp.mapper"></property>

</bean>

</beans>

2.4 测试

1、测试 Spring-Mybatis 的环境,保证 OK。

private ApplicationContext iocContext = new ClassPathXmlApplicationContext("applicationContext.xml");

@Test
public void testEnvironment() throws Exception{

DataSource ds = iocContext.getBean("dataSource",DataSource.class);

Connection conn = ds.getConnection();

System.out.println(conn);

}

2.5 集成MP

1、 Mybatis-Plus 的集成非常简单,对于 Spring,我们仅仅需要把 Mybatis 自带的MybatisSqlSessionFactoryBean 替换为 MP 自带的即可。

<bean id="sqlSessionFactoryBean" class="com.baomidou.mybatisplus.spring.MybatisSqlSessionFactoryBean">
<!-- 数据源 --> 
<property name="dataSource" ref="dataSource"></property>
<property name="configLocation" value="classpath:mybatis-config.xml"></property>
<!-- 别名处理 -->
<property name="typeAliasesPackage" value="com.atguigu.mp.beans"></property>
</bean>

3.入门

3.1 通用CRUD

问题:

假设我们已存在一张 tbl_employee 表,且已有对应的实体类 Employee,实现tbl_employee 表的 CRUD 操作我们需要做什么呢?

答:

  • 基于 Mybatis:需要编写 EmployeeMapper 接口,并手动编写 CRUD 方法;提供 EmployeeMapper.xml 映射文件,并手动编写每个方法对应的 SQL 语句.
  • 基于 MP:只需要创建 EmployeeMapper 接口, 并继承 BaseMapper 接口.这就是使用 MP需要完成的所有操作,甚至不需要创建 SQL 映射文件。

3.2 通用插入操作

1.创建EmployeeMapper ,该接口继承BaseMapper ,泛型指定要操作的表对应的实体

puvblic interface EmployeeMapper implements BaseMapper <Employee>{
}

2.创建junit测试

public class TestMP{
    
    private ApplicationConext ac = new ClassPathXmlApplicationContext("application.xml");
    
    //真正开发中自动注入
    private EmployeeMapper mapper = ac.getBean("employeeMapper",EmployeeMapper.class);
    
    
    @Test
    public void test(){
        Employee employee = new Employee();
        employee.setEmail("xxxxxx");
        、、、
        //其他属性赋值自己定义吧
        Integer result = mapper.insert(emoloyee);
        result.sout
    }
}

3.执行代码,junit测试报错。报错原因:表中主键是自增的,mybatis plus需要指定主键策略;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kc2cYs1L-1610260917684)(C:\Users\19651\AppData\Roaming\Typora\typora-user-images\image-20210108173418096.png)]

解决方式:

在表对应的实体类中(Employee),找到id字段(private Integer id ;,在该字段上边添加注解@TableId(value="id",type=IdType.AUTO)  
public class Employee {
@TableId(value="id",type=IdType.AUTO)  
private Integer id ; //如果这里定义的id名称和表中的一致,注解中就不需要指定value,否则,value需要指定表中的主键名称;这里的type指定主键的形式,是个枚举类型,具体有几种(4种),自己查看源码

private String lastName; 

private String email ;

private Integer gender ;

private Integer age ;

public Integer getId() {

return id; 

}
        .
        .
        .
        //其余字段自己补全吧
}
  1. 继续执行代码,发现junit测试报错。原因:不存在表employee!原因很好理解,数据库中的表的名字是 tbl_employee,当mybatis plus去执行代码的时候,会根据当前实体类的类名去找到这张表,所以数据库中并没有叫employee的表

    解决方式:

    //表名注解@TableName
        
    
    @TableName(value="tbl_employee")
    public class Employee {
    @TableId(value="id",type=IdType.AUTO)  
    private Integer id ; //如果这里定义的id名称和表中的一致,注解中就不需要指定value,否则,value需要指定表中的主键名称;这里的type指定主键的形式,是个枚举类型,具体有几种(4种),自己查看源码
    
    private String lastName; 
    
    private String email ;
    
    private Integer gender ;
    
    private Integer age ;
    
    public Integer getId() {
    
    return id; 
    
    }
            .
            .
            .
            //其余字段自己补全吧
    }
    
  2. 执行代码,操作成功

3.2.1插入操作问题分析

问题1:我们的字段命名时驼峰命名,数据库中的字段命名是下划线形式,那为什么mybatis plus映射成功了呢?

问题2:表名要用@TableName注解,id要用@TableId注解,当实体慢慢变多,会不会变得很繁琐?

答案:全局配置策略 !

当然,驼峰命名要有自己的注解:@TableField(value="") value指定数据库中的字段

<?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"
xmlns:mybatis-spring="http://mybatis.org/schema/mybatis-spring"
xsi:schemaLocation="http://mybatis.org/schema/mybatis-spring 
http://mybatis.org/schema/mybatis-spring-1.2.xsd
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-4.0.xsd
http://www.springframework.org/schema/tx 
http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">

<!-- 数据源 -->
<context:property-placeholder location="classpath:db.properties"/>
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
    
<property name="driverClass" value="${jdbc.driver}"></property>
<property name="jdbcUrl" value="${jdbc.url}"></property>
<property name="user" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>

</bean>

<!-- 事务管理器 -->
<bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

<property name="dataSource" ref="dataSource"></property>

</bean>

<!-- 基于注解的事务管理 -->
<tx:annotation-driven transaction-manager="dataSourceTransactionManager"/>

<!-- 配置 SqlSessionFactoryBean -->
<bean id="sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean">

<!-- 数据源 -->
<property name="dataSource" ref="dataSource"></property>
<property name="configLocation"  value="classpath:mybatis-config.xml"></property>
<!-- 别名处理 -->
<property name="typeAliasesPackage" value="com.atguigu.mp.beans"></property>

    
<!-- 注入下面的全局配置策略 -->
<property name="globalConfiguration" value="globalConfiguration"></property>
</bean>

<!--配置 mybatis 扫描 mapper 接口的路径-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    
<property name="basePackage" value="com.atguigu.mp.mapper"></property>

</bean>
    
    
    
    
    
<!-- 定义mybatis plus的全局策略配置 定义完该配置后,别忘了加入到spring中-->
<bean id = "globalConfiguration" class="com.baomidou.mybatisplus.entity.GlobalConfiguration">
    <!-- 配置驼峰映射 在2.3版本以后,dbColumnUnderline的默认值就是true(表示开启)-->
	<property name="dbColumnUnderline" value = "true"></property>
    <!--配置全局主键策略 value的值自己去看对那个的idType的枚举吧,里边讲的很详细-->
    <property name="idType" value = "0"></property>
    <!-- 全局的表格名称前缀配置   表格的名称前缀 -->
    <property name="tablePrefix" value = "tbl_"></property>
</bean>

</beans>

驼峰注解中还有一个exist()属性,默认值为true,代表该字段在数据库的表中有对应字段;当@TableField(exist=false)时,该字段的值不会被插入到数据库中

问题3:我们插入问一条数据后,怎么第一时间获取被插入数据的id呢?

答案:当我们执行操作的时候,mybatis plus会自动将主键值回写到实体类中。

public class TestMP{
    
    private ApplicationConext ac = new ClassPathXmlApplicationContext("application.xml");
    
    //真正开发中自动注入
    private EmployeeMapper mapper = ac.getBean("employeeMapper",EmployeeMapper.class);
    
    
    @Test
    public void test(){
        Employee employee = new Employee();
        employee.setEmail("xxxxxx");
        、、、
        //其他属性赋值自己定义吧
        Integer result = mapper.insert(emoloyee);
        result.sout
            int id = employee.getId();
        id.sout
    }
}

问题4:当我们注释掉插入的几条属性,观察运行时的sql语句,发现sql中被注释掉的属性对应的字段也小时了,说明mybatis plus的插入操作是动态插入操作,类似于mybatis中的动态sql语句。如果我们不希望以上这种操作出现(注释掉了属性,但是被注释掉的属性对应的字段依然出现在sql语句中)怎么办呢?

答案:我们就不能用insert方法了,应该使用insertAllColumn()方法,对应字段的值为null

public class TestMP{
    
    private ApplicationConext ac = new ClassPathXmlApplicationContext("application.xml");
    
    //真正开发中自动注入
    private EmployeeMapper mapper = ac.getBean("employeeMapper",EmployeeMapper.class);
    
    
    @Test
    public void test(){
        Employee employee = new Employee();
        employee.setEmail("xxxxxx");
        、、、
        //其他属性赋值自己定义吧
        //Integer result = mapper.insert(emoloyee);
            Integer result = mapper.insertAllColumn(emoloyee);
        result.sout
            int id = employee.getId();
        id.sout
    }
}

3.3 通用更新操作

public class TestMP{
    
    private ApplicationConext ac = new ClassPathXmlApplicationContext("application.xml");
    
    //真正开发中自动注入
    private EmployeeMapper mapper = ac.getBean("employeeMapper",EmployeeMapper.class);
    
    
    @Test
    public void testUpdate(){
        Employee employee = new Employee();
        employee.setId("123");
        employee.setEmail("xxxxxx");
        //其他属性赋值自己定义吧
        Integer result = mapper.updateById(employee);
        result.sout
        
    }
}

3.3.1 更新操作问题分析

  1. 注释掉一些属性,进行更新操作,发现sql属性中没有被注释掉的属性对应的字段,说明updateById()方法也是动态sql语句;如果向使用全量的更新语句(修改所有列,不管有没有值),使用方法updateAllColumnById();
public class TestMP{
    
    private ApplicationConext ac = new ClassPathXmlApplicationContext("application.xml");
    
    //真正开发中自动注入
    private EmployeeMapper mapper = ac.getBean("employeeMapper",EmployeeMapper.class);
    
    
    @Test
    public void testUpdate(){
        Employee employee = new Employee();
        employee.setId("123");
        employee.setEmail("xxxxxx");
        //其他属性赋值自己定义吧
        Integer result = mapper.updateAllColumnById(employee);//没有值的字段为null
        result.sout
        
    }
}

3.4 通用查询操作

public class TestMP{
    
    private ApplicationConext ac = new ClassPathXmlApplicationContext("application.xml");
    
    //真正开发中自动注入
    private EmployeeMapper mapper = ac.getBean("employeeMapper",EmployeeMapper.class);
    
    
    @Test
    public void testUpdate(){
        //1.通过id查询
        Employee employee = mapper.selectById("123");//将id传进去就可以了
        //2.通过多个列进行查询(或者说通过不同条件进行查询);举例:通过  id+lastName   进行查询(只会有一条);如果对应的数据有多条,会报错
        Employee employee = new Employee();
        employee.setId("123");
        employee.serLastName("lastName");
        Employee entity1 = mapper.selectOne(employee);//也是动态sql语句
        //3.通过多个id进行查询
        List<String> ids = new ArrayList<>();
        ids.add("1");
        ids.add("2");
        ids.add("3");
        List<Employee> employees = mapper.selectBatchIds(ids);//sql实质:where id in(1,2,3)
        //4.通过Map封装条件进行查询
        Map<String> columnMap = new HashMap<>();
        columnMap.put("last_name","张三");//注意key值是数据库中的字段名
        columnMap.put("age",20);
        List<Employee> employees = mapper.selectByMap(columnMap);
        //5.分页查询
        /**
        *mabatis plus提供了一个page实体(已一个分页辅助类对象),专门用来实现分页
        *mapper.selectPage(rowBounds,wrapper);
        *rowBounds已经被page辅助类继承了,所以直接传递一个page对象就行,后面的wrapper参数是一个代码构造器,后面会讲
        *page对象中的属性很容易理解,自己去看源码
        */
        List<Employee> employees = mapper.selectPage(new Page<>(0,20),null);//第0页,每页显示20条数据;观察sql语句,发现并没有limit语句;这个分页方式并不是很好,后续会使用到一个分页插件
        
        
    }
}

3.5 删除操作

Integer deleteById(Serializable id);//不用在意Serializable关键字,直接传递你想删除的id就是
Integer deleteByMap(@Param("cm")Map(String,Object) columnMap);//使用方法和查询中的用法一样
Integer deleteBatchIds(List<? extends Serializable> idList);//使用方法和查询中的用法一样


不再演示使用代码

3.6 Mybatis Plus启动就已经注入SQL原理分析

3.7 通用CRUD操作总结

1、以上是基本的 CRUD 操作,如您所见,我们仅仅需要继承一个 BaseMapper 即可实现大部分单表 CRUD 操作。BaseMapper 提供了多达 17 个方法给大家使用, 可以极其方便的实现单一、批量、分页等操作。极大的减少开发负担,难道这就是 MP 的强大之处了吗?

2、提出需求:

​ 现有一个需求,我们需要分页查询 tbl_employee 表中,年龄在 18~50 之间性别为男且姓名为 xx 的所有用户,这时候我们该如何实现上述需求呢?

MyBatis : 需要在 SQL 映射文件中编写带条件查询的 SQL,并基于 PageHelper 插件完成分页. 实现以上一个简单的需求,往往需要我们做很多重复单调的工作。普通的 Mapper能够解决这类痛点吗?

MP: 依旧不用编写 SQL 语句, MP 提供了功能强大的条件构造器 EntityWrapper

4.条件构造器EntityWrapper

4.1 EntityWrapper简介

1、Mybatis-Plus 通过 EntityWrapper(简称 EW,MP 封装的一个查询条件构造器)或者

Condition(与 EW 类似)来让用户自由的构建查询条件,简单便捷,没有额外的负担,能够有效提高开发效率

2、实体包装器,主要用于处理 sql 拼接,排序,实体参数查询等

3、注意: 使用的是数据库字段,不是 Java 属性!

4、条件参数说明:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DwcPS3au-1610260917688)(C:\Users\19651\AppData\Roaming\Typora\typora-user-images\image-20210109121216871.png)]

注意:xxNew方法都是另起(…) 括号包裹

4.2 EntityWrapper CRUD

//分页查询 tbl_employee 表中,年龄在 18~50 之间性别为男且姓名为 xx 的所有用户
List<Employee> userList = employeeMapper.selectPage(
    new Page<Employee>(2, 3),new EntityWrapper<Employee>()
    .eq("last_name", "MybatisPlus")//注意: 使用的是数据库字段,不是 Java 属性!
 	.eq("gender", 1)//注意: 使用的是数据库字段,不是 Java 属性!
 	.between("age", 18, 50)//注意: 使用的是数据库字段,不是 Java 属性!

);

4.2.1 带条件的查询

List selectList(@Param(“ew”) Wrapper wrapper);

//需求:查询tbl_employee表中,性别为女且名字中带有"老师"或者邮箱中带有"a"的数据,不需要分页

public class TestMP{
    
    private ApplicationConext ac = new ClassPathXmlApplicationContext("application.xml");
    
    //真正开发中自动注入
    private EmployeeMapper mapper = ac.getBean("employeeMapper",EmployeeMapper.class);
    
    
    @Test
    public void test(){
        List<Employee> list = mapper.slectList(new EntityWrapper<Employee>()
                        .eq("gender",0)
                        .like("last_name","老师")
                        .or()//也可以用orNew()方法
                        .like("email","a")
                                              );
    }
}

/**
*使用or()方法的sql:select * from 表 where (gender=? and last_name like ? or email like ?)
*
*使用orNew()方法的sql:select * from 表 where (gender=? and last_name like ?) or (email like ?)
*
*笔者学到这里感觉这两条sql对于本次的查询需求理解有歧义,但是我们的关注点在于二者的sql区别,不要纠结需求,明白原理就好
*/

4…2.2带条件的更新

Integer update(@Param(“et”) T entity, @Param(“ew”) Wrapper wrapper);

//需求,修改数据库中名字为tom且年龄为44的数据
public class TestMP{
    
    private ApplicationConext ac = new ClassPathXmlApplicationContext("application.xml");
    
    //真正开发中自动注入
    private EmployeeMapper mapper = ac.getBean("employeeMapper",EmployeeMapper.class);
    
    
    @Test
    public void test(){
        Employee emp = new Employee();
        emp.setLastName("测试名字");
        emp.setAge(88);
        emp.setGender(0);
        int result = mapper.update(emp,
                  new EntityWrapper<Employee>()
                      .eq("last_name","tom")
                      .eq("age","44"));
    }
}
//sql:update last_name=?,age=?,gender=? from 表 where (last_name = ? and age = ?)

4.2.3 带条件的删除

Integer delete(@Param(“ew”) Wrapper wrapper);

//需求,删除名字为tom且年龄为22的数据
public class TestMP{
    
    private ApplicationConext ac = new ClassPathXmlApplicationContext("application.xml");
    
    //真正开发中自动注入
    private EmployeeMapper mapper = ac.getBean("employeeMapper",EmployeeMapper.class);
    
    
    @Test
    public void test(){
        Employee emp = new Employee();
        emp.setLastName("测试名字");
        emp.setAge(88);
        emp.setGender(0);
        int result = mapper.update(
                  new EntityWrapper<Employee>()
                      .eq("last_name","tom")
                      .eq("age","22"));
    }
}
//sql:update last_name=?,age=?,gender=? from 表 where (last_name = ? and age = ?)

4.2.4 排序

public class TestMP{
    
    private ApplicationConext ac = new ClassPathXmlApplicationContext("application.xml");
    
    //真正开发中自动注入
    private EmployeeMapper mapper = ac.getBean("employeeMapper",EmployeeMapper.class);
    
    
    @Test
    public void test(){
        List<Employee> list = mapper.slectList(new EntityWrapper<Employee>()
                        .eq("gender",0)
                        .like("last_name","老师")
                        //.orderBy("age")//默认升序
                          .orderDesc(Arrays.asList(new String[] {"age"}))//要求集合类型的对象,所以要把排序的字段封装成集合
                                              );
    }
}
public class TestMP{
    
    private ApplicationConext ac = new ClassPathXmlApplicationContext("application.xml");
    
    //真正开发中自动注入
    private EmployeeMapper mapper = ac.getBean("employeeMapper",EmployeeMapper.class);
    
    
    @Test
    public void test(){
        List<Employee> list = mapper.slectList(new EntityWrapper<Employee>()
                        .eq("gender",0)
                        .like("last_name","老师")
                        .orderBy("age")//默认升序
                        .last("desc limit 1,3")//字符串拼接,相当于 order by age desc limit 1,3  last()方法有sql注入的风险,不建议使用
                  =
             
                                              );
    }
}

4.3 Condition CRUD

//分页查询 tbl_employee 表中,年龄在 18~50 之间性别为男且姓名为 xx 的所有用户
List<Employee> userList = employeeMapper.selectPage(new Page<Employee>(2, 3),
               Condition.create()//Condition 类也继承了wrapper,只不过需要通过静态方法create获取Condition实例,然后用法和EntityWrapper一样
    .eq("last_name", "MybatisPlus")//注意: 使用的是数据库字段,不是 Java 属性!
 	.eq("gender", 1)//注意: 使用的是数据库字段,不是 Java 属性!
 	.between("age", 18, 50)//注意: 使用的是数据库字段,不是 Java 属性!

);

5.ActiveRecord(活动记录)

5.1 简介

Active Record(活动记录),是一种领域模型模式,特点是一个模型类对应关系型数据库中的一个表,而模型类的一个实例对应表中的一行记录。

ActiveRecord 一直广受动态语言( PHP 、 Ruby 等)的喜爱,而 Java 作为准静态语言,对于 ActiveRecord 往往只能感叹其优雅,所以 MP 也在 AR 道路上进行了一定的探索。

5.2 如何使用AR模式

1、仅仅需要让实体类继承 Model 类且实现主键指定方法,即可开启 AR 之旅.

@TableName("tbl_employee")

public class Employee extends Model<Employee>{

// .. fields

// .. getter and setter

@Override
protected Serializable pkVal() {//这个方法是Model类中的一个抽象方法,需要实现;这个方法必须指定当前实体类的主键属性
return this.id; 
}

5.3 AR基本CRUD

1、插入操作

  • public boolean insert()
//
public class TestMP{
    
    private ApplicationConext ac = new ClassPathXmlApplicationContext("application.xml");
    
    
    @Test
    public void test(){
        Employee employee = new Employee();
        employee.setLastName("你好");
        employee.setAge(22);
        boolean t = employee.insert();
    }
}

2、修改操作

  • public boolean updateById()
//其他的求改更改自己捣鼓
public class TestMP{
    
    private ApplicationConext ac = new ClassPathXmlApplicationContext("application.xml");
    
    
    @Test
    public void test(){
        Employee employee = new Employee();
        employee.setLastName("你好");
        employee.setAge(22);
        employee.setId(1);
        boolean t = employee.updateById();
    }
}

3、查询操作

  • public T selectById()
  • public T selectById(Serializable id)
  • public List selectAll()
  • public List selectList(Wrapper wrapper)
  • public int selectCount(Wrapper wrapper)
//
public class TestMP{
    
    private ApplicationConext ac = new ClassPathXmlApplicationContext("application.xml");
    
    
    @Test
    public void test(){
        //public T selectById(Serializable id)
        Employee employee = new Employee();
        Employee t = employee.selectById(1);
        
        //public T selectById()
         Employee employee = new Employee();
         employee.setId(1);
         Employee t = employee.selectById();
        
        //public List<T> selectAll()
          Employee employee = new Employee();
        List<Employee> list = employee.selectAll();
        
        //public List<T> selectList(Wrapper wrapper)   查询名字中带有”老师“
         Employee employee = new Employee();
        List<Employee> list = employee.selectList(new EntityMapper<Employee>().like("last_name","老师"));
        
        //public int selectCount(Wrapper wrapper)  统计gender为0的数据条数
         Employee employee = new Employee();
        int num = employee.selectCount(new EntityMapper<Employee>().eq("gender",0));//如果向统计全部 employee.selectCount(null);
        
    }
}

4、删除操作

  • public boolean deleteById()
  • public boolean deleteById(Serializable id)
  • public boolean delete(Wrapper wrapper)
//
public class TestMP{
    
    private ApplicationConext ac = new ClassPathXmlApplicationContext("application.xml");
    
    //删除不存在的,逻辑上也属于成功的
    
    @Test
    public void test(){
        //public boolean deleteById()
        Employee employee = new Employee();
        employee.setId(1);
        boolean t = employee.deleteById();
        //public boolean deleteById(Serializable id)
        Employee employee = new Employee();
         boolean t = employee.deleteById(1);
        //public boolean delete(Wrapper wrapper)
         Employee employee = new Employee();
         boolean t = employee.delete(new EntityWrapper<Employee>().like("last_name","老师"));
    }
}

5、分页复杂操作

  • public Page selectPage(Page page, Wrapper wrapper)
//
public class TestMP{
    
    private ApplicationConext ac = new ClassPathXmlApplicationContext("application.xml");
    
    //删除不存在的,逻辑上也属于成功的
    
    @Test
    public void test(){
        //public boolean deleteById()
        Employee employee = new Employee();
        
        Page<Employee> page = employee.selectPage(new Page<>(1,20),new EntityWrapper<>(.like("last_name","老师")));
        List<Employee> list = page.getRecords();
    }
}

5.4 AR总结

1、AR 模式提供了一种更加便捷的方式实现 CRUD 操作,其本质还是调用的 Mybatis 对应的方法,类似于语法糖语法糖是指计算机语言中添加的某种语法,这种语法对原本语言的功能并没有影响。可以更方便开发者使用,可以避免出错的机会,让程序可读性更好。

2、 到此,我们简单领略了 Mybatis-Plus 的魅力与高效率,值得注意的一点是:我们提供了强大的代码生成器,可以快速生成各类代码,真正的做到了即开即用

6.代码生成器

6.1 简介

1、MP 提供了大量的自定义设置,生成的代码完全能够满足各类型的需求

2、 MP 的代码生成器 和 Mybatis MBG 代码生成器:

  • MP 的代码生成器都是基于 java 代码来生成。MBG 基于 xml 文件进行代码生成
  • MyBatis 的代码生成器可生成: 实体类、Mapper 接口、Mapper 映射文件
  • MP 的代码生成器可生成: 实体类(可以选择是否支持 AR)、Mapper 接口、Mapper 映射文件、 Service 层、Controller 层.

3、表及字段命名策略选择

​ 在 MP 中,我们建议数据库表名 和 表字段名采用驼峰命名方式, 如果采用下划线命名方式 请开启全局下划线开关,如果表名字段名命名方式不一致请注解指定,我们建议最好保持一致。这么做的原因是为了避免在对应实体类时产生的性能损耗,这样字段不用做映射就能直接和实体类对应。当然如果项目里不用考虑这点性能损耗,那么你采用下滑线也是没问题的,只需要在生成代码时配置 dbColumnUnderline 属性就可以

6.2 代码生成器依赖

1、模板引擎

MP 的代码生成器默认使用的是 Apache 的 Velocity 模板,当然也可以更换为别的模板技术,例如 freemarker。此处不做过多的介绍。

需要加入 Apache Velocity 的依赖

 <dependency>
 <groupId>org.apache.velocity</groupId>
 <artifactId>velocity-engine-core</artifactId>
 <version>2.0</version>
</dependency>

2、加入 slf4j ,查看日志输出信息

 <dependency> 
<groupId>org.slf4j</groupId> 
<artifactId>slf4j-api</artifactId> 
<version>1.7.7</version>
</dependency> 
<dependency> 
<groupId>org.slf4j</groupId> 
<artifactId>slf4j-log4j12</artifactId> 
<version>1.7.7</version>
</dependency>

6.3 Mybatis Plus代码生成器示例代码

就相当于去掉了xml配置,逆向工程

@Test
public void test() {

//全局配置
GlobalConfig config = new GlobalConfig();
config.setActiveRecord(true) //是否支持AR模式
 .setAuthor("weiyunhui") //编写的作者
 .setOutputDir("D:\\workspace_my\\mp03\\src\\main\\java") //生成路径  必不可少
 .setFileOverride(true)//如果多次生成文件,是否要文件覆盖,第二次覆盖第一次   
 .setServiceName("%sService") //设置生成的service接口名首字母是否为I  ,如果不配置,默认生成的接口首字母是I,如:IEmployeeService,配置了%sService,就不会出现首字母为I了

 .setIdType(IdType.AUTO) //主键策略
 .setBaseResultMap(true)//生成的sql映射文件,方便我们将来或许会用到自定义的结果集映射,所以我们这里生成一个基本的resultMap
 .setBaseColumnList(true)//生成基本的sql片段,方便我们使用   其实这里什么意思呢,就是他会生成一个对应表的mybatis映射文件,方便我们使用Mybatis
 ; 



//数据源配置

DataSourceConfig dsConfig = new DataSourceConfig();
dsConfig.setDbType(DbType.MYSQL)//设置数据库类型
.setUrl("jdbc:mysql://localhost:3306/javaEE_0228")
.setDriverName("com.mysql.jdbc.Driver")
.setUsername("root")
.setPassword("1234");
    
    
//策略配置
StrategyConfig stConfig = new StrategyConfig();
stConfig.setCapitalMode(true) // 全局大写命名
.setDbColumnUnderline(true) //表名 字段名 是否使用下滑线命名
.setNaming(NamingStrategy.underline_to_camel) // 数据库表映射到实体的命名策略   驼峰映射策略 
.setInclude("tbl_employee") //生成的表
.setTablePrefix("tbl_"); // 表前缀

//包名策略   指定生成的文件生成在哪里

PackageConfig pkConfig = new PackageConfig();
pkConfig.setParent("com.atguigu.mp")
.setController("controller")
.setEntity("beans")
.setService("service")
.setXml("mapper");

    
    
    //整合以上设定的配置
AutoGenerator ag = new AutoGenerator()
 .setGlobalConfig(config)
 .setDataSource(dsConfig)
 .setStrategy(stConfig)
 .setPackageInfo(pkConfig);
    //执行
ag.execute();

}

6.4 ServiceImpl说明

代码生成的EmployeeServiceImpl 继承了 ServiceImpl 类,mybatis-plus 通过这种方式为我们注入了 EmployeeMapper,这样可以使用 service 层默认为我们提供的很多方法,也可以调用我们自己在 dao 层编写的操作数据库的方法.

6.5更多功能

mybatis plus还有更过代码生成器的功能,自己看官方文档捣鼓吧

7 .插件扩展

7.1 Mybatis插件机制扩展

1、插件机制:

Mybatis 通过插件(Interceptor) 可以做到拦截四大对象相关方法的执行,根据需求,完成相关数据的动态改变。

  • Executor
  • StatementHandler
  • ParameterHandler
  • ResultSetHandler

2、插件原理

四大对象的每个对象在创建时,都会执行 interceptorChain.pluginAll(),会经过每个插件对象的 plugin()方法,目的是为当前的四大对象创建代理。代理对象就可以拦截到四大对象相关方法的执行,因为要执行四大对象的方法需要经过代理.

7.2 分页插件

  • com.baomidou.mybatisplus.plugins.PaginationInterceptor

以往我们的分页都是基于内存实现的,实际上是一个假分页,现在我们使用该插件实现物理分页

使用:

  1. 要想使用该插件,首先需要注册该插件。两种形式:①mybatis.xml中注册;②spring配置文件中注册

    <!--mybatis.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.plugins.PaginationInterceptor"></plugin>
        </plugins>
    </configuration>
    
    <!--spring配置文件中注册:具体位置:spring整合Mybatis的地方添加-->
    <?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"
    xmlns:mybatis-spring="http://mybatis.org/schema/mybatis-spring"
    xsi:schemaLocation="http://mybatis.org/schema/mybatis-spring 
    http://mybatis.org/schema/mybatis-spring-1.2.xsd
    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-4.0.xsd
    http://www.springframework.org/schema/tx 
    http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">
    
    <!-- 数据源 -->
    <context:property-placeholder location="classpath:db.properties"/>
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        
    <property name="driverClass" value="${jdbc.driver}"></property>
    <property name="jdbcUrl" value="${jdbc.url}"></property>
    <property name="user" value="${jdbc.username}"></property>
    <property name="password" value="${jdbc.password}"></property>
    
    </bean>
    
    <!-- 事务管理器 -->
    <bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    
    <property name="dataSource" ref="dataSource"></property>
    
    </bean>
    
    <!-- 基于注解的事务管理 -->
    <tx:annotation-driven transaction-manager="dataSourceTransactionManager"/>
    
    <!-- 配置 SqlSessionFactoryBean -->
    <bean id="sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean">
    
    <!-- 数据源 -->
    <property name="dataSource" ref="dataSource"></property>
    <property name="configLocation"  value="classpath:mybatis-config.xml"></property>
    <!-- 别名处理 -->
    <property name="typeAliasesPackage" value="com.atguigu.mp.beans"></property>
    
    <!--注册插件-->
        <property name = "plugins">
            <list>
                <bean class="com.baomidou.mybatisplus.plugins.PaginationInterceptor"></bean>                    <!--这里配置插件-->
            </list>
        </property>
    </bean>
    
    <!--配置 mybatis 扫描 mapper 接口的路径-->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        
    <property name="basePackage" 
    value="com.atguigu.mp.mapper"></property>
    
    </bean>
    
    </beans>
    
    1. 测试代码

      public class Test{
          
          ApplicationContext ac = new ClassPathXmlApplicationContext("application.xml");
          EmployeeMapper mapper = ac.getBean("employeeMapper",EmployeeMapper.class);
          
          /**
          *测试分页插件
          */
          @Test
          public void test(){
              //记得把二级缓存关闭
              List<Employee> list = mapper.selectPage(new Page<>(1,10),null);
          }
          
          
      }
      
      1. 获取分页信息

        public class Test{
            
            ApplicationContext ac = new ClassPathXmlApplicationContext("application.xml");
            EmployeeMapper mapper = ac.getBean("employeeMapper",EmployeeMapper.class);
            
            /**
            *测试分页插件
            */
            @Test
            public void test(){
                //记得把二级缓存关闭
                Page<Employee> page = new Page<>(1,10);
                List<Employee> list = mapper.selectPage(page,null);
                
                
                
                //获取总条数
                page.getTotal()
                //当前页码
                page.getCurrent()
                //总页码
                page.getPages()
                //每页显示的条数
                page.getSize()
                //是否有上一页
                page.hasPrevious()
                //是否有下一页
                page.hasNext()
                    
                    
                //将查询的结果封装到page中
                page.setRecords(list);
            }
            
            
        }
        

7.3 执行分析插件

  1. com.baomidou.mybatisplus.plugins.SqlExplainInterceptor
  2. SQL 执行分析拦截器,只支持 MySQL5.6.3 以上版本
  3. 该插件的作用是分析 DELETE UPDATE 语句,防止小白或者恶意进行 DELETE UPDATE 全表操作
  4. 只建议在开发环境中使用,不建议在生产环境使用
  5. 在插件的底层 通过 SQL 语句分析命令:Explain 分析当前的 SQL 语句,根据结果集中的 Extra 列来断定当前是否全表操作。

使用方法:

  1. 注册插件,同分页插件

    <bean class="com.baomidou.mybatisplus.plugins.SqlExplainInterceptor">
        <property name = "stopProceed" value="true"></property>
    </bean>
    
  2. 测试

    public class Test{
        
        ApplicationContext ac = new ClassPathXmlApplicationContext("application.xml");
        EmployeeMapper mapper = ac.getBean("employeeMapper",EmployeeMapper.class);
        
        /**
        *测试分页插件
        */
        @Test
        public void test(){
           mapper.delete(null);//执行全表删除  结果抛出异常,提示该操作是一个全表删除
        }
        
        
    }
    

7.4 性能分析插件

  1. com.baomidou.mybatisplus.plugins.PerformanceInterceptor
  2. 性能分析拦截器,用于输出每条 SQL 语句及其执行时间
  3. SQL 性能执行分析,开发环境使用*,*超过指定时间,停止运行。有助于发现问题。线上环境不推荐使用

使用方法:

  1. 注册插件

    <bean class=" com.baomidou.mybatisplus.plugins.PerformanceInterceptor">
        <property name = "maxTime" value="100"></property>
        <!--SQL是否格式化,默认false-->
        <property name="format" value="true"></property>
    </bean>
    
  2. 测试

    public class Test{
        
        ApplicationContext ac = new ClassPathXmlApplicationContext("application.xml");
        EmployeeMapper mapper = ac.getBean("employeeMapper",EmployeeMapper.class);
        
        /**
        *测试分页插件
        */
        @Test
        public void test(){
           //对一个插入操作惊醒分析
            Employee emp = new Employee();
            emp.setAge(22);
            emp.setLastName("名老师");
            mapper.insert(emp);//执行后查看日志,超过设定的时间抛出异常
        }
        
        
    }
    

7.5 乐观锁插件

  1. com.baomidou.mybatisplus.plugins.OptimisticLockerInterceptor

  2. 如果想实现如下需求: 当要更新一条记录的时候,希望这条记录没有被别人更新

  3. 乐观锁的实现原理:

    取出记录时,获取当前 version 2 ;更新时,带上这个 version 2 ;执行更新时, set version = yourVersion+1 where version = yourVersion

如果 version 不对,就更新失败;

  1. @Version 用于注解实体字段,必须要有。

使用方法:

@Version
private Integer version;//数据库中也要有对应字段
  1. 测试

    //数据库中id为1 的数据的version是1
    public class Test{
        
        ApplicationContext ac = new ClassPathXmlApplicationContext("application.xml");
        EmployeeMapper mapper = ac.getBean("employeeMapper",EmployeeMapper.class);
        
        /**
        *测试分页插件
        */
        @Test
        public void test(){
            Employee emp = new Employee();
            emp.setId(1);
            emp.setAge(22);
            emp.setLastName("名老师");
            emp.setVersion(1);//
            mapper.updateById(emp);//执行后,数据库中id为1 的数据的version是2;如果不对应,数据不会改变
            
        }
        
        
    }
    

8.自定义全局操作

根据 MybatisPlus 的 AutoSqlInjector 可以自定义各种你想要的 sql ,注入到全局中,相当于自定义 Mybatisplus 自动注入的方法。

之前需要在 xml 中进行配置的 SQL 语句,现在通过扩展 AutoSqlInjector 在加载 mybatis 环境时就注入。

什么意思呢?就是,如果我们要进行某个C/R/U/D操作,该操作要在映射文件中定义sql语句,但是我们想像plus中定义好的那样的形式使用,怎么办呢?就使用AutoSqlInjector

8.1 AutoSqlInjector

  1. 在 Mapper 接口中定义相关的 CRUD 方法
public interface EmployeeMapper implements BaseMapper<Employee>{
    
    
    int deleteAll();
}
  1. 扩展 AutoSqlInjector inject 方法,实现 Mapper 接口中方法要注入的 SQL

    public class MySqlInjector extends AutoSqliNJECTOR{
        /**
        *扩展Injector方法
        */
        @Override
        public void inject(Configuration configuratuion,MapperBuilderAssistant builderAssistant,Class<?> mapperClass,Class<?> modelClass,TableInfo table){
            
            //将EmployeeMapper中定义的deleteAll方法,处理成对应的MappedStatement对象,加入到configuration对象中,然后将本类注入到全局的策略中
            
            //注入的SQL语句
            String sql = "delete from "+table.getTableName();
            
            //注入的方法名
            String methodName = "deleteAll"//名字一定要和接口中定义的一致
            
            //构造sqlSource对象
            SqlSource sqlSource = languageDriver.createSqlSourec(configuratuion,sql,modelClass);//languageDriver直接用,因为继承
            
            //构造一个删除的MappedStatement对象
            this.addDeleteMappedStatement(mapperClass,methodName,sqlSource);
        }
    }
    
  2. 在 MP 全局策略中,配置 自定义注入器

    <?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"
    xmlns:mybatis-spring="http://mybatis.org/schema/mybatis-spring"
    xsi:schemaLocation="http://mybatis.org/schema/mybatis-spring 
    http://mybatis.org/schema/mybatis-spring-1.2.xsd
    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-4.0.xsd
    http://www.springframework.org/schema/tx 
    http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">
    
    <!-- 数据源 -->
    <context:property-placeholder location="classpath:db.properties"/>
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        
    <property name="driverClass" value="${jdbc.driver}"></property>
    <property name="jdbcUrl" value="${jdbc.url}"></property>
    <property name="user" value="${jdbc.username}"></property>
    <property name="password" value="${jdbc.password}"></property>
    
    </bean>
    
    <!-- 事务管理器 -->
    <bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    
    <property name="dataSource" ref="dataSource"></property>
    
    </bean>
    
    <!-- 基于注解的事务管理 -->
    <tx:annotation-driven transaction-manager="dataSourceTransactionManager"/>
    
    <!-- 配置 SqlSessionFactoryBean -->
    <bean id="sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean">
    
    <!-- 数据源 -->
    <property name="dataSource" ref="dataSource"></property>
    <property name="configLocation"  value="classpath:mybatis-config.xml"></property>
    <!-- 别名处理 -->
    <property name="typeAliasesPackage" value="com.atguigu.mp.beans"></property>
    
        
    <!-- 注入下面的全局配置策略 -->
    <property name="globalConfiguration" value="globalConfiguration"></property>
    </bean>
    
    <!--配置 mybatis 扫描 mapper 接口的路径-->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        
    <property name="basePackage" value="com.atguigu.mp.mapper"></property>
    
    </bean>
        
        
        
        
        
    <!-- 定义mybatis plus的全局策略配置 定义完该配置后,别忘了加入到spring中-->
    <bean id = "globalConfiguration" class="com.baomidou.mybatisplus.entity.GlobalConfiguration">
        <!-- 配置驼峰映射 在2.3版本以后,dbColumnUnderline的默认值就是true(表示开启)-->
    	<property name="dbColumnUnderline" value = "true"></property>
        <!--配置全局主键策略 value的值自己去看对那个的idType的枚举吧,里边讲的很详细-->
        <property name="idType" value = "0"></property>
        <!-- 全局的表格名称前缀配置   表格的名称前缀 -->
        <property name="tablePrefix" value = "tbl_"></property>
        
        
        <!--注入我们自定义的mySqlInjector-->
        <property name = "sqlInjector" ref="mySqlInjector"></property>
    </bean>
        
        
        
        <!--定义自定义全局注入器-->
        <bean class="com.xxx.xxx.MySqlInjector" id = "mySqlInjector"></bean>
        
    
    </beans>
    
    1. 测试

      public class Test{
          
          ApplicationContext ac = new ClassPathXmlApplicationContext("application.xml");
          EmployeeMapper mapper = ac.getBean("employeeMapper",EmployeeMapper.class);
          
          /**
          *测试分页插件
          */
          @Test
          public void test(){
             int a = mapper.deleteAll();//这里要把全表的删除操作关闭(执行分析插件)
          }
          
          
      }
      

8.2 自定义注入器的应之逻辑删除

假删除、逻辑删除: 并不会真正的从数据库中将数据删除掉,而是将当前被删除的这条数据中的一个逻辑删除字段置为删除状态.

tbl_user logic_flag = 1 → -1

  1. com.baomidou.mybatisplus.mapper.LogicSqlInjector

  2. logicDeleteValue 逻辑删除全局值 比如-1代表删除

  3. logicNotDeleteValue 逻辑未删除全局值 比如1代表未删除

<?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"
xmlns:mybatis-spring="http://mybatis.org/schema/mybatis-spring"
xsi:schemaLocation="http://mybatis.org/schema/mybatis-spring 
http://mybatis.org/schema/mybatis-spring-1.2.xsd
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-4.0.xsd
http://www.springframework.org/schema/tx 
http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">

<!-- 数据源 -->
<context:property-placeholder location="classpath:db.properties"/>
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
    
<property name="driverClass" value="${jdbc.driver}"></property>
<property name="jdbcUrl" value="${jdbc.url}"></property>
<property name="user" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>

</bean>

<!-- 事务管理器 -->
<bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

<property name="dataSource" ref="dataSource"></property>

</bean>

<!-- 基于注解的事务管理 -->
<tx:annotation-driven transaction-manager="dataSourceTransactionManager"/>

<!-- 配置 SqlSessionFactoryBean -->
<bean id="sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean">

<!-- 数据源 -->
<property name="dataSource" ref="dataSource"></property>
<property name="configLocation"  value="classpath:mybatis-config.xml"></property>
<!-- 别名处理 -->
<property name="typeAliasesPackage" value="com.atguigu.mp.beans"></property>

    
<!-- 注入下面的全局配置策略 -->
<property name="globalConfiguration" value="globalConfiguration"></property>
</bean>

<!--配置 mybatis 扫描 mapper 接口的路径-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    
<property name="basePackage" value="com.atguigu.mp.mapper"></property>

</bean>
    
    
    
    
    
<!-- 定义mybatis plus的全局策略配置 定义完该配置后,别忘了加入到spring中-->
<bean id = "globalConfiguration" class="com.baomidou.mybatisplus.entity.GlobalConfiguration">
    <!-- 配置驼峰映射 在2.3版本以后,dbColumnUnderline的默认值就是true(表示开启)-->
	<property name="dbColumnUnderline" value = "true"></property>
    <!--配置全局主键策略 value的值自己去看对那个的idType的枚举吧,里边讲的很详细-->
    <property name="idType" value = "0"></property>
    <!-- 全局的表格名称前缀配置   表格的名称前缀 -->
    <property name="tablePrefix" value = "tbl_"></property>
    
    
    <!--注入我们自定义的mySqlInjector-->
    <property name = "sqlInjector" ref="mySqlInjector"></property>
    
    <!--注册逻辑删除-->
    <property name="sqlInjector" ref="logicSqlInjector"></property>
    <property name="logicDeleteValue" value="-1"></property>
    <property name="logicNotDeleteValue" value="1"></property>
    
</bean>
    
    
    
    <!--定义自定义全局注入器-->
    <bean class="com.xxx.xxx.MySqlInjector" id = "mySqlInjector"></bean>
    
    <!--逻辑删除-->
    <bean id = "logicSqlInjector" class=" com.baomidou.mybatisplus.mapper.LogicSqlInjector"></bean>

</beans>
  1. 在 POJO 的逻辑删除字段 添加 @TableLogic 注解:这一步自己测试

  2. 会在 mp 自带查询和更新方法的 sql 后面,追加『逻辑删除字段』=『LogicNotDeleteValue默认值』

删除方法: deleteById()和其他 delete 方法, 底层 SQL 调用的是 update tbl_xxx set 『逻辑删除字段』=『logicDeleteValue 默认值』,查也会查询逻辑未删除的

9.公共字段自动填充

概念:插入或者修改操作的时候,有一些字段我们没有填充值,会有默认的字段

9.1元数据处理器接口

com.baomidou.mybatisplus.mapper.MetaObjectHandler;该类中有两个重要的方法:

  • insertFill(MetaObject metaObject) 插入填充
  • updateFill(MetaObject metaObject) 更新填充

这两个方法都包含metaobject对象

metaobject: 元对象。 是 Mybatis 提供的一个用于更加方便,更加优雅的访问对象的属性;给对象的属性设置值的一个对象. 还会用于包装对象. 支持对 Object 、Map、Collection等对象进行包装,本质上 metaObject 获取对象的属性值或者是给对象的属性设置值,最终是要通过 Reflector 获取到属性的对应方法的 Invoker, 最终 invoke.

9.2 开发步骤

  1. 注解填充字段 @TableFile(fill = FieldFill.INSERT) 查看 FieldFill

    假设存在这样一个实体

    public class User{
        private int id;
        private int name;
        private int age;
        @TableFile(fill = FieldFill.INSERT_UPDATE)//表示无论是插入操作还是更新操作都会设置该默认字段
        private int deleteFlag;//是否被删除,0-未删除,1-已删除,默认是0
    }
    
  2. 自定义公共字段填充处理器

    public class MyMetaObjectHandler extends MetaObjectHandler{
        
        //插入操作自动填充
        @Override
        public void insertFill(MetaObject metaObject){
            //获取需要被填充的字段的值
            Object value = getFieldValByName("deleteFlag",metaObject);
            if(value == null){//如果为空,填充
                setFieldValByName("deleteFlag","0",metaObject);
            }
        }
            //更新操作自动填充
        @Override
        public void updateFill(MetaObject metaObject){
            //获取需要被填充的字段的值
            Object value = getFieldValByName("deleteFlag",metaObject);
            if(value == null){//如果为空,填充
                setFieldValByName("deleteFlag","1",metaObject);
            }
        }
        
        
        
    }
    
  3. MP 全局注入 自定义公共字段填充处理器

    <?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"
    xmlns:mybatis-spring="http://mybatis.org/schema/mybatis-spring"
    xsi:schemaLocation="http://mybatis.org/schema/mybatis-spring 
    http://mybatis.org/schema/mybatis-spring-1.2.xsd
    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-4.0.xsd
    http://www.springframework.org/schema/tx 
    http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">
    
    <!-- 数据源 -->
    <context:property-placeholder location="classpath:db.properties"/>
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        
    <property name="driverClass" value="${jdbc.driver}"></property>
    <property name="jdbcUrl" value="${jdbc.url}"></property>
    <property name="user" value="${jdbc.username}"></property>
    <property name="password" value="${jdbc.password}"></property>
    
    </bean>
    
    <!-- 事务管理器 -->
    <bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    
    <property name="dataSource" ref="dataSource"></property>
    
    </bean>
    
    <!-- 基于注解的事务管理 -->
    <tx:annotation-driven transaction-manager="dataSourceTransactionManager"/>
    
    <!-- 配置 SqlSessionFactoryBean -->
    <bean id="sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean">
    
    <!-- 数据源 -->
    <property name="dataSource" ref="dataSource"></property>
    <property name="configLocation"  value="classpath:mybatis-config.xml"></property>
    <!-- 别名处理 -->
    <property name="typeAliasesPackage" value="com.atguigu.mp.beans"></property>
    
        
    <!-- 注入下面的全局配置策略 -->
    <property name="globalConfiguration" value="globalConfiguration"></property>
    </bean>
    
    <!--配置 mybatis 扫描 mapper 接口的路径-->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        
    <property name="basePackage" value="com.atguigu.mp.mapper"></property>
    
    </bean>
        
        
        
        
        
    <!-- 定义mybatis plus的全局策略配置 定义完该配置后,别忘了加入到spring中-->
    <bean id = "globalConfiguration" class="com.baomidou.mybatisplus.entity.GlobalConfiguration">
        <!-- 配置驼峰映射 在2.3版本以后,dbColumnUnderline的默认值就是true(表示开启)-->
    	<property name="dbColumnUnderline" value = "true"></property>
        <!--配置全局主键策略 value的值自己去看对那个的idType的枚举吧,里边讲的很详细-->
        <property name="idType" value = "0"></property>
        <!-- 全局的表格名称前缀配置   表格的名称前缀 -->
        <property name="tablePrefix" value = "tbl_"></property>
        
        
        <!--注入我们自定义的mySqlInjector-->
        <property name = "sqlInjector" ref="mySqlInjector"></property>
        
        <!--注册逻辑删除-->
        <property name="sqlInjector" ref="logicSqlInjector"></property>
        <property name="logicDeleteValue" value="-1"></property>
        <property name="logicNotDeleteValue" value="1"></property>
        
        
        <!--注入公共字段处理器-->
        <property name="metaObjectHandler" ref="myMetaObjectHandler"></property>
    </bean>
        
        
        
        <!--定义自定义全局注入器-->
        <bean class="com.xxx.xxx.MySqlInjector" id = "mySqlInjector"></bean>
        
        <!--逻辑删除-->
        <bean id = "logicSqlInjector" class=" com.baomidou.mybatisplus.mapper.LogicSqlInjector"></bean>
            
         <!--公共字段填充处理器-->
         <bean id="myMetaObjectHandler" class="com.xxx.xxx.MyMetaObjectHandler"></bean>
    </beans>
    
    1. 测试

      public class Test{
          
          ApplicationContext ac = new ClassPathXmlApplicationContext("application.xml");
          UserMapper mapper = ac.getBean("userMapper",UserMapper.class);
          
          /**
          *测试分页插件
          */
          @Test
          public void test(){
              User u = new User();
              u.setName("粑粑");
              u.setAge(1);
             int a = mapper.insert(u);//这里要把全表的删除操作关闭(执行分析插件)
          }
          
          
      }
      

10.Oracle主键Sequence

MySQL: 支持主键自增。 IdType.Auto

Oracle: 序列(Sequence)

  1. 实体类配置主键 Sequence @KeySequence(value=”序列名”,clazz=xxx.class 主键属性类型)
  2. 全局 MP 主键生成策略为 IdType.INPUT
  3. 全局 MP 中配置 Oracle 主键 Sequence

com.baomidou.mybatisplus.incrementer.OracleKeyGenerator

  1. 可以将@keySequence 定义在父类中,可实现多个子类对应的多个表公用一个 Sequence

这里笔者不会Oracle所以没有按照视频中的操作做笔记

11.idea快速开发插件

MybatisX 辅助 idea 快速开发插件,为效率而生.

可以实现 java 与 xml 跳转,根据 Mapper 接口中的方法自动生成 xml 结构.

官方安装: File -> Settings -> Plugins -> Browse Repositories… 输入 mybatisx 安装下载

Jar 安装: File -> Settings -> Plugins -> Install plugin from disk… 选中 mybatisx…jar 安装

Logo

瓜分20万奖金 获得内推名额 丰厚实物奖励 易参与易上手

更多推荐