您的位置:首页 > 其它

Mybatis Plus快速入门

2020-07-16 05:49 113 查看

Mybatis Plus的使用

老规矩,先看官网,通过官网我们就能够系统的学好Mybatis-Plus:https://mp.baomidou.com/

一、概念

MyBatis-Plus(简称 MP)是一个 MyBatis的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。

特性:

  • 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
  • 损耗小:启动即会自动注入基本 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 操作智能分析阻断,也可自定义拦截规则,预防误操作

二、mybatis-plus环境搭建

1、添加pom依赖

<?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>org.example</groupId>
<artifactId>mybatis_plus_0703</artifactId>
<version>1.0-SNAPSHOT</version>

<dependencies>

<!-- https://mvnrepository.com/artifact/com.baomidou/mybatis-plus -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus</artifactId>
<version>3.3.1</version>
</dependency>
<!--其他的与平时没什么区别,主要是添加这个mybatis-plus的支持-->

<!-- https://mvnrepository.com/artifact/junit/junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/log4j/log4j -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.21</version>
</dependency>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.19</version>
</dependency>

<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.3.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-orm -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>5.2.3.RELEASE</version>
</dependency>

</dependencies>

</project>

2、创建Dao接口

/**
* 使用Mybatis-plus的时候,dao层接口只需要继承mybatis-plus提供的BaseMapper接口即可
* 无需在resource目录下通过xml文件对sql语句进行实现
*/
//使用@Mapper注解,使Spring能够扫描此接口
@Mapper
public interface EmpDao extends BaseMapper<Emp> {
}

3、编写各类配置文件

db.properties

jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/demo?serverTimezone=UTC
jdbc.username=root
jdbc.password=123456

log4j.properties

# 全局日志配置
log4j.rootLogger=ERROR, stdout
# MyBatis 日志配置
log4j.logger.com.mjt=TRACE
# 控制台输出
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

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

<!--因为是Spring整合Mybatis,所以mybatis配置文件中什么都不需要写-->
<configuration>

</configuration>

spring.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
https://www.springframework.org/schema/tx/spring-tx.xsd">

<!--spring中整合mybatis,我们在前面已经学习过,这里简单复习怎么配置-->

<!--引入外部配置文件-->
<context:property-placeholder location="db.properties"></context:property-placeholder>

<!--定义注解的包扫描路径-->
<context:component-scan base-package="com.mjt"></context:component-scan>

<!--配置数据源-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
<property name="driverClassName" value="${jdbc.driver}"></property>
<property name="url" value="${jdbc.url}"></property>
</bean>

<!--与数据库相关,需要配置事务-->
<!--添加事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>

<!--添加事务注解配置-->
<tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>

<!--整合spring和mybatis-->
<!--注意此处是使用Mybatis-plus的MybatisSqlSessionFactoryBean-->
<bean id="sqlSessionFactoryBean" class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean">

<property name="dataSource" ref="dataSource"></property>
<!--整合mybatis-->
<property name="configLocation" value="classpath:mybatis.xml"></property>
</bean>

<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.mjt.dao"></property>
</bean>
</beans>

4、进行单元测试

public class MyTest {
ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");

@Test
public void MyTest01(){
EmpDao empDao = context.getBean("empDao", EmpDao.class);
List<Emp> emps = empDao.selectList(null);
for (Emp emp : emps) {
System.out.println(emp);//能够输出数据库表信息
}

}
}

我们发现在Dao接口中我们并没有定义增删改查方法,也没有在mapper代理中进行sql语句的实现,那么是怎么执行的sql语句呢?也就是说,是在哪里对基本的增删改查sql语句进行实现呢?

我们查看Dao接口,发现接口只是继承了BaseMapper接口:

/**
* 使用Mybatis-plus的时候,dao层接口只需要继承mybatis-plus提供的BaseMapper接口即可
* 无需在resource目录下通过xml文件对sql语句进行实现
*/
//使用@Mapper注解,使Spring能够扫描此接口
@Mapper
public interface EmpDao extends BaseMapper<Emp> {
}

我们查看此BaseMapper接口源码:

BaseMapper

public interface BaseMapper<T> extends Mapper<T> {
int insert(T entity);

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

int updateById(@Param("et") T entity);

int update(@Param("et") T entity, @Param("ew") Wrapper<T> updateWrapper);

T selectById(Serializable id);

List<T> selectBatchIds(@Param("coll") Collection<? extends Serializable> idList);

List<T> selectByMap(@Param("cm") Map<String, Object> columnMap);

T selectOne(@Param("ew") Wrapper<T> queryWrapper);

Integer selectCount(@Param("ew") Wrapper<T> queryWrapper);

List<T> selectList(@Param("ew") Wrapper<T> queryWrapper);

List<Map<String, Object>> selectMaps(@Param("ew") Wrapper<T> queryWrapper);

List<Object> selectObjs(@Param("ew") Wrapper<T> queryWrapper);

<E extends IPage<T>> E selectPage(E page, @Param("ew") Wrapper<T> queryWrapper);

<E extends IPage<Map<String, Object>>> E selectMapsPage(E page, @Param("ew") Wrapper<T> queryWrapper);
}

我们可以发现Mybatis-plus提供的BaseMapper接口,定义了基本的增删改查对应的方法,然后通过代理进行了基本的SQL语句的实现

三、简单的CRUD

如果我们下面要实现CRUD的基本操作,那么我们该如何实现呢?

在Mybatis中,我们需要编写对应的Dao接口,并在接口中定义相关的方法,然后提供与该接口相同名称的Dao.xml文件,在文件中填写对应的sql语句,才能完成对应的操作

在Mybatis-plus中,我们只需要定义接口,然后继承BaseMapper类即可,此前做的所有操作都是由Mybatis-plus来帮我们完成,不需要创建sql映射文件

EmpDao.java

/**
* 在mybatis操作的时候,我们需要自己定义接口中实现的方法,并添加与之对应的EmpDao.xml文件,编写对应的sql语句
* 在mybatis-plus操作的时候,我们只需要继承BaseMapper接口即可,其中的泛型T表示我们要实际操作的实体类对象
*/
public interface EmpDao extends BaseMapper<Emp> {
}

1、插入操作

MyTest.java

public class MyTest {

ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");

private EmpDao empDao = context.getBean("empDao",EmpDao.class);

@Test
public void testInsert(){
Emp emp = new Emp();
emp.seteName("zhangsan");
emp.setJob("Teacher");
emp.setMgr(100);
emp.setSal(1000.0);
emp.setComm(500.0);
emp.setHiredate(new Date());
emp.setDeptno(10);
int insert = empDao.insert(emp);
System.out.println(insert);
}
}

当运行上述代码的时候,大家发现报错了,原因在于你写的实体类的名称跟表的名称不匹配,因此在实现的是需要添加@TableName注解,指定具体的表的名称

@TableName("emp")
public class Emp {//省略内容}

上述代码运行通过之后,大家会发现结果能够正常的进行插入,但是在控制台会打印一个警告信息,说没有@TableId的注解,原因就在于定义实体类的时候并没有声明其中的主键是哪个列,以及使用什么样的主键生成策略,因此,可以在类的属性上添加如下注解,来消除此警告

public class Emp {

@TableId(value = "empno",type = IdType.AUTO)
private Integer empno;
private String eName;
private String job;
private Integer mgr;
private Date hiredate;
private Double sal;
private Double comm;
private Integer deptno;
//set、get、tostring方法省略
}

大家其实可以看到我们在插入的时候,mybatis-plus会根据我会输入的对象的字段的个数来动态的调整我们的sql语句插入的字段,这是大家需要注意的mybatis-plus比较灵活的地方。

2、更新操作

@Test
public void testUpdate(){
Emp emp = new Emp();
emp.setEmpno(1);
emp.seteName("lisi");
emp.setJob("student");
emp.setMgr(100);
emp.setSal(1000.0);
emp.setComm(500.0);
emp.setHiredate(new Date());
emp.setDeptno(10);
int update = empDao.updateById(emp);
System.out.println(update);
}

3、删除操作

@Test
public void testDelete(){
// 1、根据id删除数据
//        int i = empDao.deleteById(1);
//        System.out.println(i);

// 2、根据一组id删除数据
//        int i = empDao.deleteBatchIds(Arrays.asList(2, 3, 4));
//        System.out.println(i);

// 3、根据条件删除数据
//        QueryWrapper queryWrapper = new QueryWrapper();
//        queryWrapper.in("empno",Arrays.asList(5,6,7));
//        int delete = empDao.delete(queryWrapper);
//        System.out.println(delete);

// 4、条件封装map删除数据
Map<String,Object> map = new HashMap<>();
map.put("empno",9);
int i = empDao.deleteByMap(map);
System.out.println(i);
}

4、查询操作

@Test
public void testselect(){

// 1、根据id查询对象
//        Emp emp = empDao.selectById(1);
//        System.out.println(emp);

// 2、根据实体包装类查询单个对象,返回的结果集有且仅能有一个对象
//        QueryWrapper<Emp> emp = new QueryWrapper<Emp>();
//        emp.eq("empno",2).eq("e_name","zhangsan");
//        Emp emp1 = empDao.selectOne(emp);
//        System.out.println(emp1);

// 3、通过多个id值进行查询
//        List<Emp> list = empDao.selectBatchIds(Arrays.asList(1, 2, 3));
//        for (Emp emp : list) {
//            System.out.println(emp);
//        }

// 4、通过map封装进行条件查询
//        Map<String,Object> map = new HashMap<String, Object>();
//        map.put("e_name","zhangsan");
//        map.put("sal",1000.0);
//        List<Emp> list = empDao.selectByMap(map);
//        for (Emp emp : list) {
//            System.out.println(emp);
//        }

// 5、分页查询,需要添加分页插件
/**
* <property name="plugins">
*             <array>
*                 <bean class="com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor"></bean>
*             </array>
*         </property>
*/

// Page<Emp> empPage = empDao.selectPage(new Page<>(2, 5), null);
// List<Emp> records = empPage.getRecords();
// System.out.println(records);

// 6、根据条件返回查询结果总数
//        QueryWrapper<Emp> queryWrapper = new QueryWrapper<>();
//        queryWrapper.eq("e_name","zhangsan");
//        Integer integer = empDao.selectCount(queryWrapper);
//        System.out.println(integer);

// 7、根据条件查询所有结果返回list集合
//        List<Emp> list = empDao.selectList(null);
//        for (Emp emp : list) {
//            System.out.println(emp);
//        }

// 8、根据条件查询结果封装成map的list结构
//        List<Map<String, Object>> maps = empDao.selectMaps(null);
//        System.out.println(maps);
}

四、Mybatis-plus配置文件

在mybatis中我们可以在mybatis-config配置文件中可以添加标签,设置全局的默认策略,在Mybatis-plus中也具备相同的功能,只不过配置方式有所不同,我们可以在spring.xml文件中添加配置,如果你对Mybatis配置文件的配置比较熟悉,那么理解Mybatis-plus配置文件也不会很难。

比如驼峰规则—mapUnderscoreToCamelCase、开启二级缓存—cacheEnabled、指定Mybatis配置文件的路径—configLocation、MyBatis Mapper 所对应的 XML 文件位置—mapperLocations、MyBaits 别名包扫描路径—typeAliasesPackage…等等

Mybatis-plus官网配置文件详解:https://mp.baomidou.com/config/

在此链接中包含了非常多的配置项,我们可以按照自己的需求添加需要的配置,在这里就不再通过代码演示了。

补充:以下内容一般来说用不太到(尤其对于新手来说),简单了解即可。如果某块业务逻辑用到了,再针对性的学习即可

五、插件扩展

MyBatis 允许你在映射语句执行过程中的某一点进行拦截调用。默认情况下,MyBatis 允许使用插件来拦截的方法调用包括:

  • Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
  • ParameterHandler (getParameterObject, setParameters)
  • ResultSetHandler (handleResultSets, handleOutputParameters)
  • StatementHandler (prepare, parameterize, batch, update, query)

1、分页插件

在spring.xml文件中添加如下配置引入插件

<property name="plugins">
<array>
<bean class="com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor"></bean>
</array>
</property>

编写测试类

@Test
public void TestPage(){
Page page = new Page(2,2);
Page page1 = empDao.selectPage(page, null);
List records = page1.getRecords();
for (Object record : records) {
System.out.println(record);
}
System.out.println("==============");
System.out.println("获取总条数:"+page.getTotal());
System.out.println("当前页码:"+page.getCurrent());
System.out.println("总页码:"+page.getPages());
System.out.println("每页显示的条数:"+page.getSize());
System.out.println("是否有上一页:"+page.hasPrevious());
System.out.println("是否有下一页:"+page.hasNext());
}

2、乐观锁插件

当要更新一条记录的时候,希望这条记录没有被别人更新

乐观锁实现方式:

取出记录时,获取当前version
更新时,带上这个version
执行更新时, set version = newVersion where version = oldVersion
如果version不对,就更新失败

添加配置:

<bean class="com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor"></bean>

修改实体类添加version字段并在表中添加version字段

编写测试类

@Test
public void testOptimisticLocker(){
Emp emp = new Emp();
emp.setEmpno(22);
emp.seteName("zhang");
emp.setSal(10000.0);
emp.setComm(1000.0);
emp.setVersion(2);
empDao.updateById(emp);
}

3、SQL执行分析插件,避免出现全表更新和删除

<bean class="com.baomidou.mybatisplus.extension.plugins.SqlExplainInterceptor">
<property name="sqlParserList">
<list>
<bean class="com.baomidou.mybatisplus.extension.parsers.BlockAttackSqlParser"></bean>
</list>
</property>
</bean>
@Test
public void testSqlExplain(){
int delete = empDao.delete(null);
System.out.println(delete);
}

4、非法sql检查插件

<bean class="com.baomidou.mybatisplus.extension.plugins.IllegalSQLInterceptor">
</bean>
@Test
public void testSqlIllegal(){
QueryWrapper<Emp> queryWrapper = new QueryWrapper<>();
queryWrapper.or();
List<Emp> list = empDao.selectList(queryWrapper);
for (Emp emp : list) {
System.out.println(emp);
}
}

六、SQL注入器

​ 全局配置

sqlInjector
用于注入
ISqlInjector
接口的子类,实现自定义方法注入。也就是说我们可以将配置在xml中的文件使用注入的方式注入到全局中,就不需要再编写sql语句

自定义注入器

import com.baomidou.mybatisplus.core.injector.AbstractMethod;
import com.baomidou.mybatisplus.core.injector.AbstractSqlInjector;

import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class MyInjector extends  AbstractSqlInjector{

@Override
public List<AbstractMethod> getMethodList(Class<?> mapperClass) {
return Stream.of(new DeleteAll()).collect(Collectors.toList());
}
}

添加配置:

<bean id="globalConfig" class="com.baomidou.mybatisplus.core.config.GlobalConfig">
<property name="dbConfig" ref="dbConfig"></property>
<property name="sqlInjector" ref="myinject"></property>
</bean>
<bean id="myinject" class="com.mjt.injector.MyInjector"></bean>
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;

public class DeleteAll extends AbstractMethod {
@Override
public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
String sql;
MySqlMethod mySqlMethod = MySqlMethod.DELETE_ALL;
if (tableInfo.isLogicDelete()) {
sql = String.format(mySqlMethod.getSql(), tableInfo.getTableName(),  tableInfo,
sqlWhereEntityWrapper(true,tableInfo));
} else {
mySqlMethod = MySqlMethod.DELETE_ALL;
sql = String.format(mySqlMethod.getSql(), tableInfo.getTableName(),
sqlWhereEntityWrapper(true,tableInfo));
}
SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql, modelClass);
return addUpdateMappedStatement(mapperClass, modelClass, mySqlMethod.getMethod(), sqlSource);
}
}
/**
* 自定义全局删除方法
*/

public enum MySqlMethod {

/**
* 删除全部
*/
DELETE_ALL("deleteAll", "根据 entity 条件删除记录", "<script>\nDELETE FROM %s %s\n</script>");

private final String method;
private final String desc;
private final String sql;

MySqlMethod(String method, String desc, String sql) {
this.method = method;
this.desc = desc;
this.sql = sql;
}

public String getMethod() {
return method;
}

public String getDesc() {
return desc;
}

public String getSql() {
return sql;
}

}
/**
* 在mybatis操作的时候,我们需要自己定义接口中实现的方法,并添加与之对应的EmpDao.xml文件,编写对应的sql语句
* 在mybatis-plus操作的时候,我们只需要继承BaseMapper接口即可,其中的泛型T表示我们要实际操作的实体类对象
*/
public interface EmpDao extends BaseMapper<Emp> {
Integer deleteAll();
}

七、公共字段填充

  • 实现元对象处理器接口:com.baomidou.mybatisplus.core.handlers.MetaObjectHandler

  • 注解填充字段

    @TableField(.. fill = FieldFill.INSERT)
    生成器策略部分也可以配置!

    metaobject:元对象,是mybatis提供的一个用于更加方便,更加优雅的访问对象的属性,给对象的属性设置值的一个对象,还会用于包装对象,支持Object,Map,Collection等对象进行包装。本质上metaobject是给对象的属性设置值,最终还是要通过Reflect获取到属性的对应方法的invoker,最终执行。

编写自定义的公共字段填充

public class MyMetaObjectHandler implements MetaObjectHandler {

@Override
public void insertFill(MetaObject metaObject) {
this.strictInsertFill(metaObject, "eName", String.class, "lian"); // 起始版本 3.3.0(推荐使用)
//        this.fillStrategy(metaObject, "createTime", LocalDateTime.now()); // 也可以使用(3.3.0 该方法有bug请升级到之后的版本如`3.3.1.8-SNAPSHOT`)
}

@Override
public void updateFill(MetaObject metaObject) {
this.strictUpdateFill(metaObject, "eName", String.class,"lian"); // 起始版本 3.3.0(推荐使用)
//        this.fillStrategy(metaObject, "updateTime", LocalDateTime.now()); // 也可以使用(3.3.0 该方法有bug请升级到之后的版本如`3.3.1.8-SNAPSHOT`)
}
}

添加到对应的配置中:

<bean id="globalConfig" class="com.baomidou.mybatisplus.core.config.GlobalConfig">
<property name="dbConfig" ref="dbConfig"></property>
<property name="metaObjectHandler" ref="myMeta"></property>
</bean>
<bean id="myMeta" class="com.mjt.fill.MyMetaObjectHandler"></bean>

测试:

@Test
public void testMeta(){
int insert = empDao.insert(new Emp());
System.out.println(insert);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: