mybatisplus入门教程
什么是Mybatis Plus
快速入门
创建数据库 gk_mybatis_plus
创建数据库表
DROP TABLE IF EXISTS gk_user;
CREATE TABLE gk_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)
);
添加数据
select *
from gk_user;
DELETE
FROM user;
INSERT INTO gk_user (id, name, age, email)
VALUES (1, 'Jone', 18, 'test1@baomidou.com'),
(2, 'Jack', 20, 'test2@baomidou.com'),
(3, 'Tom', 28, 'test3@baomidou.com'),
(4, 'Sandy', 21, 'test4@baomidou.com'),
(5, 'Billie', 24, 'test5@baomidou.com');
创建空的Spring Boot项目
1 创建项目目录
File->New->Project
2 选择脚手架,jdk版本
Spring Initializr
Project SDK : java version “1.8.0_131”
choose Initializr Service URL.
Default: https://start.spring.io
3 Spring Boot基本信息
注意:修改version:2.4.1
最终效果空项目
添加依赖
父工程
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.1</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.1</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
注意:尽量不要同时导入mybatis和mybatis_plus,版本差异
配置数据库连接MySQL
# DataSource Config
spring:
datasource:
username: root
password: 123456
url: jdbc:mysql:///mybatis_plus?userUnicode=true&characterEncoding=utf-8
driver-class-name: com.mysql.cj.jdbc.Driver
在spring boot启动类中添加@MapperScan注解,扫描Mapper文件夹
package com.geekmice.gkmybatisplusdemo;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@MapperScan("com.geekmice.gkmybatisplusdemo.dao")
@SpringBootApplication
public class GkMybatisplusDemoApplication {
public static void main(String[] args) {
SpringApplication.run(GkMybatisplusDemoApplication.class, args);
}
}
编写代码
实体类 GkUserDomain
package com.geekmice.gkmybatisplusdemo.domain;
/**
* @BelongsProject: gk-mybatisplus-demo
* @BelongsPackage: com.geekmice.gkmybatisplusdemo.domain
* @Author: pingmingbo
* @CreateTime: 2023-07-21 09:26
* @Description: TODO
* @Version: 1.0
*/
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
/**
* @TableName gk_user
*/
@Data
@TableName("gk_user")
public class GkUserDomain {
/**
* 主键ID
*/
private Long id;
/**
* 姓名
*/
private String name;
/**
* 年龄
*/
private Integer age;
/**
* 邮箱
*/
private String email;
}
注意:@TableName("gk_user")
,这个注解是为了说明映射数据库表,默认gk_user_domain
,类似于起别名作用。
mapper
package com.geekmice.gkmybatisplusdemo.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.geekmice.gkmybatisplusdemo.domain.GkUserDomain;
/**
* @Entity com.geekmice.gkmybatisplusdemo.domain.GkUser
*/
public interface GkUserMapper extends BaseMapper<GkUserDomain> {
}
xml映射文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.geekmice.gkmybatisplusdemo.mapper.GkUserMapper">
<resultMap id="BaseResultMap" type="com.geekmice.gkmybatisplusdemo.domain.GkUserDomain">
<id property="id" column="id" jdbcType="BIGINT"/>
<result property="name" column="name" jdbcType="VARCHAR"/>
<result property="age" column="age" jdbcType="INTEGER"/>
<result property="email" column="email" jdbcType="VARCHAR"/>
</resultMap>
<sql id="Base_Column_List">
id,name,age,
email
</sql>
</mapper>
业务层,实现类
package com.geekmice.gkmybatisplusdemo.service;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.extension.service.IService;
import com.geekmice.gkmybatisplusdemo.domain.GkUserDomain;
import java.util.List;
/**
*
*/
public interface GkUserService extends IService<GkUserDomain> {
List<GkUserDomain> listFirst(Wrapper<GkUserDomain> queryWrapper);
}
package com.geekmice.gkmybatisplusdemo.service.impl;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.geekmice.gkmybatisplusdemo.domain.GkUserDomain;
import com.geekmice.gkmybatisplusdemo.mapper.GkUserMapper;
import com.geekmice.gkmybatisplusdemo.service.GkUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
/**
*
*/
@Service
public class GkUserServiceImpl extends ServiceImpl<GkUserMapper, GkUserDomain>
implements GkUserService {
@Autowired
private GkUserMapper userMapper;
@Override
public List<GkUserDomain> listFirst(Wrapper<GkUserDomain> queryWrapper) {
List<GkUserDomain> result = userMapper.selectList(null);
return result;
}
}
控制层
package com.geekmice.gkmybatisplusdemo.controller;
import com.geekmice.gkmybatisplusdemo.domain.GkUserDomain;
import com.geekmice.gkmybatisplusdemo.service.GkUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* @BelongsProject: gk-mybatisplus-demo
* @BelongsPackage: com.geekmice.gkmybatisplusdemo.controller
* @Author: pingmingbo
* @CreateTime: 2023-07-21 09:37
* @Description: TODO
* @Version: 1.0
*/
@RestController
@Slf4j
public class GkUserController {
@Autowired
private GkUserService gkUserService;
@GetMapping("test")
public List<GkUserDomain> test() {
List<GkUserDomain> gkUserDomains = gkUserService.listFirst(null);
log.info("abc");
return gkUserDomains;
}
}
创建请求
GET http://localhost:8080/test
Accept: application/json
###
配置日志打印
yml
#配置日志
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
注解
@TableName
- 描述:表名注解,映射实体类对应表
- 实体类使用
/**
* @TableName gk_user
*/
@Data
@TableName("gk_user")
public class GkUserDomain {
/**
* 主键ID
*/
private Long id;
/**
* 姓名
*/
private String name;
/**
* 年龄
*/
private Integer age;
/**
* 邮箱
*/
private String email;
}
@TableId
说明:标识主键,实体类主键字段
没有添加注解@TableId,会生成一个序列号id,自 3.3.0 开始,默认使用雪花算法+UUID(不含中划线)
{
"id": 1682215281188872194,
"name": "zs",
"age": 10,
"email": "123@163.com"
}
添加注解@TableId,没有什么变化,还是生成无序编号id
{
"id": 1682215919683575809,
"name": "ls",
"age": 11,
"email": "456@163.com"
}
type之IdType属性如下
注意:数据库表主键字段需要设置为自增,整形
自 3.3.0 开始,默认使用雪花算法+UUID(不含中划线)
@TableField
说明:非主键字段,起别名value=“”
package com.geekmice.gkmybatisplusdemo.domain;
/**
* @BelongsProject: gk-mybatisplus-demo
* @BelongsPackage: com.geekmice.gkmybatisplusdemo.domain
* @Author: pingmingbo
* @CreateTime: 2023-07-21 09:26
* @Description: TODO
* @Version: 1.0
*/
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
/**
* @TableName gk_user
*/
@Data
@TableName("gk_user")
public class GkUserDomain {
/**
* 主键ID
*/
@TableId(type = IdType.AUTO)
private Long id;
/**
* 姓名
*/
@TableField(value="user_name")
private String name;
}
自定义id
生成器
分页插件
在这里插入代码片
条件构造器
/**
* @description 练习mybatis plus 条件构造器
* @return
*/
@GetMapping(value = "validQueryWrapper")
public String validQueryWrapper(){
QueryWrapper<GkUserDomain> userQueryWrapper = new QueryWrapper<>();
// 1 查询用户表所有id列信息
// QueryWrapper<GkUserDomain> tempIdInfos = userQueryWrapper.select("id");
// java.lang.IndexOutOfBoundsException: Index: 1, Size: 1
// List<GkUserDomain> domains = gkUserMapper.selectList(tempIdInfos);
// List<Object> idList = gkUserMapper.selectObjs(userQueryWrapper);
// 2 查询用户表某几列信息
// 3 模糊查询
// userQueryWrapper.likeLeft("name","mb"); // 左模糊
// log.info("左模糊:[{}]",gkUserMapper.selectList(userQueryWrapper)); // SELECT id FROM gk_user WHERE (name LIKE '%mb')
// userQueryWrapper.likeRight("name","pmb"); // 右模糊
// log.info("右模糊:[{}]",gkUserMapper.selectList(userQueryWrapper)); // SELECT id FROM gk_user WHERE (name LIKE '%mb' AND name LIKE 'pmb%')
// 4 分页查询 todo
// 使用分页插件
// 5 全部相等情况
// HashMap<String, Object> allEqMap = new HashMap<>(16);
// allEqMap.put("id","1682216842073970971");
// allEqMap.put("name","pmb0");
// allEqMap.put("age",10);
// allEqMap.put("email","abc0@163.com");
// userQueryWrapper.allEq(allEqMap);
// log.info("全部相等:[{}]",gkUserMapper.selectList(userQueryWrapper));
// SELECT id,name,age,email,field1,field2,field3,field4,field5,field6 FROM gk_user
// WHERE (name = 'pmb0' AND id = '1682216842073970971' AND age = 10 AND email = 'abc0@163.com')
// 6 eq 某个字段相等
String paramFirst = "abc";
// // userQueryWrapper.eq("name","pmb1");
// userQueryWrapper.eq(StringUtils.isNotBlank(paramFirst),"name","pmb2");
// // SELECT id,name,age,email,field1,field2,field3,field4,field5,field6 FROM gk_user WHERE (name = 'pmb2')
// gkUserMapper.selectList(userQueryWrapper);
//
// 7 ne 某个字段不相等/外加条件某个字段不相等
// userQueryWrapper.ne("name","pmb3");
// userQueryWrapper.ne(StringUtils.contains(paramFirst,"a"),"age","18");
// gkUserMapper.selectList(userQueryWrapper);
//SELECT id,name,age,email,field1,field2,field3,field4,field5,field6 FROM gk_user WHERE (name <> 'pmb3')
//SELECT id,name,age,email,field1,field2,field3,field4,field5,field6 FROM gk_user WHERE (age <> '18')
// // 8 排序 asc desc
// userQueryWrapper.orderByAsc("age");
// SELECT id,name,age,email,field1,field2,field3,field4,field5,field6 FROM gk_user ORDER BY age ASC 升序
// userQueryWrapper.orderByDesc("age");
// SELECT id,name,age,email,field1,field2,field3,field4,field5,field6 FROM gk_user ORDER BY age DESC 降序
// gkUserMapper.selectList(userQueryWrapper);
// // 9 是否为空
// userQueryWrapper.isNull("name");
// SELECT id,name,age,email,field1,field2,field3,field4,field5,field6 FROM gk_user WHERE (name IS NULL);
// userQueryWrapper.isNotNull("name");
// SELECT id,name,age,email,field1,field2,field3,field4,field5,field6 FROM gk_user WHERE (name IS NOT NULL)
// gkUserMapper.selectList(userQueryWrapper);
//
// // 10 大于
// userQueryWrapper.gt("age",19);
// SELECT id,name,age,email,field1,field2,field3,field4,field5,field6 FROM gk_user WHERE (age > 19)
// gkUserMapper.selectList(userQueryWrapper);
//
// // 11 大于等于
// userQueryWrapper.ge("age",20);
// gkUserMapper.selectList(userQueryWrapper);
// SELECT id,name,age,email,field1,field2,field3,field4,field5,field6 FROM gk_user WHERE (age >= 20)
//
// // 12 小于
// userQueryWrapper.lt("age",11);
// gkUserMapper.selectList(userQueryWrapper);
// SELECT id,name,age,email,field1,field2,field3,field4,field5,field6 FROM gk_user WHERE (age < 11)
//
// // 13 小于等于
// userQueryWrapper.le("age",22);
// gkUserMapper.selectList(userQueryWrapper);
// SELECT id,name,age,email,field1,field2,field3,field4,field5,field6 FROM gk_user WHERE (age <= 22)
//
// // 14 在a与b之间 between
// userQueryWrapper.between("age",18,20);
// gkUserMapper.selectList(userQueryWrapper);
// SELECT id,name,age,email,field1,field2,field3,field4,field5,field6 FROM gk_user WHERE (age BETWEEN 18 AND 20)
//
// // 15 不在a,b之间 notBetween
// userQueryWrapper.notBetween("age",18,20);
// gkUserMapper.selectList(userQueryWrapper);
// SELECT id,name,age,email,field1,field2,field3,field4,field5,field6 FROM gk_user WHERE (age NOT BETWEEN 18 AND 20)
//
// // 16 在哪几个之内 in
// userQueryWrapper.in("name","pmb1","pmb2");
// gkUserMapper.selectList(userQueryWrapper);
// SELECT id,name,age,email,field1,field2,field3,field4,field5,field6 FROM gk_user WHERE (name IN ('pmb1','pmb2'))
// // 17 不在哪几个之内 notIn
// userQueryWrapper.notIn("name","pmb1","pmb2","pm3");
// gkUserMapper.selectList(userQueryWrapper);
//SELECT id,name,age,email,field1,field2,field3,field4,field5,field6 FROM gk_user WHERE (name NOT IN ('pmb1','pmb2','pm3'))
// // 18 inSql
// userQueryWrapper.inSql("name","pmb");
// userQueryWrapper.inSql("name","select name from gk_user where name like '%4'");
// gkUserMapper.selectList(userQueryWrapper);
// SELECT id,name,age,email,field1,field2,field3,field4,field5,field6 FROM gk_user WHERE (name IN (select name from gk_user where name like '%4'))
//
// // 19 notInSql
// userQueryWrapper.notInSql("name","pmb1,pmb2,pmb3");
//
// // 20 分组 groupBy
// userQueryWrapper.groupBy("age");
//
// // 21 or 或者
// // 主动调用or表示紧接着下一个方法不是用and连接!(不调用or则默认为使用and连接)
userQueryWrapper.inSql("name","select name from gk_user where name like '%4'")
.or()
.inSql("name","select name from gk_user where name like '%6'");
gkUserMapper.selectList(userQueryWrapper);
//
// SELECT id,name,age,email,field1,field2,field3,field4,field5,field6 FROM gk_user WHERE
// (name IN (select name from gk_user where name like '%4') OR
// name IN (select name from gk_user where name like '%6'))
// return idList.toString();
return "success";
}
批量操作
方法一:Mybatis-plus 提供的 saveBatch
数据量 | 10w | 10w | 10w | 10w | 10w |
---|---|---|---|---|---|
耗时 | 11s | 11s | 11s | 10s | 10s |
service
public interface UserService extends IService<User> {
}
serviceimpl
public class UserServiceImpl extends ServiceImpl<UserDao, User> implements UserService {
}
测试类
package com.geekmice.sbeasypoi.utils;
import com.geekmice.sbeasypoi.SbEasyPoiApplication;
import com.geekmice.sbeasypoi.dao.UserDao;
import com.geekmice.sbeasypoi.entity.User;
import com.geekmice.sbeasypoi.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.ArrayList;
import java.util.Date;
/**
* @BelongsProject: spring-boot-scaffold
* @BelongsPackage: com.geekmice.sbeasypoi.utils
* @Author: pingmingbo
* @CreateTime: 2023-08-04 13:20
* @Description: TODO
* @Version: 1.0
*/
@SpringBootTest(classes = SbEasyPoiApplication.class)
@Slf4j
@RunWith(SpringRunner.class)
public class TestMain {
@Autowired
private UserDao userDao;
@Autowired
private UserService userService;
static ArrayList<User> list = new ArrayList<>();
static {
for (int i = 0; i < 100000; i++) {
User build = User.builder().userName(RandomStringUtils.randomAlphabetic(4)).address(RandomStringUtils.random(7))
.sex(RandomStringUtils.randomAlphabetic(1)).birthday(new Date()).build();
list.add(build);
}
}
@Test
public void t2(){
long start = System.currentTimeMillis();
userService.saveBatch(list);
long end = System.currentTimeMillis();
long consumeTime = (end - start) / 1000;
log.info("耗时:【{}】",consumeTime);
}
}
方法二:Mybatis 动态SQL,
数据量 | 10w | 10w | 10w | 10w | 10w |
---|---|---|---|---|---|
耗时 | 17s | 16s | 16s | 16s | 17s |
注意:然MyBatis的动态标签的批量操作在数据量特别大的时候,拼接出来的SQL语句过大;
优化思路:
static int batchSize = 10000;
public void createBatch(List<TestPO> entityList) {
if (!entityList.isEmpty()) {
int size = entityList.size();
int idxLimit = Math.min(batchSize, size);
int i = 1;
List<TestPO> oneBatchList = new ArrayList<>();
for (Iterator<TestPO> var7 = entityList.iterator(); var7.hasNext(); ++i) {
TestPOelement = var7.next();
oneBatchList.add(element);
if (i == idxLimit) {
baseMapper.insertBatchSomeColumn(oneBatchList);
oneBatchList.clear();
idxLimit = Math.min(idxLimit + batchSize, size);
}
}
}
}
dao层
public interface UserDao extends BaseMapper<User> {
void batchSaveMybatis(@Param("list") List<User> list);
}
xml
<insert id="batchSaveMybatis" parameterType="java.util.List">
insert into user(user_name,birthday,sex,address) values
<foreach collection="list" separator="," item="data">
(
#{data.userName},
#{data.birthday},
#{data.sex},
#{data.address}
)
</foreach>
</insert>
测试类
package com.geekmice.sbeasypoi.utils;
import com.geekmice.sbeasypoi.SbEasyPoiApplication;
import com.geekmice.sbeasypoi.dao.UserDao;
import com.geekmice.sbeasypoi.entity.User;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.ArrayList;
import java.util.Date;
/**
* @BelongsProject: spring-boot-scaffold
* @BelongsPackage: com.geekmice.sbeasypoi.utils
* @Author: pingmingbo
* @CreateTime: 2023-08-04 13:20
* @Description: TODO
* @Version: 1.0
*/
@SpringBootTest(classes = SbEasyPoiApplication.class)
@Slf4j
@RunWith(SpringRunner.class)
public class TestMain {
@Autowired
private UserDao userDao;
@Test
public void t1(){
long start = System.currentTimeMillis();
ArrayList<User> list = new ArrayList<>();
for (int i = 0; i < 100000; i++) {
User build = User.builder().userName(RandomStringUtils.randomAlphabetic(4)).address(RandomStringUtils.random(7))
.sex(RandomStringUtils.randomAlphabetic(1)).birthday(new Date()).build();
list.add(build);
}
userDao.batchSaveMybatis(list);
long end = System.currentTimeMillis();
int result= (int) ((end-start)/1000);
log.info("耗时:【{}】",result);
}
}
方法三 通过使用InsertBatchSomeColumn方法批量插入
数据量 | 10w | 10w | 10w | 10w | 10w |
---|---|---|---|---|---|
耗时 | 15s | 19s | 12s | 13s | 17s |
说明:底层是拼接SQL,但是无需手动编写SQL语句
1 自定义SQL注入器实现DefaultSqlInjector,添加InsertBatchSomeColumn方法
public class EasySqlInjector extends DefaultSqlInjector {
/**
* 如果只需增加方法,保留MP自带方法
* 可以super.getMethodList() 再add
* @return
*/
@Override
public List<AbstractMethod> getMethodList(Class<?> mapperClass, TableInfo tableInfo) {
List<AbstractMethod> methodList = super.getMethodList(mapperClass, tableInfo);
methodList.add(new InsertBatchSomeColumn());
return methodList;
}
}
2 添加配置类交给spring容器管理
package com.geekmice.gkmybatisplusdemo.plugin;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @BelongsProject: gk-mybatisplus-demo
* @BelongsPackage: com.geekmice.gkmybatisplusdemo.plugin
* @Author: pingmingbo
* @CreateTime: 2023-07-21 15:57
* @Description: TODO
* @Version: 1.0
*/
@Configuration
@MapperScan("com.geekmice.gkmybatisplusdemo.mapper")
public class MybatisPlusConfig {
@Bean
public EasySqlInjector easySqlInjector() {
return new EasySqlInjector();
}
}
3 编写自定义BaseMapper,加入InsertBatchSomeColumn方法
注意事项:参数只能是list,否则错误找到mappedstatement
参考官网案例说明demo
public interface MyBaseMapper<T> extends BaseMapper<T> {
/**
* 自定义通用方法
*/
Integer deleteAll();
int myInsertAll(T entity);
/**
* 如果要自动填充,@{@code Param}(xx) xx参数名必须是 list/collection/array 3个的其中之一
*
* @param batchList
* @return
*/
int mysqlInsertAllBatch(@Param("list") List<T> batchList);
}
public interface EasyBaseMapper<T> extends BaseMapper<T> {
/**
* @description 批量插入
* @param entityList
* @return
*/
int insertBatchSomeColumn(@Param("list") List<T> list);
}
4 将自定义的业务mapper继承自定义的BaseMapper
public interface UserMapper extends EasyBaseMapper<GkUserDomain> {
}
5 测试验证效果
package com.geekmice.gkmybatisplusdemo.plugin;
import com.alibaba.fastjson.JSON;
import com.geekmice.common.annota.MethodExporter;
import com.geekmice.gkmybatisplusdemo.GkMybatisplusDemoApplication;
import com.geekmice.gkmybatisplusdemo.domain.GkUserDomain;
import com.geekmice.gkmybatisplusdemo.mapper.GkUserMapper;
import com.geekmice.gkmybatisplusdemo.mapper.UserMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.sql.*;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Random;
/**
* @BelongsProject: spring-boot-scaffold
* @BelongsPackage: com.geekmice.gkmybatisplusdemo.plugin
* @Author: pingmingbo
* @CreateTime: 2023-07-28 19:14
* @Description: TODO
* @Version: 1.0
*/
@SpringBootTest(classes = GkMybatisplusDemoApplication.class)
@Slf4j
@RunWith(SpringRunner.class)
public class ImportAnnotionTest {
@Autowired
private UserMapper userMapper;
@Test
public void t9() {
long start = System.currentTimeMillis();
List<GkUserDomain> gkUserDomains = new ArrayList<>();
Random random = new Random();
for (int i = 0; i < 100000; i++) {
GkUserDomain test = new GkUserDomain();
test.setUserName(RandomStringUtils.randomAlphabetic(4));
test.setAge(random.nextInt(20));
test.setEmail(i + "2" + i + "@163.com");
test.setField1(RandomStringUtils.randomAlphabetic(8));
gkUserDomains.add(test);
}
userMapper.insertBatchSomeColumn(gkUserDomains);
long end = System.currentTimeMillis();
log.info("耗时:【{}】", (end - start) / 1000);
}
}
方法四:jdbc操作,效率飙升
数据量 | 10w | 10w | 10w | 10w | 10w |
---|---|---|---|---|---|
耗时 | 4s | 6s | 4s | 4s | 5s |
核心代码
注意事项
1 yml中rewriteBatchedStatements=true开启
2 事务手动提交关闭。
package com.geekmice.sbeasypoi.utils;
import com.geekmice.sbeasypoi.SbEasyPoiApplication;
import com.geekmice.sbeasypoi.dao.UserDao;
import com.geekmice.sbeasypoi.entity.User;
import com.geekmice.sbeasypoi.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.sql.*;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
* @BelongsProject: spring-boot-scaffold
* @BelongsPackage: com.geekmice.sbeasypoi.utils
* @Author: pingmingbo
* @CreateTime: 2023-08-04 13:20
* @Description: TODO
* @Version: 1.0
*/
@SpringBootTest(classes = SbEasyPoiApplication.class)
@Slf4j
@RunWith(SpringRunner.class)
public class TestMain {
@Autowired
private UserDao userDao;
private String url = "jdbc:mysql://localhost:3306/school?rewriteBatchedStatements=true";
private String user = "root";
private String password = "root";
@Autowired
private UserService userService;
static ArrayList<User> list = new ArrayList<>();
@Autowired
private SqlSessionFactory sqlSessionFactory;
static {
for (int i = 0; i < 100000; i++) {
User build = User.builder().userName(RandomStringUtils.randomAlphabetic(4)).address(RandomStringUtils.random(7))
.sex(RandomStringUtils.randomAlphabetic(1)).birthday(new Date()).build();
list.add(build);
}
}
@Test
public void t3(){
long start = System.currentTimeMillis();
jdbcSave(list);
long end = System.currentTimeMillis();
long consumeTime = (end - start) / 1000;
log.info("耗时:【{}】",consumeTime);
}
private void jdbcSave(List<User> cachedList) {
SqlSession sqlSession = sqlSessionFactory.openSession();
Connection connection = sqlSession.getConnection();
PreparedStatement preparedStatement = null;
sqlSessionFactory.getConfiguration();
try {
Class.forName("com.mysql.cj.jdbc.Driver");
// connection = DriverManager.getConnection(url, user, password);
String sql = "insert into user(user_name,birthday,sex,address) values (?,?,?,?)";
preparedStatement = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
connection.setAutoCommit(false);
for (User item : cachedList) {
preparedStatement.setString(1, item.getUserName());
preparedStatement.setDate(2, new java.sql.Date(item.getBirthday().getTime()));
preparedStatement.setString(3, item.getSex());
preparedStatement.setString(4, item.getAddress());
preparedStatement.addBatch();
}
preparedStatement.executeBatch();
connection.commit();
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
} finally {
if (preparedStatement != null) {
try {
preparedStatement.close();
} catch (SQLException e) {
log.error("error msg:[{}]", e);
throw new RuntimeException(e);
}
}
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
log.error("error msg:[{}]", e);
}
}
}
}
}
批量查询开始
方案一:内置方法selectBatchIds
selectBatchIds根据主键查询
List<Employee> emps=employeeMapper.selectBatchIds(Arrays.asList(1,2,13,14) );
方法二:条件构造器QueryWrapper
List<Long> idList = new ArrayList<>(); // 批量查询的 ID 列表
// 添加要查询的 ID 到 idList 中
QueryWrapper<Entity> queryWrapper = new QueryWrapper<>();
queryWrapper.in("id", idList); // 设置查询条件,in("id", idList) 表示查询 id 字段在 idList 中的记录
List<Entity> entityList = entityMapper.selectList(queryWrapper); // 执行批量查询
方案三:编写动态SQL实现
<select id="studentList" resultType="com.ywt.springboot.model.Student">
select *
from student
where id in
<foreach collection="array" index="index" item="item" open="(" separator="," close=")">
#{item}
</foreach>
</select>
注:foreach中的 collection标签中为array,item是遍历ids中的每个元素,默认为item可以自定义。
sql
耗时
Consume Time:5 ms 2023-07-22 16:20:27
Execute SQL:SELECT id,name,age,email,field1,field2,field3,field4,field5,field6 FROM gk_user WHERE (id = '1682216842073980917')
添加依赖
<!--sql耗时-->
<!-- https://mvnrepository.com/artifact/p6spy/p6spy -->
<dependency>
<groupId>p6spy</groupId>
<artifactId>p6spy</artifactId>
<version>3.8.6</version>
</dependency>
yml配置
spring:
datasource:
username: root
password: root
url: jdbc:p6spy:mysql://localhost:3306/gk_mybatis-plus?useUnicode=true&characterEncoding=utf8&autoReconnect=true&rewriteBatchedStatements=true&serverTimezone=UTC&useSSL=false&allowMultiQueries=true
driver-class-name: com.p6spy.engine.spy.P6SpyDriver
添加属性文件spy.properties
#3.2.1以上使用
modulelist=com.baomidou.mybatisplus.extension.p6spy.MybatisPlusLogFactory,com.p6spy.engine.outage.P6OutageFactory
#3.2.1以下使用或者不配置
#modulelist=com.p6spy.engine.logging.P6LogFactory,com.p6spy.engine.outage.P6OutageFactory
# 自定义日志打印
logMessageFormat=com.baomidou.mybatisplus.extension.p6spy.P6SpyLogger
#日志输出到控制台
appender=com.baomidou.mybatisplus.extension.p6spy.StdoutLogger
# 使用日志系统记录 sql
#appender=com.p6spy.engine.spy.appender.Slf4JLogger
# 设置 p6spy driver 代理
deregisterdrivers=true
# 取消JDBC URL前缀
useprefix=true
# 配置记录 Log 例外,可去掉的结果集有error,info,batch,debug,statement,commit,rollback,result,resultset.
excludecategories=info,debug,result,commit,resultset
# 日期格式
dateformat=yyyy-MM-dd HH:mm:ss
# 实际驱动可多个
#driverlist=org.h2.Driver
# 是否开启慢SQL记录
outagedetection=true
# 慢SQL记录标准 2 秒
outagedetectioninterval=2