1.MyBatis Plus简介
MyBatis-Plus 简称 MP)是一个 MyBatis的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。
2.MyBatis Plus特性
- 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
- 损耗小:启动即会自动注入基本 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 等多种数据库
- 内置全局拦截插件:提供全表 delete 、 update 操作智能分析阻断,也可自定义拦截规则,预防误操作
3.支持的数据库
任何能使用 mybatis 进行 crud, 并且支持标准 sql 的数据库
4.快速入门
4.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@qq.com',1,22);
INSERT INTO tbl_employee(last_name,email,gender,age) VALUES('Jerry','jerry@qq.com',0,25);
INSERT INTO tbl_employee(last_name,email,gender,age) VALUES('Black','black@qq.com',1,30);
INSERT INTO tbl_employee(last_name,email,gender,age) VALUES('White','white@qq.com',0,35);
4.2 创建JavaBean
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Employee {
private Integer id;
private String lastName;
private String email;
private Integer gender;
private Integer age;
}
4.3 依赖配置
Mybatis 及 Mybatis-Spring 依赖请勿加入项目配置,以免引起版本冲突,Mybatis-Plus 会自动帮你维护!
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!--spring-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.19.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.0.19.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>5.0.19.RELEASE</version>
</dependency>
<!--mybatis plus-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus</artifactId>
<version>3.4.1</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>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.23</version>
</dependency>
<!--mysql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.36</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.10</version>
</dependency>
</dependencies>
4.4 MyBatis配置文件: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>
</configuration>
4.5 日志配置文件: log4j.properties
log4j.logger.com.ibatis=DEBUG
log4j.logger.com.ibatis.common.jdbc.SimpleDataSource=DEBUG
log4j.logger.com.ibatis.common.jdbc.ScriptRunner=DEBUG
log4j.logger.com.ibatis.sqlmap.engine.impl.SqlMapClientDelegate=DEBUG
4.6 数据库配置文件:jdbc.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mp
jdbc.username=root
jdbc.password=root
4.7 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="cn.edu.mp.mapper"></property>
</bean>
</beans>
4.8 测试环境搭建
//搭建Spring测试环境
// 前提(依赖引入):1.junit 4.12以上版本 2.spring-test 与spring-context相同版本即可
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class MyTest {
}
4.9 测试环境搭建
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class MyTest {
@Autowired
private DataSource dataSource;
@Test
public void test1() throws SQLException {
Connection connection = dataSource.getConnection();
System.out.println("==>" + connection);
}
}
4.10 集成MP
Mybatis-Plus 的集成非常简单,对于 Spring,我们仅仅需要把 Mybatis 自带MybatisSqlSessionFactoryBean 替换为 MP 自带的即可。
<!--applicationContext.xml-->
<bean id="sqlSessionFactory" class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="typeAliasesPackage" value="cn.edu.pojo"/>
<!--<property name="configLocation" value="classpath:mybatis-config.xml"/>-->
</bean>
4.11 配置日志
目的:查看sql语言是如何执行
<!--applicationContext.xml-->
<bean id="sqlSessionFactory" class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="typeAliasesPackage" value="cn.edu.pojo"/>
<!--<property name="configLocation" value="classpath:mybatis-config.xml"/>-->
<property name="configuration" ref="configuration"/>
</bean>
<!--mybatis plus日志-->
<bean id="configuration" class="com.baomidou.mybatisplus.core.MybatisConfiguration">
<property name="logImpl" value="org.apache.ibatis.logging.stdout.StdOutImpl"/>
</bean>
5.MyBatis Plus自带的Mapper CRUD接口
EmployeeMapper继承BaseMapper<>
<>中实体类名
@Repository
public interface EmployeeMapper extends BaseMapper<Employee> {
}
- 注解@TableName: 表名注解
- 体类与数据库表对应,若表名与实体类名相同,则value不需要书写,若不一致,则需要写进表名
- 注解@TableId:主键注解
- value指定主键名,type指主键生成策略
- 若实体类的属性名与表中相同,则可以省略
- 注解@TableField:字段注解(非主键)
- value指定字段名,若实体类属性与表名相同,或符合驼峰规则都可省略
@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName(value = "tbl_employee")
public class Employee {
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
@TableField("last_name")
private String lastName;
private String email;
private Integer gender;
private Integer age;
5.1 插入操作
- int insert(T entity); // 插入一条记录,并实现主键回填
@Test
public void testCommonInsert() {
Employee employee = new Employee();
employee.setLastName("黄药师");
employee.setEmail("hys@qq.com");
employee.setGender(1);
int result = employeeMapper.insert(employee);
System.out.println("==>" + result);
System.out.println(employee.getId())
}
5.2 更新操作
- int updateById(@Param(Constants.ENTITY) T entity); // 根据 ID 修改
@Test
public void testUpdate() {
Employee employee = new Employee();
employee.setId(1);
employee.setLastName("杨康");
employee.setGender(1);
int result = employeeMapper.updateById(employee);
System.out.println("==>" + result);
}
5.3 查询操作
-T selectById(Serializable id); //根据 ID 查询
- List selectBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList); //查询(根据ID 批量查询
- List selectByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap); //查询(根据 columnMap 条件)
- List selectList(@Param(Constants.WRAPPER) Wrapper queryWrapper); // 根据 entity 条件,查询全部记录
@Test
public void testQuery() {
/*
//1.根据id查询
Employee employee = employeeMapper.selectById(1);
System.out.println(employee);
*/
/*
//2.查询(根据ID 批量查询)
List<Integer> idList = new ArrayList<>();
for (int i = 1; i < 5; i++) {
idList.add(i);
}
List<Employee> employeeList = employeeMapper.selectBatchIds(idList);
employeeList.forEach((temp) -> {
System.out.println(temp);
});
*/
/*
//3.查询(根据 columnMap 条件)
HashMap<String, Object> columnMap = new HashMap<>();
columnMap.put("gender", "0");
List<Employee> employees = employeeMapper.selectByMap(columnMap);
employees.forEach((temp) -> {
System.out.println(temp);
});
*/
//4.
List<Employee> employees = employeeMapper.selectList(null);
employees.forEach((temp) -> {
System.out.println(temp);
});
}
5.4 删除操作
- int deleteById(Serializable id); //根据 ID 删除
- int deleteBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList); //删除(根据ID 批量删除)
- int deleteByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap); //根据 columnMap 条件,删除记录
@Test
public void testDelete() {
/*
//1.根据id批量删除
List<Integer> ids = new ArrayList<>();
for (int i = 8; i < 31; i++) {
ids.add(i);
}
int result = employeeMapper.deleteBatchIds(ids);
System.out.println(result);
*/
//2.根据id删除
int result = employeeMapper.deleteById(1);
System.out.println(result);
/*
//3.根据 columnMap 条件,删除记录
Map<String, Object> columnMap = new HashMap<>();
columnMap.put("email", "ouyangfeng@.com");
columnMap.put("gender", "1");
int result = employeeMapper.deleteByMap(columnMap);
System.out.println(result);
*/
}
6.扩展
6.1自动填充功能
目的:创建时间、修改时间实现自动更新,而非手动更新
方法一:数据库实现(不推荐)
- 在数据库中创建create_time,update_time字段
- 设置默认值:CURRENT_TIMESTAMP
- 在实体类Employee类中添加属性createTime,updateTime
方法二:MyBatis Plus实现
1).在实体类Employee类中添加属性createTime,updateTime及注解
//注解@TableField():字段自动填充策略
@TableField(fill = FieldFill.INSERT)
private Date createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updateTime;
2).编写处理器来处理这个注解即可!
public class MyMetaObjectHandler implements MetaObjectHandler {
//插入填充策略
@Override
public void insertFill(MetaObject metaObject) {
System.out.println("==>自动填充策略:insertFill");
this.setFieldValByName("createTime", new Date(), metaObject);
this.setFieldValByName("updateTime", new Date(), metaObject);
}
// 更新时填充策略
@Override
public void updateFill(MetaObject metaObject) {
System.out.println("==>自动填充策略:updateFill");
this.setFieldValByName("updateTime", new Date(), metaObject);
}
}
3).添加到配置文件中
<!--applicationContext.xml-->
<bean id="sqlSessionFactory" class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="typeAliasesPackage" value="cn.edu.pojo"/>
<!--<property name="configLocation" value="classpath:mybatis-config.xml"/>-->
<property name="configuration" ref="configuration"/>
<property name="globalConfig" ref="globalConfig"/>
</bean>
<!--MyBatisPlus全局声明-->
<bean id="globalConfig" class="com.baomidou.mybatisplus.core.config.GlobalConfig">
<property name="metaObjectHandler">
<!--自动填充策略-->
<bean id="myMetaObjectHandler" class="cn.edu.config.MyMetaObjectHandler"/>
</property>
</bean>
4)测试即可
6.2 逻辑删除
物理删除:从数据库中真是删除
逻辑删除:不是真实从数据库中删除,而是逻辑上的删除
目的==>管理员查看删除记录,防止数据丢失,犹如电脑的回收站
1)在数据库中添加字段deleted,并设置默认值为0
2)注册组件
<!--applicationContext.xml-->
<bean id="sqlSessionFactory" class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="typeAliasesPackage" value="cn.edu.pojo"/>
<!--<property name="configLocation" value="classpath:mybatis-config.xml"/>-->
<property name="configuration" ref="configuration"/>
<property name="globalConfig" ref="globalConfig"/>
<property name="plugins">
<array>
<ref bean="plugins"/>
</array>
</property>
</bean>
<!--MyBatisPlus全局声明-->
<bean id="globalConfig" class="com.baomidou.mybatisplus.core.config.GlobalConfig">
<property name="dbConfig">
<bean class="com.baomidou.mybatisplus.core.config.GlobalConfig$DbConfig">
<property name="logicDeleteValue" value="1"/>
<property name="logicNotDeleteValue" value="0"/>
</bean>
</property>
</bean>
3)测试:
==>实际上执行的是update操作
7.插件
7.1 乐观锁
简介:无论怎样,它都认为没有问题,因此不上锁。
乐观锁实现方式:
- 取出记录时,获取当前version
- 更新时,带上这个version
- 执行更新时, set version = newVersion where version = oldVersion
- 如果version不对,就更新失败
1)在数据库中添加version字段,并设置默认值为1
2)实体类添加version属性
//注解@Version:乐观锁
@Version
private Integer version;
3)注册组件
<!--applicationContext.xml-->
<bean id="sqlSessionFactory" class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="typeAliasesPackage" value="cn.edu.pojo"/>
<!--<property name="configLocation" value="classpath:mybatis-config.xml"/>-->
<property name="configuration" ref="configuration"/>
<property name="globalConfig" ref="globalConfig"/>
<property name="plugins">
<array>
<ref bean="plugins"/>
</array>
</property>
</bean>
<!--MyBatisPlus插件-->
<bean id="plugins" class="com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor">
<property name="interceptors">
<array>
<!--乐观锁-->
<bean class="com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor"/>
</array>
</property>
</bean>
4)测试
@Test
public void testOptimisticLocker2() {
Employee employee = employeeMapper.selectById(1);
employee.setLastName("杨二111");
employee.setAge(23);
Employee employee2 = employeeMapper.selectById(1);
employee2.setLastName("杨二222");
employee2.setAge(23);
employeeMapper.updateById(employee2);
employeeMapper.updateById(employee);
}
7.2 分页
1)注册组件
<!--applicationContext.xml-->
<bean id="sqlSessionFactory" class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="typeAliasesPackage" value="cn.edu.pojo"/>
<!--<property name="configLocation" value="classpath:mybatis-config.xml"/>-->
<property name="configuration" ref="configuration"/>
<property name="globalConfig" ref="globalConfig"/>
<property name="plugins">
<array>
<ref bean="plugins"/>
</array>
</property>
</bean>
<!--MyBatisPlus插件-->
<bean id="plugins" class="com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor">
<property name="interceptors">
<array>
<!--分页插件-->
<bean class="com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor"/>
</array>
</property>
</bean>
2)测试
@Test
public void testPage() {
Page<Employee> page = new Page<>(1, 5);
employeeMapper.selectPage(page, null);
page.getRecords().forEach(System.out::println);
System.out.println(page.getTotal());
System.out.println(page.getCurrent());
}