最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

MyBatisPlus mybatis-plus-join使用及說明

 更新時間:2026年04月26日 10:54:02   作者:@航空母艦  
本文介紹了MyBatisPlus的基本使用、集成SpringBoot的方法、代碼生成器等核心功能,以及@TableName、@TableField等注解的使用方法,并詳細(xì)說明了批量插入、Join查詢、StopWatch計時和Hutool工具的使用

一、MyBatis Plus 介紹

MyBatis Plus 是國內(nèi)人員開發(fā)的 MyBatis 增強工具,在 MyBatis 的基礎(chǔ)上只做增強不做改變,為簡化開發(fā)、提高效率而生。MybatisX 是一款基于 IDEA 的快速開發(fā)插件,為效率而生。

MyBatis Plus 的核心功能有:支持通用的 CRUD、代碼生成器與條件構(gòu)造器。

  • 通用 CRUD:定義好 Mapper 接口后,只需要繼承 BaseMapper<T> 接口即可獲得通用的增刪改查功能,無需編寫任何接口方法與配置文件
  • 條件構(gòu)造器:通過 EntityWrapper<T> (實體包裝類),可以用于拼接 SQL 語句,并且支持排序、分組查詢等復(fù)雜的 SQL
  • 代碼生成器:支持一系列的策略配置與全局配置,比 MyBatis的代碼生成更好用
/***
 * 通用刪除操作 deleteBatchIds 通過多個ID進行刪除
 */
@Test
public void testDeleteBatchIds() {
	List<Integer> idList = new ArrayList<Integer>();
	idList.add(5);
	idList.add(6);
	int result = employeeMapper.deleteBatchIds(idList);
	System.out.println("*******************" + result);
}

public void selectIn() {
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    wrapper.setSqlSelect(WinAgent.COL_ID, WinAgent.COL_AG_NUM);
    wrapper.in(User.COL_AG_NUM, new String[]{"11","22","33","44"});
    List agreeList = Arrays.asList(agreeMan.split(",|,"));
    if (agreeList.size() > 1) {
      wrapper.in(User.COL_CREATE_USER, agreeList);
    } else {
      wrapper.eq(User.COL_CREATE_USER, agreeList.get(0));
    }
    userMapper.selectList(wrapper);
}
/**
 * 根據(jù)條件構(gòu)造器刪除
 */
public void testDeleteByWrapper(){
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    // 參數(shù)1-字段名,參數(shù)2-匹配的值
    wrapper.eq("user_name", "lisi");
    // count代表刪除成功的記錄數(shù)
    int count = userMapper.delete(wrapper);
}
/***
 * 通用更新操作
 */
@Test
public void testUpdateOrInsert() {
	Employee entity = new Employee();
	entity.setId(1);
	entity.setName("更新測試成功");
	int result = employeeMapper.updateById(entity);
	//int result = employeeMapper.insert(entity);
    System.out.println("插入后:employee id="+entity.getId());
}

public void testUpdate() {
	Employee entity = new Employee();
	entity.setName("更新測試成功");
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    queryWrapper.eq("id", "1");
	int result = employeeMapper.update(entity, queryWrapper);
}

/**
 * 查詢所有數(shù)據(jù)
 * UserMapper 中的 selectList() 方法的參數(shù)
 * 為 MP 內(nèi)置的條件封裝器 Wrapper,所以不填寫就是無任何條件(條件構(gòu)造器)
 */
@Test
public void selectList() {
    List<User> list = userMapper.selectList(null);
    list.forEach(System.out::println);
}

/**
 * 根據(jù) entity 條件,查詢一條記錄
 * 其實 QueryWrapper 條件構(gòu)造器(相當(dāng)于給SQL的條件語句)
 * selectOne() 方法查詢必須有且只能查詢一條記錄,多一條會報錯。
 */
@Test
public void selectOne() {
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    //查詢名字為 Tom 的一條記錄
    queryWrapper.eq("name", "Tom");
    User user = userMapper.selectOne(queryWrapper);
    System.out.println(user);
}

/**
 * 根據(jù)主鍵ID查詢數(shù)據(jù)
 * 查詢主鍵id=2 的一條數(shù)據(jù),只能查詢一個主鍵的數(shù)據(jù)不能多個
 */
@Test
public void selectById() {

    User user = userMapper.selectById(1);
    System.out.println(user);
}

/**
 * 根據(jù) List 的 ID 集合 查詢對應(yīng)的用戶list
 */
@Test
public void selectBatchIds() {
    List<User> list = userMapper.selectBatchIds(Arrays.asList(new String[] { "1", "2" }));
    list.forEach(System.out::println);
}

/**
 * 查詢(根據(jù) columnMap 條件),查詢年齡為20歲的所有記錄
 * <p>
 * 注意:建議盡量減少使用map這種方式。
 * 因為可能字段名可能存在修改的情況,
 * 如果,項目開發(fā)一段時間后,再修改,影響太大
 */
@Test
public void selectByMap() {
    Map<String, Object> map = new HashMap<>();
    map.put("age", "20");
    List<User> list = userMapper.selectByMap(map);
    list.forEach(System.out::println);
}

/**
 * 查詢大于20歲的學(xué)生,名稱中包含“J”的人,帶條件判斷的,可以采用這種方式
 * SELECT * FROM user WHERE (name LIKE ? AND age > ?)
 * gt()方法 相當(dāng)于:大于 > 但沒有等于=
 */
@Test
public void selectListWrapper() {
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    queryWrapper.like("name", "J");//格式:(字段,值)
    queryWrapper.gt("age", "19"); //查詢不小于20歲
    List<User> list = userMapper.selectList(queryWrapper);
    list.forEach(System.out::println);
}

/**
 * 根據(jù) Wrapper 條件,查詢?nèi)坑涗洝?
 * 查詢名字含有 a 的,且年齡大于等于20。
 * ge()方法 相當(dāng)于: 大于等于 >= 。
 * like()方法  相當(dāng)于: NOT LIKE '%值%' 。
 */
@Test
public void selectMaps() {
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    queryWrapper.like("name", "a");
    queryWrapper.ge("age", "20");
    List<Map<String, Object>> maps = userMapper.selectMaps(queryWrapper);
    maps.forEach(System.out::println);
}

/**
 * 根據(jù) Wrapper 條件,查詢總記錄數(shù)
 * 查詢一共有多少條數(shù)據(jù)記錄
 */
@Test
public void selectCount() {
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    Integer count = userMapper.selectCount(queryWrapper);
    System.out.printf("一共有" + String.valueOf(count) + "條記錄");
}

不更新名稱,前提沒有配置FieldStrategy.IGNORED

Employee entity = new Employee();
entity.setId(1);
entity.setName(null);
employeeMapper.updateById(entity);

查詢括號與SQL打印

//有很多中Wrapper實現(xiàn)類,我也不是很了解,這里我使用的是EntityWrapper
EntityWrapper wrapper = new EntityWrapper();
wrapper.eq("status", status);
wrapper.andNew().gt("gmt_end", now).or().isNotNull("days");
Integer count = couponMapper.selectCount(wrapper);
// 打印生成的SQL
log.info("生成的SQL: {}", wrapper.getSqlSegment());

SELECT COUNT(1) FROM unimall_coupon WHERE status = 1 AND (gmt_end > '2019-07-14 16:14:23.51' OR days IS NOT NULL)

分頁查詢

/**
 * 根據(jù) entity 條件,查詢?nèi)坑涗洠ú⒎摚?
 * 查詢年齡大于 18 且 小于等于30 歲的所有記錄,分 3 條數(shù)記錄為一頁
 * gt()方法 相當(dāng)于: 大于 > 。
 * le()方法 相當(dāng)于: 小于等于 <= 。
 */
@Test
public void selectPage() {
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    queryWrapper.gt("age", "18");
    queryWrapper.le("age", "30");
    //第一個參數(shù)表示當(dāng)前頁
    //第二個參數(shù)表示當(dāng)前頁顯示多少條
    //第三個參數(shù)是否查詢count
    Page<User> page = new Page<>(1, 3);
    Page<User> userIPage = userMapper.selectPage(page, queryWrapper);
    List<User> records = userIPage.getRecords();
    records.forEach(System.out::println);
}

public void selectPage1() {
	Wrapper<User> wrapper = new EntityWrapper<>();
	wrapper.last("limit 0,30");
	List<User> list = this.selectList(wrapper);
}
/**
 * 根據(jù) Wrapper 條件,查詢?nèi)坑涗洠ú⒎摚?
 */
@Test
public void selectMapsPage() {
    QueryWrapper<User> query = new QueryWrapper<User>();
    //第一個參數(shù)表示當(dāng)前頁
    //第二個參數(shù)表示當(dāng)前頁顯示多少條
    Page<Map<String, Object>> page = new Page<>(2, 3);
    Page<Map<String, Object>> maps = userMapper.selectMapsPage(page, query);
    maps.getRecords().forEach(System.out::println);
}

queryWrapper是mybatis plus中實現(xiàn)查詢的對象封裝操作類.。

LambdaQueryWrapper<BillChargeInfo> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(BillChargeInfo::getTransactionNo, transactionNo);
wrapper.last("limit 1");
return baseMapper.selectOne(wrapper);

注意這是因為我的mybatisplus的版本是3.2版本,只有3.x的版本才有QueryWrapper,而如果是2.x版本,是沒有QueryWrapper的,如果找不到QueryWrapper,可以在配置里將mybatisplus的版本改為3.x

<mybatis-plus.version>2.2.0</mybatis-plus.version>

或者使用EntityWrapper,兩者的功能其實差不多。 

條件參數(shù)說明

二、MyBatis Plus 集成 Spring

數(shù)據(jù)表結(jié)構(gòu)

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

創(chuàng)建一個 SpringBoot 項目。直接使用 IDE 工具創(chuàng)建一個。 Spring Initializer。從 Spring Boot 3 開始,官方不再支持 Java 8 和 Java 11

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.6.3</version> <!-- 使用支持的版本號 -->
</parent>

注意選擇Type,JDK等.

輸入Group、Artifact、Package的對應(yīng)的信息,再點擊next 

注意:這里必須得選擇web,否則demo不能使用controller層。 在我們的實際項目中,最好還是要引用spring-boot release版本的

添加 MyBatis-Plus 依賴(mybatis-plus-boot-starter)

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.3.1</version>
</dependency>

使用 mysql,需要引入 mysql 相關(guān)依賴。為了簡化代碼,引入 lombok 依賴

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.10</version>
</dependency>
<!-- 工具類相關(guān) -->
<dependency>
    <groupId>org.mapstruct</groupId>
    <artifactId>mapstruct</artifactId> <!-- use mapstruct-jdk8 for Java 8 or higher -->
</dependency>
<dependency>
    <groupId>org.mapstruct</groupId>
    <artifactId>mapstruct-jdk8</artifactId>
</dependency>
<!-- 測試相關(guān)  -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>

完整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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.6.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.lyh.test</groupId>
    <artifactId>test-mybatis-plus</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>test-mybatis-plus</name>
    <description>測試 -- 測試 MyBatis-Plus 功能</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.10</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
            <version>3.3.1</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

mysql數(shù)據(jù)源

在 resources/application.yml 文件中配置 mysql 數(shù)據(jù)源信息。

server:
  port: 2525
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    password: 123456
    url: jdbc:mysql://localhost:3306/testMyBatisPlus?useUnicode=true&characterEncoding=utf8
mybatis-plus:
  mapper-locations: classpath:mapper/*.xml
  configuration:
    map-underscore-to-camel-case: true
    cache-enabled: false
    jdbc-type-for-null: null

該配置表示 MyBatis-Plus 會在 resources/mapper/ 目錄下查找所有的 .xml 文件作為 Mapper 映射文件 src/main/resources/mapper/*Mapper.xml 

三、快速體驗 MyBatis Plus

實體類

package entity;

import lombok.Data;

@Data
public class User {
    private Long id;
    private String name;
    private int age;
    private String email;
}

mapper 接口,這是 mybatis-plus 封裝好的類。

@Select @Update

package mapper;

import entity.User;

import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.toolkit.Constants;

import java.util.List;

public interface UserMapper extends BaseMapper<User> {
    //@Select("SELECT * FROM user where name = #{name}")
    //List<User> selectByName(@Param("name") String name);

    @Update({"UPDATE user SET supplier_fee_id=null,category_id=#{categoryId},supplier_id=#{supplierId} WHERE number_type=#{numberType} AND number=#{phone}"})
    boolean updateUserByPhone(@Param("phone") String phone, @Param("numberType") Integer numberType, @Param("supplierId") Integer supplierId, @Param("categoryId") Integer categoryId);
    
    //傳入對象參數(shù)xml方式
    //List<User> selectAllUsers(@Param("user") User user, @Param("bm") String bm);
}

實體類、Mapper 類都寫好了,就可以使用了。接口綁定有兩種實現(xiàn)方式,一種是通過注解綁定,就是在接口的方法上面加上@Select @Update 等注解里面包含 Sql 語句來綁定,另外一種就是通過xml 里面寫 SQL 來綁定,在這種情況下,要指定 xml 映射文件里面的namespace 必須為接口的全路徑名。當(dāng) Sql 語句比較簡單時候,用注解綁定;當(dāng) SQL 語句比較復(fù)雜時候,用 xml 綁定,一般用 xml 綁定的比較多

添加UserMapper.xml文件(可省略) 

對于$和#的用法區(qū)別

簡單來說 #{} 會在將參數(shù)加上引號,而${}并不會在給參數(shù)加上引號。mybatis對參數(shù)沒有進行任何的處理。通常${}用于GROUP BY,ORDER BY,IN等的后面

但是,實際應(yīng)用中,并不提倡使用 ${},因為使用 #{} 寫法,除了可以防止sql注入以外,還能在參數(shù)里含有單引號的時候自動轉(zhuǎn)義

<?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="UserMapper">
    <select id="findUserCount" resultType="java.lang.Integer">
        select count(1) from user
    </select>
    <select id="selectAllUsers" resultMap="BaseResultMap">
        select * from user where number_type = ${@net.test.api.constants.ProductEnum@PHONE400.type}
        <if test="user.name != null and user.name != ''">
            and name like '%${user.name}%'
        </if>
        <if test="user.startTime != null ">
            AND start_time>='${user.startTime} 00:00:00' and <![CDATA[ start_time<='${user.startTime} 23:59:59' ]]>
        </if>
    </select>
</mapper>

ServiceImpl層 通用的IService實現(xiàn)crud功能

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Autowired
    private UserMapper userMapper;

    public Integer getUserNum() {
        return userMapper.findUserCount();
    }

    // 增
    @Override
    public int insertUser(User user) {
        return insert(user);
    }
    
    // 改
    @Override
    public int updateUser(User user) {
        return updateById(user);
    }
    
    // 刪
    @Override
    public int deleteUser(User user) {
        Integer id = user.getUserId();
        return deleteById(id);
    }
    
    // 查
    @Override
    public User findUserByName(String userName) {
        return baseMapper.getUserByName(userName);
    }

    // 分頁查
    @Override
    public IPage getUserPage(Page page, User user) {
        return baseMapper.getUsersPage( page, user );
    }
}

Service層

public interface UserService extends IService<User> {
  
   Integer getUserNum();

   int insertUser( User user );
   int updateUser( User user );
   int deleteUser( User user );
   User findUserByName( String userName );
   IPage getUserPage( Page page, User user );

Step1:啟動類里掃描 Mapper 類,即添加 @MapperScan 注解

package com.lyh.test.testmybatisplus;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@MapperScan({"com.kfit.*.mapper","org.kfit.*.mapper"})
@SpringBootApplication
public class TestMybatisPlusApplication {

    public static void main(String[] args) {
        SpringApplication.run(TestMybatisPlusApplication.class, args);
    }

}

多module項目掃描失敗解決: Consider defining a bean of type 'xxx' in your configuration

@SpringBootApplication(scanBasePackages = {"com.xx.xx.xx.A", "com.xx.xx.common"})

Step2:寫一個測試類測試一下。

package com.lyh.test.testmybatisplus;

import entity.User;
import mapper.UserMapper;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

@SpringBootTest
class TestMybatisPlusApplicationTests {

    @Autowired
    private UserMapper userMapper;

    @Test
    public void testSelect() {
        System.out.println(("----- selectAll method test ------"));
        List<User> userList = userMapper.selectList(null);
        for(User user:userList) {
            System.out.println(user);
        }
    }

    @Test
    public void testSelectBySql() {
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper();
        wrapper.like("name" , "k").lt("age", 40).last("limit 4");

        List<User> userList = userMapper.selectBySql(wrapper);
        userList.forEach(System.out::println);
    }
}

上面幾個例子中,并沒有在 UserMapper 接口中定義任何方法,也沒有在配置文件中編寫 SQL 語句,而是通過繼承 BaseMapper 接口獲得通用的的增刪改查方法,復(fù)雜的 SQL 也可以使用條件構(gòu)造器拼接。通過這兩種方式已經(jīng)能夠滿足很多的開發(fā)需求了,不過復(fù)雜的業(yè)務(wù)需求還是要編寫 SQL 語句的,流程和 MyBatis 一樣。

若遇到 @Autowired 標(biāo)記的變量出現(xiàn) 紅色下劃線,但是不影響 正常運行??梢赃M入 Settings,找到 Inspection,并選擇其中的 Spring Core -> Code -> Autowiring for Bean Class,將 Error 改為 Warning,即可。

四、代碼生成器

package com.example.demo;

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.rules.NamingStrategy;

/**
 * MybatisPlus代碼生成器
 */
public class MybatisPlusGeneratorRunner {
    public static final String MYSQL_DRIVER = "com.mysql.cj.jdbc.Driver";
    //模塊名 如果有模塊名,則需在模塊名前加. 例:log
    public static final String MODULE_NAME = "";
    public static final String AUTHOR = "danny";
    public static final String MYSQL_URL = "jdbc:mysql://locallhost:3306/test?serverTimezone=UTC";
    public static final String USERNAME = "root";
    public static final String PASSWORD = "0rb!t";
    public static final String[] DB_TABLE_NAMES = {"user", "role"};
    public static final String PACKAGE_NAME = "cn.kerninventory.mybatis";

    public static void main(String[] args) {
        AutoGenerator generator = new AutoGenerator();
        //配置數(shù)據(jù)庫連接參數(shù)
        DataSourceConfig dataSourceConfig = new DataSourceConfig();
        dataSourceConfig.setDriverName(MYSQL_DRIVER);
        dataSourceConfig.setUrl(MYSQL_URL);
        dataSourceConfig.setUsername(USERNAME);
        dataSourceConfig.setPassword(PASSWORD);
        generator.setDataSource(dataSourceConfig);

        //配置文件生成路徑參數(shù)
        PackageConfig packageConfig = new PackageConfig();
        packageConfig.setModuleName(MODULE_NAME);
        packageConfig.setParent(PACKAGE_NAME);
        packageConfig.setEntity("entity");
        packageConfig.setXml("xml");
        packageConfig.setMapper("mapper");
        //packageConfig.setServiceImpl("serviceimpl");
        packageConfig.setService("service");
        packageConfig.setController("controller");
        generator.setPackageInfo(packageConfig);

        //策略配置
        StrategyConfig strategyConfig = new StrategyConfig();
        //表名轉(zhuǎn)駝峰
        strategyConfig.setNaming(NamingStrategy.underline_to_camel);
        //字段駝峰命名
        strategyConfig.setColumnNaming(NamingStrategy.underline_to_camel);
        //set方法builder模式
        strategyConfig.setChainModel(true);
        //使用lombok注解
        strategyConfig.setEntityLombokModel(true);
        //不生成serial version uuid
        //strategyConfig.setEntitySerialVersionUID(false);
        //要生成的表名
        strategyConfig.setInclude(DB_TABLE_NAMES);
        //rest風(fēng)格
        strategyConfig.setRestControllerStyle(true);
        //是否生成字段常量
		strategyConfig.setEntityColumnConstant(true);
        //是否生成實體時,生成字段注解
        strategyConfig.setEntityTableFieldAnnotationEnable(true);
        generator.setStrategy(strategyConfig);

        //全局配置
        GlobalConfig globalConfig = new GlobalConfig();
        globalConfig.setServiceName("%sService");
		globalConfig.setXmlName("mapper");
        globalConfig.setBaseResultMap(true);  //XML中的ResultMap標(biāo)簽
        globalConfig.setBaseColumnList(true); //XML標(biāo)簽
        globalConfig.setOpen(false); //不彈出生成目錄
        //輸出目錄
        globalConfig.setOutputDir(System.getProperty("user.dir") + "/src/main/java");
        globalConfig.setAuthor(AUTHOR);
        generator.setGlobalConfig(globalConfig);
        generator.execute();
    }
}

五、@TableField注解

  • @TableField(exist = false) 注解加載bean屬性上,表示當(dāng)前屬性不是數(shù)據(jù)庫的字段,但在項目中必須使用,這樣在新增等使用bean的時候,mybatis-plus就會忽略這個,不會報錯
  • @TableField(.. , update="%s+1") 其中 %s 會填充為字段。輸出 SQL 為:update 表 set 字段=字段+1 @TableField(.. , update="now()") 輸出 SQL 為:update 表 set 字段=now() where 
  • @TableField(condition = SqlCondition.LIKE) 輸出 SQL 為:select 表 where name LIKE CONCAT('%',值,'%')
  • @TableField(fill = FieldFill.INSERT)插入自動填充,F(xiàn)ieldFill.INSERT_UPDATE在插入和更新操作時的自動填充 private Date updateTime;
  • @TableField("`inout`") 避免關(guān)鍵字沖突
  • @TableField(select = false) 把一些敏感數(shù)據(jù)查詢到返回給前端,這個時候我們就需要限制哪些字段默認(rèn)不要進行查詢。如:密碼
  • @TableField(value = "user_name")
    private String userName;   setSqlSelect("user_name")可能識別不了。換成setSqlSelect("user_name as userName")

@TableName注解

  • @TableName(value = "my_table_name")  表名和類名不一致時指定

Mybatis-plus批量插入

saveBatch方法分析:底層也是通過for來完成,默認(rèn)是一個事務(wù)一次提交N條數(shù)據(jù)。即偽批量性能比較差。引入依賴,3.4.0之上的版本都可以

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.5.2</version>
</dependency>

insertBatchSomeColumn

自定義SQL注入器

import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.core.injector.AbstractMethod;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.extension.injector.methods.InsertBatchSomeColumn;
import com.github.yulichang.injector.MPJSqlInjector;
import java.util.List;

/**
 * mybatis-plus-join兼容批量插入
 *
 * @author hudy
 */
public class InsertBatchSqlInjector extends MPJSqlInjector {

  /**
   * 獲取方法列表
   *
   * @param mapperClass Mapper 類
   * @param tableInfo   表信息
   * @return 方法列表
   */
  @Override
  public List<AbstractMethod> getMethodList(Class<?> mapperClass, TableInfo tableInfo) {
    // 保留 Mybatis Plus-Join 自帶的方法
    List<AbstractMethod> methodList = super.getMethodList(mapperClass, tableInfo);
    // 添加自定義方法:批量插入,方法名為 insertBatchSomeColumn
    // 過濾掉僅在更新時填充的字段
    methodList.add(new InsertBatchSomeColumn(i -> i.getFieldFill() != FieldFill.UPDATE));
    return methodList;
  }
}

版本2:注意根據(jù)plus的版本api不同選擇

import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.core.injector.AbstractMethod;
import com.baomidou.mybatisplus.core.injector.DefaultSqlInjector;
import com.baomidou.mybatisplus.extension.injector.methods.InsertBatchSomeColumn;
import java.util.List;

/**
 * @author hudeyong 批量插入 SQL 注入器.
 * @date 2025/7/24
 */
public class InsertBatchSqlInjector extends DefaultSqlInjector {

  @Override
  public List<AbstractMethod> getMethodList(Class<?> mapperClass) {
    // super.getMethodList() 保留 Mybatis Plus 自帶的方法
    List<AbstractMethod> methodList = super.getMethodList(mapperClass);
    // 添加自定義方法:批量插入,方法名為 insertBatchSomeColumn
    methodList.add(new InsertBatchSomeColumn(i -> i.getFieldFill() != FieldFill.UPDATE));
    return methodList;
  }
}

在MyBatis-Plus配置類中注冊該注入器

  /**
   * 自定義批量插入 SQL 注入器.
   */
  @Bean
  public InsertBatchSqlInjector insertBatchSqlInjector() {
    return new InsertBatchSqlInjector();
  }

到此定義完畢,繼承下面定義的 MyBaseMapper,你就可以撒手不管了,直接調(diào)用就行?;蛘咧苯釉赟erviceImpl通過Mapper調(diào)用insertBatchSomeColumn,然后ALT+回車生成此方法

import com.github.yulichang.base.MPJBaseMapper;
import java.util.List;
import org.apache.ibatis.annotations.Param;

/**
 * MPJBaseMapper 是mybatis-plus-join插件提供的Mapper接口
 *
 * @author hudeyong
 * @date 2025/7/24
 */
public interface MyBaseMapper<T> extends MPJBaseMapper<T> {

  /**
   * 執(zhí)行批量插入操作,針對指定列表中的對象插入數(shù)據(jù)庫。 此方法專注于通過批量操作提高數(shù)據(jù)插入的效率,而不是逐個插入對象。這有助于減少數(shù)據(jù)庫訪問次數(shù),從而提高性能。
   *
   * @param batchList 待插入數(shù)據(jù)庫的對象列表。列表中的每個對象都將被插入到數(shù)據(jù)庫中, 注意,對象的屬性和數(shù)據(jù)庫表的字段需要對應(yīng),以便正確插入數(shù)據(jù)。
   * @return 返回插入操作影響的行數(shù)。這可以用于判斷插入操作的成功與否,或者了解操作的范圍。
   */
  int insertBatchSomeColumn(@Param("list") List<T> batchList);
}

baseService

import java.util.ArrayList;
import java.util.List;

public class BaseServiceImpl<M extends MyBaseMapper<T>, T> extends ServiceImpl<M, T> implements
    IMyService<T> {

  @Override
  public int insertBatchSomeColumn(List<T> entityList) {
    return this.baseMapper.insertBatchSomeColumn(entityList);
  }

  @Override
  public int insertBatchSomeColumn(List<T> entityList, int batchSize) {
    int size = entityList.size();
    if (size < batchSize) {
      return this.baseMapper.insertBatchSomeColumn(entityList);
    }
    int page = 1;
    if (size % batchSize == 0) {
      page = size / batchSize;
    } else {
      page = size / batchSize + 1;
    }
    for (int i = 0; i < page; i++) {
      List<T> sub = new ArrayList<>();
      if (i == page - 1) {
        sub = entityList.subList(i * batchSize, entityList.size());
      } else {
        sub.subList(i * batchSize, (i + 1) * batchSize);
      }
      if (sub.size() > 0) {
        this.baseMapper.insertBatchSomeColumn(sub);
      }

    }
    return size;
  }
}

測試代碼,調(diào)用insertBatchSomeColumn方法

@Test
void testInsertBatch() {
    List<User> users = new ArrayList<>();
    for (int i = 0; i < 3; i++) {
        User user = new User();
        user.setName("犬小哈" + i);
        user.setAge(i);
        user.setGender(1);
        users.add(user);
    }
 
    userMapper.insertBatchSomeColumn(users);
}

mybatis-plus-join用法

mybatis plus 封裝的 mapper 不支持 join,如果需要支持就必須自己去實現(xiàn)。但是對于大部分的業(yè)務(wù)場景來說,都需要多表 join。MyBatis-Plus-Join(MPJ)框架提供的基礎(chǔ) Mapper 接口,需要 Mybatis-plus version >= 3.4.0。它是對 MyBatis-Plus 的 BaseMapper 的擴展,主要增強了以下功能:

  • 聯(lián)表查詢支持:提供了便捷的多表關(guān)聯(lián)查詢能力
  • 復(fù)雜查詢構(gòu)建:支持更復(fù)雜的 SQL 查詢構(gòu)建
  • 繼承 BaseMapper:保留了 BaseMapper 的所有基礎(chǔ)功能。

安裝

  • maven
<dependency>
    <groupId>com.github.yulichang</groupId>
    <artifactId>mybatis-plus-join</artifactId>
    <version>1.4.5</version>
</dependency>

使用

  • mapper繼承MPJBaseMapper (必選)
  • service繼承MPJBaseService (可選)
  • serviceImpl繼承MPJBaseServiceImpl (可選)

查詢例子

// 多表連接查詢
MPJLambdaWrapper<HotelJob> wrapper = new MPJLambdaWrapper<HotelJob>()
    .selectAll(HotelJob.class)
    .select(Hotel::getHotelName, City::getCityName)
    .leftJoin(Hotel.class, Hotel::getId, HotelJob::getHotelId)
    .leftJoin(City.class, City::getId, Hotel::getCityId)
    .eq(Hotel::getStatus, 1)
    .eq(City::getIsActive, true)
    .groupBy(HotelJob::getJobType)
    .having(HotelJob::getJobType, ">", 5);

List<HotelJob> result = mapper.selectJoinList(HotelJob.class, wrapper);


// 聚合函數(shù)使用
MPJLambdaWrapper<HotelJob> wrapper = new MPJLambdaWrapper<HotelJob>()
    .selectSum(HotelJob::getSalary, "totalSalary")
    .selectCount(HotelJob::getId, "jobCount")
    .selectAs(Hotel::getHotelName, "hotelName")
    .leftJoin(Hotel.class, Hotel::getId, HotelJob::getHotelId)
    .groupBy(Hotel::getId);

List<Map<String, Object>> result = mapper.selectJoinMaps(wrapper);

其他

Java計時StopWatch的使用方法詳解

StopWatch 是位于 org.springframework.util 包下的一個工具類,通過它可方便的對程序部分代碼進行計時(ms級別),適用于同步單線程代碼塊。簡單總結(jié)一句,Spring提供的計時器StopWatch對于秒、毫秒為單位方便計時的程序,尤其是單線程、順序執(zhí)行程序的時間特性的統(tǒng)計輸出支持比較好。也就是說假如我們手里面有幾個在順序上前后執(zhí)行的幾個任務(wù),而且我們比較關(guān)心幾個任務(wù)分別執(zhí)行的時間占用狀況,希望能夠形成一個不太復(fù)雜的日志輸出,StopWatch提供了這樣的功能。而且Spring的StopWatch基本上也就是僅僅為了這樣的功能而實現(xiàn)。

想要使用它,首先你需要在你的 Maven 中引入 Spring 核心包,當(dāng)然 Spring MVC 和 Spring Boot 都已經(jīng)自動引入了該包:

<!-- https://mvnrepository.com/artifact/org.springframework/spring-core -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-core</artifactId>
    <version>${spring.version}</version>
</dependency>

對一切事物的認(rèn)知,都是從使用開始,那就先來看看它的用法,會如下所示:

public static void main(String[] args) throws InterruptedException {
    StopWatch stopWatch = new StopWatch();

    // 任務(wù)一模擬休眠3秒鐘
    stopWatch.start("TaskOneName");
    Thread.sleep(1000 * 3);
    System.out.println("當(dāng)前任務(wù)名稱:" + stopWatch.currentTaskName());
    stopWatch.stop();

    // 任務(wù)一模擬休眠10秒鐘
    stopWatch.start("TaskTwoName");
    Thread.sleep(1000 * 10);
    System.out.println("當(dāng)前任務(wù)名稱:" + stopWatch.currentTaskName());
    stopWatch.stop();

    // 任務(wù)一模擬休眠10秒鐘
    stopWatch.start("TaskThreeName");
    Thread.sleep(1000 * 10);
    System.out.println("當(dāng)前任務(wù)名稱:" + stopWatch.currentTaskName());
    stopWatch.stop();

    // 打印出耗時
    System.out.println(stopWatch.prettyPrint());
    System.out.println(stopWatch.shortSummary());
    // stop后它的值為null
    System.out.println(stopWatch.currentTaskName()); 
    
    // 最后一個任務(wù)的相關(guān)信息
    System.out.println(stopWatch.getLastTaskName());
    System.out.println(stopWatch.getLastTaskInfo());
    
    // 任務(wù)總的耗時  如果你想獲取到每個任務(wù)詳情(包括它的任務(wù)名、耗時等等)可使用
    System.out.println("所有任務(wù)總耗時:" + sw.getTotalTimeMillis());
    System.out.println("任務(wù)總數(shù):" + sw.getTaskCount());
    System.out.println("所有任務(wù)詳情:" + sw.getTaskInfo());
}

Hutool工具

Hutool是一個小而全的Java工具類庫,通過靜態(tài)方法封裝,降低相關(guān)API的學(xué)習(xí)成本,提高工作效率,使Java擁有函數(shù)式語言般的優(yōu)雅。Hutool是對文件、流、加密解密、轉(zhuǎn)碼、正則、線程、XML等JDK方法進行封裝,組成各種Util工具類。

在項目的pom.xml的dependencies中加入以下內(nèi)容:

<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <version>5.5.2</version>
</dependency>

禁用 netflix-eureka 客戶端

  • Spring Cloud Eureka主要負(fù)責(zé)實現(xiàn)微服務(wù)架構(gòu)中的服務(wù)治理功能
  • SpringCloudGateway作為SpringCloud生態(tài)系中的網(wǎng)關(guān),為微服務(wù)架構(gòu)提供統(tǒng)一的路由管理,并且根據(jù)http請求進行相應(yīng)的匹配、斷言、過濾
eureka.client.enabled=false

事務(wù)處理

public class TransactionStatusUtils {
    @Autowired
    PlatformTransactionManager dataSourceTransactionManager;

    public TransactionStatus getTransactionStatus(DataSourceType dbType){
        DbContextHolder.setDbType(dbType);
        DefaultTransactionDefinition transactionDefinition = new DefaultTransactionDefinition();
        transactionDefinition.setPropagationBehavior(DefaultTransactionDefinition.PROPAGATION_REQUIRES_NEW);
        TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);
        return transactionStatus;
    }

    public void commit(TransactionStatus transactionStatus) {
      dataSourceTransactionManager.commit(transactionStatus);
    }

    public void rollback(TransactionStatus transactionStatus) {
      dataSourceTransactionManager.rollback(transactionStatus);
    }
}

MyBatisPlus 獲取實體表名或字段名

MyBatis Plus 通過實體的原理是通過TableId,TableField,TableName等注解或?qū)傩悦Q/類名稱轉(zhuǎn)下劃線實現(xiàn)的

//表名
SqlHelper.table(User.class).getTableName();
//主鍵
SqlHelper.table(User.class).getKeyColumn();
//獲取userName的數(shù)據(jù)庫字段
WrapperKit.getTableFieldInfoByProperty(User.class, "userName").getColumn();

import com.baomidou.mybatisplus.entity.TableFieldInfo;
import com.baomidou.mybatisplus.entity.TableInfo;
import com.baomidou.mybatisplus.toolkit.TableInfoHelper;
import java.util.List;

public class WrapperKit {

  /**
   * 獲取主鍵的實體屬性名
   *
   * @param cls
   * @return
   */
  public static String getTableIdProperty(Class<?> cls) {
    return TableInfoHelper.getTableInfo(cls).getKeyProperty();
  }

  public static List<TableFieldInfo> getTableFieldInfo(Class<?> cls) {
    TableInfo tableInfo = TableInfoHelper.getTableInfo(cls);
    return tableInfo.getFieldList();
  }

  public static TableFieldInfo getTableFieldInfoByProperty(Class<?> cls, String property) {
    final List<TableFieldInfo> tableFieldInfoList = getTableFieldInfo(cls);
    for (TableFieldInfo tableFieldInfo : tableFieldInfoList) {
      if (tableFieldInfo.getProperty().equals(property)) {
        return tableFieldInfo;
      }
    }
	if (!getTableIdProperty(cls).equals(property)) {
		System.out.println(cls.toString() + " 屬性" + property + "不存在,或?qū)傩詻]有配置@TableField");
	} else {
		System.out.println(property + "主鍵不支持,因為@TableId不會加入到fieldList");
	}
    return null;
  }

  public static <T> void appendDynamicEqual(Wrapper<T> wrapper, Object model, String... attrs) {
    TableInfo tableInfo = TableInfoHelper.getTableInfo(model.getClass());
    List<TableFieldInfo> fieldList = tableInfo.getFieldList();
    Map<String, TableFieldInfo> collect = fieldList.stream()
        .collect(Collectors.toMap(TableFieldInfo::getProperty, account -> account));
    for (String attr : attrs) {
      String[] attrArray = attr.split(":");
      // 最后一個就是真實的
      String reallyAttrName = attrArray[attrArray.length - 1];
      Object attrValue = ReflectionKit.getMethodValue(model, reallyAttrName);
      if (attrValue == null) {
        continue;
      }
      if (String.class.equals(attrValue.getClass()) && StrKit.isEmpty((String) attrValue)) {
        continue;
      }

      TableFieldInfo tableFieldInfo = collect.get(reallyAttrName);
      if (attrArray.length > 1) {
        switch (attrArray[0]) {
          case "in":
            wrapper.in(tableFieldInfo.getColumn(), attrValue.toString());
            break;
          case "like":
            wrapper.like(tableFieldInfo.getColumn(), attrValue.toString());
            break;
          case "notlike":
            wrapper.notLike(tableFieldInfo.getColumn(), attrValue.toString());
            break;
          default:
            wrapper.eq(tableFieldInfo.getColumn(), attrValue);
            break;
        }
      } else {
        wrapper.eq(tableFieldInfo.getColumn(), attrValue);
      }
    }
  }
}

更新不了空字符串或NULL問題

  • 使用 FieldStrategy.IGNORED 允許設(shè)置 null 值
  • 使用 FieldStrategy.NOT_EMPTY 會忽略 null 和空字符串
  • 使用 FieldStrategy.NOT_NULL 只會忽略 null 值
@TableField(strategy = FieldStrategy.IGNORED)

The valid characters are defined in RFC 7230 and RFC 3986

在yml中配置

server:
  tomcat:
    relaxedQueryChars: <,>, [,],^,`,{,|,} #參數(shù)內(nèi)容
    relaxedPathChars: <,>, [,],^,`,{,|,} #參數(shù)名稱

總結(jié)

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • spring實現(xiàn)動態(tài)切換、添加數(shù)據(jù)源及源碼分析

    spring實現(xiàn)動態(tài)切換、添加數(shù)據(jù)源及源碼分析

    這篇文章主要給大家介紹了關(guān)于spring實現(xiàn)動態(tài)切換、添加數(shù)據(jù)源及源碼分析的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2018-09-09
  • SpringBoot使用PageHelper插件實現(xiàn)Mybatis分頁效果

    SpringBoot使用PageHelper插件實現(xiàn)Mybatis分頁效果

    這篇文章主要介紹了SpringBoot使用PageHelper插件實現(xiàn)Mybatis分頁效果,本文通過實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作有一定的參考借鑒價值,需要的朋友可以參考下
    2024-02-02
  • Java多線程系列之JDK并發(fā)包舉例詳解

    Java多線程系列之JDK并發(fā)包舉例詳解

    Java并發(fā)包提供了許多用于多線程編程的類和接口,這篇文章主要給大家介紹了關(guān)于Java多線程系列之JDK并發(fā)包的相關(guān)資料,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2024-03-03
  • Java實現(xiàn)爬取百度圖片的方法分析

    Java實現(xiàn)爬取百度圖片的方法分析

    這篇文章主要介紹了Java實現(xiàn)爬取百度圖片的方法,結(jié)合實例形式分析了java基于jsonp爬取百度圖片的相關(guān)原理、操作技巧與注意事項,需要的朋友可以參考下
    2018-12-12
  • Java基于Swing實現(xiàn)的打獵射擊游戲代碼

    Java基于Swing實現(xiàn)的打獵射擊游戲代碼

    這篇文章主要介紹了Java基于Swing實現(xiàn)的打獵射擊游戲代碼,包含完整的游戲事件處理與邏輯流程控制,具有不錯的參考借鑒價值,需要的朋友可以參考下
    2014-11-11
  • Spring中如何通過多種方式實現(xiàn)使用線程

    Spring中如何通過多種方式實現(xiàn)使用線程

    這篇文章主要介紹了Spring中如何通過多種方式實現(xiàn)使用線程,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2025-05-05
  • ScheduledThreadPoolExecutor巨坑解決

    ScheduledThreadPoolExecutor巨坑解決

    這篇文章主要為大家介紹了使用ScheduledThreadPoolExecutor遇到的巨坑解決示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-02-02
  • Java類和對象全面解析

    Java類和對象全面解析

    本文介紹了Java面向?qū)ο缶幊痰暮诵母拍?文章通過具體代碼示例,幫助讀者理解Java面向?qū)ο缶幊痰幕驹砗蛯嵺`方法,感興趣的朋友跟隨小編一起看看吧
    2026-05-05
  • 基于Java編寫簡易的算式測試程序

    基于Java編寫簡易的算式測試程序

    本文將利用Java語言編寫一個簡易的算式測試程序,這個程序可以自動生成指定數(shù)量的加減乘三則運算題目,感興趣的小伙伴可以了解一下
    2022-05-05
  • VsCode配置java環(huán)境的詳細(xì)圖文教程

    VsCode配置java環(huán)境的詳細(xì)圖文教程

    vscode是一個免費的代碼編輯器,支持多種主題,應(yīng)用起來簡單方便,下面這篇文章主要給大家介紹了關(guān)于VsCode配置java環(huán)境的詳細(xì)圖文教程,文中通過圖文介紹的非常詳細(xì),需要的朋友可以參考下
    2023-02-02

最新評論

富顺县| 乐东| 涞源县| 玛纳斯县| 鸡东县| 财经| 张家口市| 堆龙德庆县| 邵阳县| 霸州市| 长泰县| 孟津县| 应城市| 广水市| 宁化县| 嘉义县| 商河县| 探索| 龙游县| 抚宁县| 无棣县| 大理市| 兴国县| 罗源县| 永胜县| 高淳县| 三穗县| 东光县| 邓州市| 金平| 连江县| 喀喇沁旗| 房产| 广德县| 容城县| 雷山县| 榕江县| 卢氏县| 永登县| 呼和浩特市| 阳谷县|