jpa tk-mapper mybatis-plus
MyBatis-Plus (opens new window)(简称 MP)是一个 MyBatis (opens new window)的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user`
(
id BIGINT(20) NOT NULL COMMENT '主键ID',
`name` VARCHAR(30) NULL DEFAULT NULL COMMENT '姓名',
age INT(11) NULL DEFAULT NULL COMMENT '年龄',
email VARCHAR(50) NULL DEFAULT NULL COMMENT '邮箱',
PRIMARY KEY (id)
);
INSERT INTO `user` (id, `name`, age, email) VALUES
(1, 'Jone', 18, '[email protected]'),
(2, 'Jack', 20, '[email protected]'),
(3, 'Tom', 28, '[email protected]'),
(4, 'Sandy', 21, '[email protected]'),
(5, 'Billie', 24, '[email protected]');
添加依赖
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>5.1.47version>
dependency>
<dependency>
<groupId>com.baomidougroupId>
<artifactId>mybatis-plus-boot-starterartifactId>
<version>3.0.5version>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<version>1.18.10version>
dependency>
<dependency>
<groupId>com.baomidougroupId>
<artifactId>mybatis-plus-extensionartifactId>
<version>3.0.5version>
dependency>
<dependency>
<groupId>com.baomidougroupId>
<artifactId>mybatis-plus-generatorartifactId>
<version>3.4.1version>
dependency>
高版本的驱动兼容低版本的数据库,8版本的驱动需要增加时区的配置
pojo–dao(mybatis配置文件、Mapper.xml配置文件)–service–controller
pojo–dao(只需要继承指定泛型的接口:BansMapper)–service–controller
User.java
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
//数据库主键id自动生成:uuid,自增,雪花算法,redis,zookeeper
@TableId(type = IdType.ID_WORKER)
private Long id;
private String name;
private Integer age;
private String email;
}
UserMapper.java
@Mapper
@Repository
public interface UserMapper extends BaseMapper<User> {
}
application.yml
spring:
datasource:
username: root
password: 123456
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/demo?useUniocde=true&characterEncoding=utf8&useSSL=true&serverTimezone=GMT%2B8
#开启mybatis-plus控制台日志输出
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
测试
@SpringBootTest
class MybatisPlusTestApplicationTests {
@Autowired
private UserMapper userMapper;
@Test
void contextLoads() {
//测试Mybatis-Plus环境是否搭建成功
List<User> userList = userMapper.selectList(null);
for (User user : userList) {
System.out.println(user.toString());
}
}
}
主键id
主键生成策略:uuid,自增,雪花算法,redis,zookeeper
mybatis-plus所带的主键生成策略:@TableId
@TableId(type = IdType.ID_WORKER)
private Long id;
分析
public enum IdType {
AUTO(0),//数据库id自增
NONE(1),//该类型为未设置主键类型
INPUT(2),//手动输入,该类型可以通过自己注册自动填充插件进行填充
//以下3种类型、只有当插入对象ID 为空,才自动填充
ID_WORKER(3),//雪花算法
UUID(4),//uuid
ID_WORKER_STR(5);//字符串全局唯一id
private int key;
private IdType(int key) {
this.key = key;
}
public int getKey() {
return this.key;
}
}
动态sql
@Test
void testUpdate(){
User user = new User();
user.setId(5L);
user.setName("麻腾飞");
user.setAge(18);
int i = userMapper.updateById(user);
}
时间自动填充
数据库级别
@Test
void testUpdate(){
User user = new User();
user.setId(5L);
user.setName("飞哥");
user.setAge(9);
int i = userMapper.updateById(user);
}
注解级别(Mybatis-plus自带注解)
//User.java
@TableField(fill = FieldFill.INSERT)//添加数据时,自动给createTime字段添加当前系统时间
private Date createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)//添加或修改数据时,自动给editTime字段添加当前系统时间
private Date editTime;
//编写处理器来为注解自定义填充策略
@Slf4j
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
log.info("start fill insert...");
this.setFieldValByName("createTime",new Date(),metaObject);
this.setFieldValByName("editTime",new Date(),metaObject);
}
@Override
public void updateFill(MetaObject metaObject) {
this.setFieldValByName("editTime",new Date(),metaObject);
}
}
什么是乐观锁、悲观锁?自旋锁尝试多次提交
乐观锁:当要更新一条记录时,希望这条记录没有被别人更新
- 取出记录时,获取当前version
- 更新时,带上这个version
- 执行更新时, set version = newVersion where version = oldVersion
- 如果version不对,就更新失败
测试Mybatis-plus乐观锁插件
乐观锁执行成功测试
//实体类加上@Version注解
@Version
private Integer version;
//编写配置类注册乐观锁插件
@Configuration
@EnableTransactionManagement
public class MyConfig {
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
return new OptimisticLockerInterceptor();
}
//注册乐观锁插件,3.5.x版本的
// @Bean
// public MybatisPlusInterceptor mybatisPlusInterceptor() {
// MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
// return interceptor;
// }
}
//测试乐观锁成功
@Test
void testOptimisticSuccess(){
//先根据id获取记录,获取当前的version字段的值
User user = userMapper.selectById(3L);
user.setName("飞哥");
int i = userMapper.updateById(user);
}
乐观锁执行成功测试01
@Test
void testOptimisticSuccess(){
//先根据id获取记录,获取当前的version字段的值
User user = userMapper.selectById(2L);
//模拟插队线程
user.setAge(10);
userMapper.updateById(user);
user.setName("飞哥");
userMapper.updateById(user);
}
总结:使用乐观锁插件更新记录,只需要查询一次记录即可
乐观锁执行失败
//测试乐观锁失败
@Test
void testOptimisticError(){
//先根据id获取记录,获取当前的version字段的值
User user = userMapper.selectById(1L);
user.setName("飞哥");
//模拟插队线程
User user1 = userMapper.selectById(1L);
user1.setAge(10);
userMapper.updateById(user1);
userMapper.updateById(user);
}
//测试常用查询操作
@Test
void test01(){
//查询所有数据
List<User> userList1 = userMapper.selectList(null);
//根据唯一id查询
User user1 = userMapper.selectById(1L);
//通过多个id查询多条记录
List<User> userList2 = userMapper.selectBatchIds(Arrays.asList(1L, 2L, 3L));
//通过Map集合查询记录
Map<String, Object> map = new HashMap<>();
map.put("name","Jone");
List<User> userList3 = userMapper.selectByMap(map);
for (User user : userList3) {
System.out.println(user.toString());
}
}
原始的limit
分页插件:pageHelper
Mybatis-plus自带的分页插件
//编写配置类配置分页插件
@Configuration
@EnableTransactionManagement
@MapperScan("com.mtf.mapper")
public class MyConfig {
// 旧版
@Bean
public PaginationInterceptor paginationInterceptor() {
PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
// 设置请求的页面大于最大页后操作, true调回到首页,false 继续请求 默认false
// paginationInterceptor.setOverflow(false);
// 设置最大单页限制数量,默认 500 条,-1 不受限制
// paginationInterceptor.setLimit(500);
// 开启 count 的 join 优化,只针对部分 left join
// paginationInterceptor.setCountSqlParser(new JsqlParserCountOptimize(true));
return paginationInterceptor;
}
// 最新版
// @Bean
// public MybatisPlusInterceptor mybatisPlusInterceptor() {
// MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.H2));
// return interceptor;
// }
}
//测试分页插件
@Test
void testPage(){
Page<User> userPage = new Page<>();
userPage.setCurrent(1);
userPage.setSize(2);
userMapper.selectPage(userPage, null);
for (User record : userPage.getRecords()) {
System.out.println(record.toString());
}
}
物理删除
逻辑删除
逻辑删除数据并不是把数据从数据库中移除,而是通过改变变量的值让该行数据失效
#开启mybatis-plus控制台日志输出
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
global-config:
db-config:
logic-delete-value: 0 #逻辑已删除设置为0
logic-not-delete-value: 1 #逻辑未删除设置为1
@Configuration
@EnableTransactionManagement
@MapperScan("com.mtf.mapper")
public class MyConfig {
//注册逻辑删除实例
@Bean
public ISqlInjector sqlInjector(){
return new LogicSqlInjector();
}
}
//删除操作
@Test
void testDelete(){
userMapper.deleteById(5L);
}
用来检测项目开发过程中存在的慢sql,MP的性能分析插件能够设置sql的执行时间,如果一些sql执行时间超过设定值就会停止运行!
#设置开发环境
spring:
profiles:
active:test
@Configuration
@EnableTransactionManagement
@MapperScan("com.mtf.mapper")
public class MyConfig {
//注册性能分析插件
@Bean
@Profile({"dev","test"}) //设置dev 和 test 开发环境开启
public PerformanceInterceptor performanceInterceptor(){
PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor();
performanceInterceptor.setMaxTime(1);//单位毫秒
performanceInterceptor.setFormat(true);
return performanceInterceptor;
}
}
@SpringBootTest
public class WrapperTest {
@Autowired
private UserMapper userMapper;
// 查询name不为空的用户,并且邮箱不为空的用户,年龄大于等于12
@Test
void test01(){
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.isNotNull("name")
.isNotNull("email")
.ge("age",12);
List<User> userList = userMapper.selectList(wrapper);
for (User user : userList) {
System.out.println(user.toString());
}
}
// 查询名字Jone
@Test
void test02(){
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.eq("name","Jone");
//返回一个结果调用selectOne,返回多个结果调用selectList
User user = userMapper.selectOne(wrapper);
System.out.println(user.toString());
}
// 查询年龄在 20 ~ 30 岁之间的用户
@Test
void test03(){
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.ge("age",10)
.le("age",22);
//wrapper.between("age",10,22);
List<User> userList = userMapper.selectList(wrapper);
for (User user : userList) {
System.out.println(user.toString());
}
}
//其他功能参考官方文档
}
通过 AutoGenerator 可以快速生成 Entity、Mapper、Mapper XML、Service、Controller 等各个模块的代码,极大的提升了开发效率。
package com.mtf;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.GlobalConfig;
import com.baomidou.mybatisplus.generator.config.PackageConfig;
import com.baomidou.mybatisplus.generator.config.StrategyConfig;
import com.baomidou.mybatisplus.generator.config.po.TableFill;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import java.util.ArrayList;
/**
* @BelongsProject: Mybatis_Plus_Test
* @BelongsPackage: com.mtf
* @Author: Matengfei
* @CreateTime: 2022-08-10 20:41
* @Description: TODO
* @Version: 1.0
*/
public class CodeGenerator {
public static void main(String[] args) {
// 需要构建一个 代码自动生成器 对象
AutoGenerator mpg = new AutoGenerator();
//1、全局配置
GlobalConfig globalConfig = new GlobalConfig();
//指定代码生成的物理位置
globalConfig.setOutputDir(System.getProperty("user.dir") + "/src/main/java");
//设置作者
globalConfig.setAuthor("Matengfei");
globalConfig.setOpen(false);
// 是否覆盖
globalConfig.setFileOverride(false);
//去掉Service名称前面的I
globalConfig.setServiceName("%sService");
globalConfig.setIdType(IdType.ID_WORKER);
globalConfig.setDateType(DateType.ONLY_DATE);
globalConfig.setSwagger2(true);
mpg.setGlobalConfig(globalConfig);
//2、数据源配置
DataSourceConfig dataSourceConfig = new DataSourceConfig();
dataSourceConfig.setUrl("jdbc:mysql://localhost:3306/demo?useUnicode=true&useSSL=false&characterEncoding=utf8");
dataSourceConfig.setDriverName("com.mysql.jdbc.Driver");
dataSourceConfig.setUsername("root");
dataSourceConfig.setPassword("123456");
//3、包的配置
PackageConfig pc = new PackageConfig();
//只需要改实体类名字 和包名 还有 数据库配置即可
pc.setModuleName("blog"); pc.setParent("com.kuang");
pc.setEntity("entity"); pc.setMapper("mapper");
pc.setService("service"); pc.setController("controller");
mpg.setPackageInfo(pc);
//4、策略配置
StrategyConfig strategy = new StrategyConfig();
//表名
strategy.setInclude("blog_tags","course","links","sys_settings","user_record"," user_say");
// 设置要映射的表名
strategy.setNaming(NamingStrategy.underline_to_camel);
strategy.setColumnNaming(NamingStrategy.underline_to_camel);
strategy.setEntityLombokModel(true);
// 自动lombok
strategy.setLogicDeleteFieldName("deleted");
// 自动填充配置
TableFill gmtCreate = new TableFill("create_time", FieldFill.INSERT);
TableFill gmtModified = new TableFill("edit_time", FieldFill.INSERT_UPDATE);
ArrayList<TableFill> tableFills = new ArrayList<>();
tableFills.add(gmtCreate); tableFills.add(gmtModified);
strategy.setTableFillList(tableFills);
// 乐观锁
strategy.setVersionFieldName("version");
strategy.setRestControllerStyle(true);
strategy.setControllerMappingHyphenStyle(true);
// localhost:8080/hello_id_2
mpg.setStrategy(strategy);
mpg.execute(); //执行
}
}