Mybatis-Plus 02
配置
MybatisPlus:
特性:
1.无侵入: 只做增强,不做改变,不会对现有工程产生影响
2.损耗小: 启动即会自动注入基本CURD,性能基本无损耗
3.强大的CURD操作,内置通用Mapper,通用Service,少量配置即可实现大部分的CURD操作,更有强大的条件构造器,满足各类需求
4.支持主键自动生成: 支持4种主键策略
5.内置分页插件:基于mybatis物理分页
6.内置代码生成器:采用代码或者Maven插件可以快速生成Mapper,Service,Model,Controller层代码
依赖:
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus</artifactId>
<version>3.4.3.1</version>
</dependency>
spring.xml 配置文件:
<!--spring整合mybatis-plus-->
<bean id="sqlSessionFactory" class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="typeAliasesPackage" value="com.sin.entity"/>
</bean>
实体类:
@Data//自动生成set/get等方法
@AllArgsConstructor//生成全参构造
@NoArgsConstructor//无参构造
@TableName("emp")//这个实体类对应的表
public class Emp {
@TableId(type = IdType.AUTO)//操纵数据库主键自增
private Integer empno;
//员工姓名
private String ename;
//职位
private String job;
//领导
private Integer mgr;
//入职时间
private Date hiredate;
//工资
private Double sal;
//部门编号
private Integer deptno;
//奖金
private Double comm;
}
mapper层:
public interface EmpMapper extends BaseMapper<Emp> {
}
service层:
public interface EmpService extends IService<Emp> {
}
serviceImpl实现类:
@Service
public class EmpServiceImpl extends ServiceImpl<EmpMapper, Emp> implements EmpService {
}
测试类:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:spring.xml")
public class TestEmp {
@Autowired
private EmpService empService;
@Test
public void testGetAllEmpList(){
List<Emp> list = empService.list();
for (Emp emp : list) {
System.out.println(emp);
}
}
}
补充:
1.classpath:target->classes下面的路径
2.bean:
1.所有的实体类
2.所有的java类
@Data 注解 //自动生成set/get等方法
依赖:
<!--get/set-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.0</version>
</dependency>
加在实体类上
@Data//自动生成set/get等方法
@AllArgsConstructor//生成全参构造
@NoArgsConstructor//无参构造
介绍
- ActiveRecord
- Mybatis-Plus的插件
- Sql 注入器实现自定义全局操作
- 自动填充功能
- 逻辑删除
- 代码生成器
- MybatisX 快速开发插件
文章目录
1、ActiveRecord
ActiveRecord(简称AR)一直广受动态语言( PHP 、 Ruby 等)的喜爱,而 Java 作为准静态语言,对于 ActiveRecord 往往只能感叹其优雅,所以我们也在 AR 道路上进行了一定的探索,希望大家能够喜欢。
什么是ActiveRecord?
ActiveRecord也属于ORM(对象关系映射)层,由Rails最早提出,遵循标准的ORM模型:表映射到记录,记录映射到对象,字段映射到对象属性。配合遵循的命名和配置惯例,能够很大程度的快速实现模型的操作,而且简洁易懂。
ActiveRecord的主要思想是:
- 每一个数据库表对应创建一个类,类的每一个对象实例对应于数据库中表的一行记录;通常表的每个字段在类中都有相应的Field;
- ActiveRecord同时负责把自己持久化,在ActiveRecord中封装了对数据库的访问,即CURD;;
- ActiveRecord是一种领域模型(Domain Model),封装了部分业务逻辑;
1.1、开启AR之旅
在MP中,开启AR非常简单,只需要将实体对象继承Model即可。
package com.test.pojo;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 用户实体类
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@TableName("tb_user")
public class User extends Model<User> {
//指定id类型为使用分布式ID生成器生成
@TableId(type = IdType.ID_WORKER)
private Long id;
private String userName;
//密码字段不应该被查询出来
@TableField(select = false)
private String password;
private String name;
private Integer age;
//表中字段名和实体类属性名不一致
@TableField(value = "email")
private String mail;
//表中不存在这个字段
@TableField(exist = false)
private String address;
}
1.2、根据主键查询
package com.test.test.ar;
import com.test.pojo.User;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
/**
* AR模式测试
*/
@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTest {
@Test
public void testAR() {
User user = new User();
user.setId(2L);
User userResult = user.selectById();
System.out.println(userResult);
}
}
1.3、新增数据
package com.test.test.ar;
import com.test.pojo.User;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
/**
* AR模式测试
*/
@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTest {
@Test
public void testARInsert() {
User user = new User();
user.setName("混沌");
user.setAge(30);
user.setPassword("123456");
user.setUserName("hundun");
user.setMail("hundun@1000phone.com");
boolean insert = user.insert();
System.out.println(insert);
}
}
1.4、更新操作
package com.test.test.ar;
import com.test.pojo.User;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
/**
* AR模式测试
*/
@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTest {
@Test
public void testARUpdate() {
User user = new User();
user.setId(4L);
user.setAge(32);
boolean update = user.updateById();
System.out.println(update);
}
}
1.5、删除操作
package com.test.test.ar;
import com.test.pojo.User;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
/**
* AR模式测试
*/
@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTest {
@Test
public void testARDelete() {
User user = new User();
user.setId(1352412605444091909L);
boolean delete = user.deleteById();
System.out.println(delete);
}
}
1.6、根据条件查询
package com.test.test.ar;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.test.pojo.User;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.List;
/**
* AR模式测试
*/
@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTest {
@Test
public void testARSelectList() {
User user = new User();
QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
userQueryWrapper.ge("age","20");
List<User> users = user.selectList(userQueryWrapper);
for (User user1 : users) {
System.out.println(user1);
}
}
}
2、插件
2.4、乐观锁插件
2.4.1、主要适用场景
意图:
当要更新一条记录的时候,希望这条记录没有被别人更新
乐观锁实现方式:
- 取出记录时,获取当前version
- 更新时,带上这个version
- 执行更新时, set version = newVersion where version = oldVersion
- 如果version不对,就更新失败
2.4.2、插件配置
spring xml:
<bean class="com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor"/>
spring boot启动类加入下面代码, 乐观锁配置 :
/**
* 乐观锁插件
*/
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
return new OptimisticLockerInterceptor();
}
2.4.3、注解实体字段
需要为实体字段添加@Version注解。
- 第一步,为表添加version字段,并且设置初始值为1:
ALTER TABLE `tb_user`
ADD COLUMN `version` int(10) NULL AFTER `email`;
UPDATE `tb_user` SET `version`='1';
- 第二步,为User实体对象添加version字段,并且添加@Version注解:
@Version
private Integer version;
2.4.4、测试
测试用例:
@Test
public void testUpdate(){
User user = new User();
user.setAge(30);
user.setId(2L);
user.setVersion(1); //获取到version为1
int result = userMapper.updateById(user);
System.out.println("result = " + result);
}
执行日志:
Preparing: UPDATE tb_user SET age=?, version=? WHERE id=? AND version=?
Parameters: 30(Integer), 2(Integer), 2(Long), 1(Integer)
Updates: 1
可以看到,更新的条件中有version条件,并且更新的version为2。
如果再次执行,更新则不成功。这样就避免了多人同时更新时导致数据的不一致。
2.4.5、特别说明
- 支持的数据类型只有:int,Integer,long,Long,Date,Timestamp,LocalDateTime
- 整数类型下
newVersion = oldVersion + 1
newVersion
会回写到entity
中- 仅支持
updateById(id)
与update(entity, wrapper)
方法 - 在 update(entity, wrapper) 方法下, wrapper 不能复用!!!
3、Sql 注入器
我们已经知道,在MP中,通过AbstractSqlInjector将BaseMapper中的方法注入到了Mybatis容器,这样这些方法才可以正常执行。
那么,如果我们需要扩充BaseMapper中的方法,又该如何实现呢?
下面我们以扩展findAll方法为例进行学习。
3.1、编写MyBaseMapper
package com.test.mapper.base;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import java.util.List;
/**
* 公共组件: 自定义公共Mapper, 所有业务Mapper都要继承这个接口
*/
public interface MyBaseMapper<T> extends BaseMapper<T> {
/**
* 查询表中所有数据方法
*/
public List<T> findAll();
}
其他的Mapper都可以继承该Mapper,这样实现了统一的扩展。
如:
package com.test.mapper;
import com.test.mapper.base.MyBaseMapper;
import com.test.pojo.User;
/**
* 用户Mapper
*/
public interface UserMapper extends MyBaseMapper<User> {
public User findById(Long id);
}
3.2、编写MySqlInjector
如果直接继承AbstractSqlInjector的话,原有的BaseMapper中的方法将失效,所以我们选择继承DefaultSqlInjector进行扩展。
package com.test.mapper.base;
import com.baomidou.mybatisplus.core.injector.AbstractMethod;
import com.baomidou.mybatisplus.core.injector.DefaultSqlInjector;
import java.util.List;
/**
* 公共组件: 自定义Sql注入器
* 作用: 保证了原有BaseMapper中的所有方法可以使用,
* 并且加入了新的自定义公共方法可以使用
*/
public class MySqlInjector extends DefaultSqlInjector {
@Override
public List<AbstractMethod> getMethodList() {
List<AbstractMethod> methodList = super.getMethodList();
// 再扩充自定义的方法
methodList.add(new FindAll());
return methodList;
}
}
3.3、编写FindAll
package com.test.mapper.base;
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;
/**
* 公共组件: 自定义FindAll类, 查询表中所有数据
*/
public class FindAll extends AbstractMethod {
@Override
public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
String sqlMethod = "findAll";
String sql = "select * from " + tableInfo.getTableName();
SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql, modelClass);
return this.addSelectMappedStatement(mapperClass, sqlMethod, sqlSource, modelClass, tableInfo);
}
}
3.4、注册到Spring容器
/**
* 公共组件: 自定义SQL注入器
*/
@Bean
public MySqlInjector mySqlInjector(){
return new MySqlInjector();
}
3.5、测试
@Test
public void testFindAll(){
List<User> users = userMapper.findAll();
for (User user : users) {
System.out.println(user);
}
}
输出的SQL:
[main] [com.test.mapper.UserMapper.findAll]-[DEBUG] ==> Preparing: select * from tb_user
[main] [com.test.mapper.UserMapper.findAll]-[DEBUG] ==> Parameters:
[main] [com.test.mapper.UserMapper.findAll]-[DEBUG] <== Total: 7
至此,我们实现了全局扩展SQL注入器。
4、自动填充功能
有些时候我们可能会有这样的需求,插入或者更新数据时,希望有些字段可以自动填充数据,比如密码、version等。在MP中提供了这样的功能,可以实现自动填充。
4.1、添加@TableField注解
//插入数据时进行填充, 并且查询时不被查询出来
@TableField(select = false, fill = FieldFill.INSERT)
private String password;
为password添加自动填充功能,在新增数据时有效。
FieldFill提供了多种模式选择:
public enum FieldFill {
/**
* 默认不处理
*/
DEFAULT,
/**
* 插入时填充字段
*/
INSERT,
/**
* 更新时填充字段
*/
UPDATE,
/**
* 插入和更新时填充字段
*/
INSERT_UPDATE
}
4.2、编写MyMetaObjectHandler
package com.test.handler;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
/**
* 自定义: 字段自动填充处理器
*/
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
/**
* insert语句, 如果字段为空自动填充处理方法
* @param metaObject
*/
@Override
public void insertFill(MetaObject metaObject) {
Object password = getFieldValByName("password", metaObject);
if(null == password){
//字段为空,可以进行填充
setFieldValByName("password", "123456", metaObject);
}
}
@Override
public void updateFill(MetaObject metaObject) {
}
}
4.3、测试
@Test
public void testInsertAuto(){
User user = new User();
user.setName("关羽");
user.setUserName("guanyu");
user.setAge(30);
user.setMail("guanyu@1000phone.com");
user.setVersion(1);
int result = this.userMapper.insert(user);
System.out.println("result = " + result);
}
6、代码生成器
AutoGenerator 是 MyBatis-Plus 的代码生成器,通过 AutoGenerator 可以快速生成 Entity、Mapper、Mapper XML、Service、Controller 等各个模块的代码,极大的提升了开发效率。
效果:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-f15WhC8x-1672022129401)(Pictures/generator.gif)]
6.1、创建工程
pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.test</groupId>
<artifactId>test_mybatis_plus_generator</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.4.RELEASE</version>
</parent>
<properties>
<!-- 项目源码及编译输出的编码 -->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<!-- 项目编译JDK版本 -->
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--mybatis-plus的springboot支持-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.1.1</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.1.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
<!--mysql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
6.2、代码
package com.test;
import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
/**
* mysql 代码生成器演示例子
*/
public class MysqlGenerator {
/**
* 生成方法
*/
public static void main(String[] args) {
//1. 代码生成器
AutoGenerator mpg = new AutoGenerator();
//2. 全局配置
GlobalConfig gc = new GlobalConfig();
String projectPath = System.getProperty("user.dir");
gc.setOutputDir(projectPath + "/src/main/java");
//3. 类上注释, 代码作者, 可以写自己名字
gc.setAuthor("zhangsan");
gc.setOpen(false);
mpg.setGlobalConfig(gc);
/**
* 4. 数据源配置
*/
DataSourceConfig dsc = new DataSourceConfig();
dsc.setUrl("jdbc:mysql://127.0.0.1:3306/test_mp?useUnicode=true&useSSL=false&characterEncoding=utf8");
// dsc.setSchemaName("public");
dsc.setDriverName("com.mysql.jdbc.Driver");
dsc.setUsername("root");
dsc.setPassword("123456");
mpg.setDataSource(dsc);
//5. 包配置
PackageConfig pc = new PackageConfig();
//6. 模块名字, 一定要按照, 用户模块, 订单模块等分模块
pc.setModuleName("user");
//7. 模块父级包名, 一般为组织名
pc.setParent("com.test");
mpg.setPackageInfo(pc);
//8. 自定义配置
InjectionConfig cfg = new InjectionConfig() {
@Override
public void initMap() {
// to do nothing
}
};
List<FileOutConfig> focList = new ArrayList<>();
focList.add(new FileOutConfig("/templates/mapper.xml.ftl") {
@Override
public String outputFile(TableInfo tableInfo) {
// 自定义输入文件名称
return projectPath + "/src/main/resources/mapper/" + pc.getModuleName()
+ "/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
}
});
cfg.setFileOutConfigList(focList);
mpg.setCfg(cfg);
//9. 配置模板
mpg.setTemplate(new TemplateConfig().setXml(null));
/**
* 10. 策略配置
*/
StrategyConfig strategy = new StrategyConfig();
strategy.setNaming(NamingStrategy.underline_to_camel);
strategy.setColumnNaming(NamingStrategy.underline_to_camel);
//strategy.setSuperEntityClass("com.baomidou.mybatisplus.samples.generator.common.BaseEntity");
//11. 是否使用Lombok
strategy.setEntityLombokModel(true);
//12. controller是否为Rest形式
strategy.setRestControllerStyle(true);
//strategy.setSuperControllerClass("com.baomidou.mybatisplus.samples.generator.common.BaseController");
/**
* 13. 如果 setInclude() 不加参数, 会自定查找所有表
* 如需要制定单个表, 需填写参数如: strategyConfig.setInclude("user_info);
*/
strategy.setInclude();
//strategy.setSuperEntityColumns("id");
strategy.setControllerMappingHyphenStyle(true);
strategy.setTablePrefix(pc.getModuleName() + "_");
mpg.setStrategy(strategy);
mpg.setTemplateEngine(new FreemarkerTemplateEngine());
System.out.println("===================== MyBatis Plus Generator ==================");
mpg.execute();
}
}
6.3. 代码生成器使用注意事项
- 执行生成器如果有问题, 需要将生成后的内容删掉, 然后再执行生成代码, 从新生成.
- 上面生成器项目创建的时候只能是project, 不能是model, 否则生成的文件有问题.
7、MybatisX 快速开发插件
MybatisX 是一款基于 IDEA 的快速开发插件,为效率而生。
安装方法:打开 IDEA,进入 File -> Settings -> Plugins -> Browse Repositories,输入 mybatisx
搜索并安装。
功能:
- Java 与 XML 跳转
- Mapper 方法自动生成 XML
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QQQ549ij-1672022129402)(Pictures/mybatisx-001.gif)]
*/
strategy.setInclude();
//strategy.setSuperEntityColumns("id");
strategy.setControllerMappingHyphenStyle(true);
strategy.setTablePrefix(pc.getModuleName() + "_");
mpg.setStrategy(strategy);
mpg.setTemplateEngine(new FreemarkerTemplateEngine());
System.out.println("===================== MyBatis Plus Generator ==================");
mpg.execute();
}
}
### 6.3. 代码生成器使用注意事项
- **执行生成器如果有问题, 需要将生成后的内容删掉, 然后再执行生成代码, 从新生成.**
- **上面生成器项目创建的时候只能是project, 不能是model, 否则生成的文件有问题.**
## 7、MybatisX 快速开发插件
MybatisX 是一款基于 IDEA 的快速开发插件,为效率而生。
安装方法:打开 IDEA,进入 File -> Settings -> Plugins -> Browse Repositories,输入 `mybatisx` 搜索并安装。
功能:
- Java 与 XML 跳转
- Mapper 方法自动生成 XML
[外链图片转存中...(img-QQQ549ij-1672022129402)]