mybatisplus学习笔记

准备工作

参考网址

Mybatis中#{}和${}的区别

{}是预编译处理,${}是字符串替换。

  • 在处理#{}时,会将sql中的#{}替换为?号,调用PreparedStatement的set方法来赋值;

  • 在处理${}时,就是把${}替换成变量的值。

使用#{}可以有效的防止SQL注入,提高系统安全性。

准备数据

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for orders
-- ----------------------------
DROP TABLE IF EXISTS `orders`;
CREATE TABLE `orders`  (
  `id` bigint NOT NULL,
  `price` int NULL DEFAULT NULL,
  `remark` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `user_id` int NULL DEFAULT NULL,
  `update_time` timestamp NULL DEFAULT NULL,
  `create_time` timestamp NULL DEFAULT NULL,
  `version` int NULL DEFAULT 1,
  `del_flag` int NULL DEFAULT 0,
  `create_by` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `update_by` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of orders
-- ----------------------------
INSERT INTO `orders` VALUES (1, 57, '广东', 1, '2022-10-03 12:24:54', '2022-10-03 12:24:54', 1, 0, 'simon', 'linda');
INSERT INTO `orders` VALUES (2, 38, '新疆', 1, '2022-10-03 12:24:54', '2022-10-03 12:24:54', 1, 0, 'linda', 'linda');
INSERT INTO `orders` VALUES (3, 45, '中国', 1, '2022-10-03 12:24:54', '2022-10-03 12:24:54', 1, 0, 'simon', 'linda');
INSERT INTO `orders` VALUES (4, 79, '四川', 1, '2022-10-03 12:24:54', '2022-10-03 12:24:54', 1, 0, 'simon', 'linda');
INSERT INTO `orders` VALUES (5, 198, '山东', 1, '2022-10-03 12:24:54', '2022-10-03 12:24:54', 1, 0, 'simon', 'linda');
INSERT INTO `orders` VALUES (6, 22, '云南', 1, '2022-10-03 12:24:54', '2022-10-03 12:24:54', 1, 0, 'simon', 'linda');

-- ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user`  (
  `id` bigint NOT NULL AUTO_INCREMENT,
  `user_name` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `password` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `name` varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `age` int NULL DEFAULT NULL,
  `address` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 7 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES (1, 'simon', '111111', '张三', 48, '盛大花园38-04-502');
INSERT INTO `user` VALUES (2, 'linda', '111111', '李四', 48, NULL);
INSERT INTO `user` VALUES (3, 'doudou', '111111', '王五', 99, NULL);
INSERT INTO `user` VALUES (6, 'lisi', '111111', NULL, 99, NULL);

SET FOREIGN_KEY_CHECKS = 1;

idea插件

推荐两个插件:

Free MyBatis Tool

该插件可以通过idea中的数据库连接界面中集中生成mapper、entity、xml等。

Mybatis Generator

该插件可以在没有xml的情况下,先编写接口,然后通过接口及方法生成xml文件,并且在xml文件中生成方法片段。

新建springboot工程

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.7.3</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.simon</groupId>
    <artifactId>mybatisplustest</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>mybatisplustest</name>
    <description>mybatisplustest</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </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.2</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.30</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

application.yml

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
    username: root
    password: root
mybatis-plus:
#  global-config:
#    db-config:
#      table-prefix: sys_
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
    map-underscore-to-camel-case: true
  mapper-locations: classpath*:/mapper/**/*.xml

pojo准备

user

@Data
@NoArgsConstructor
@AllArgsConstructor
//@TableName("sys_user")
public class User {
    @TableId(type = IdType.AUTO)
    private Long id;
    private String userName;
    private String password;
    private String name;
    private Integer age;
    @TableField("address")
    private String address;
}

orders

@Data
public class Orders implements Serializable {
    private Long id;
    private Integer price;
    private String remark;
    private Integer userId;
    private Date updateTime;
    private Date createTime;
    private Integer version;
    private Integer delFlag;
    private String createBy;
    private String updateBy;
    private static final long serialVersionUID = 1L;
}

扫描类路径配置

@SpringBootApplication
@MapperScan("com.simon.app.mapper")
public class Test {
    public static void main(String[] args) {
        SpringApplication.run(Test.class,args);
    }
}

在启动类中添加@MapperScan注解,内容为mapper类存放的包名。

基本操作

mapper类

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import com.simon.app.domain.User;
import org.apache.ibatis.annotations.Param;

public interface UserMapper extends BaseMapper<User> {
}

增删改查

@SpringBootTest
class MybatisPlusTests {

    @Autowired
    private UserMapper userMapper;

    @Test
    public void testQueryList(){
        List<User> users = userMapper.selectList(null);
        System.out.println(users);
    }

    /**
     * 自增主键,表要设为自增主键
     * id属性要设置@TableId(type = IdType.AUTO)
     */
    @Test
    public void testIdAutoIncrementInsert(){
        User user=new User();
        user.setUserName("wangwu");
        user.setPassword("111111");
        int insert = userMapper.insert(user);
        System.out.println(insert);
    }

    @Test
    public void testDeleteById(){
        userMapper.deleteById(4);
    }

    @Test
    public void testDeleteByMap(){
        Map map = new HashMap();
        map.put("user_name","wangwu");
        userMapper.deleteByMap(map);
    }

    @Test
    public void testUpdate(){
        User user = new User();
        user.setId(6L);
        user.setUserName("lisi");
        userMapper.updateById(user);
    }

}
  • 当mapper继承自BaseMapper后,就具备了基本的增删改查操作。
  • 要编写junit测试类,该测试类要所在包要和application主启动类在相同包下

Wrapper-条件构造器

AbstractWrapper通用方法

  • eq:等于 = 例: eq("name", "老王")--->name = '老王'
  • ne:不等于<> 例: ne("name", "老王")--->name <> '老王'
  • gt:大于> 例: gt("age", 18)--->age > 18
  • ge:大于等于>= 例: ge("age", 18)--->age >= 18
  • lt:小于< 例:lt("age", 18)--->age < 18
  • le:小于等于<= 例:le("age", 18)--->age <= 18
  • between:BETWEEN 值1 AND 值2 例: between("age", 18, 30)--->age between 18 and 30
  • notBetween:NOT BETWEEN 值1 AND 值2 例: notBetween("age", 18, 30)--->age not between 18 and 30
  • like:LIKE '%值%' 例: like("name", "王")--->name like '%王%'
  • notLike:NOT LIKE '%值%' 例: notLike("name", "王")--->name not like '%王%'
  • likeLeft:LIKE '%值' 例: likeLeft("name", "王")--->name like '%王'
  • likeRight:LIKE '值%' 例: likeRight("name", "王")--->name like '王%'
  • isNull:字段 IS NULL 例: isNull("name")--->name is null
  • isNotNull:字段 IS NOT NULL 例: isNotNull("name")--->name is not null
  • in:字段 IN (value.get(0), value.get(1), ...) 例: in("age",{1,2,3})--->age in (1,2,3)
  • notIn:字段 NOT IN (value.get(0), value.get(1), ...) 例: notIn("age",{1,2,3})--->age not in (1,2,3)
  • inSql:字段 IN ( sql语句 ) 例: inSql("age", "1,2,3,4,5,6")--->age in (1,2,3,4,5,6) 例: inSql("id", "select id from table where id < 3")--->id in (select id from table where id < 3)
  • notSql:字段 NOT IN ( sql语句 ) 例: notInSql("age", "1,2,3,4,5,6")--->age not in (1,2,3,4,5,6) 例: notInSql("id", "select id from table where id < 3")--->id not in (select id from table where id < 3)
  • groupBy:分组:GROUP BY 字段, ... 例: groupBy("id", "name")--->group by id,name
  • orderByAse:排序:ORDER BY 字段, ... ASC 例: orderByAsc("id", "name")--->order by id ASC,name ASC
  • orderByDesc:排序:ORDER BY 字段, ... DESC 例: orderByDesc("id", "name")--->order by id DESC,name DESC
  • orderBy:排序:ORDER BY 字段, ... 例: orderBy(true, true, "id", "name")--->order by id ASC,name ASC
  • having:HAVING ( sql语句 ) 例: having("sum(age) > 10")--->having sum(age) > 10 例: having("sum(age) > {0}", 11)--->having sum(age) > 11

QueryWrapper

常规QueryWrapper

@Test
public void testQueryList(){
    QueryWrapper wrapper = new QueryWrapper();
    wrapper.gt("age",30);
    wrapper.eq("user_name","simon");

    List<User> users = userMapper.selectList(wrapper);
    System.out.println(users);
}

@Test
public void testIn(){
    QueryWrapper wrapper = new QueryWrapper();
    wrapper.in("id",1,2,3);

    List<User> users = userMapper.selectList(wrapper);
    System.out.println(users);
}

字段过滤

@Test
public void test1(){
    QueryWrapper wrapper = new QueryWrapper();
    wrapper.select(User.class, new Predicate<TableFieldInfo>() {
        @Override
        public boolean test(TableFieldInfo tableFieldInfo) {
            return "user_name".equals(tableFieldInfo.getColumn());

        }
    });

    List<User> users = userMapper.selectList(wrapper);
    System.out.println(users);
}

@Test
public void test2(){
    QueryWrapper<User> wrapper = new QueryWrapper<>(new User());
    wrapper.select(tableFieldInfo -> !"address".equals(tableFieldInfo.getColumn()));

    List<User> users = userMapper.selectList(wrapper);
    System.out.println(users);
}

Predicate的test会循环遍历所有字段名称,并返回boolean,如果为true,则相应的字段就会追加到select列表中。

Lambda表达式

@Test
public void testLambda2(){
    LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>(new User());
    wrapper.eq(User::getName,"simon");
    List<User> users = userMapper.selectList(wrapper);
    System.out.println(users);
}

User::getName的用法是不需要直接指定物理字段名称,用属性名代替。

UpdateWrapper

直接使用wrapper通过set设定某个字段的值来更新

@Test
public void testUpdateWrapper(){
    UpdateWrapper<User> wrapper = new UpdateWrapper<>();
    wrapper.eq("id",2);
    wrapper.set("age",99);
    userMapper.update(null,wrapper);
}

通过pojo赋值进行更新

@Test
public void testUpdateWrapper1(){
    UpdateWrapper<User> wrapper = new UpdateWrapper<>();
    wrapper.eq("id",2);
    User user=new User();
    user.setAge(1000);

    userMapper.update(user,wrapper);
}

Lambda表达式

@Test
public void testUpdateLambda(){
    LambdaUpdateWrapper<User> wrapper = new LambdaUpdateWrapper<>();
    wrapper.eq(User::getId,3);

    User user=new User();
    user.setAge(48);

    userMapper.update(user,wrapper);
}

UpdateWrapper的作用是拼接where条件语句

另一种方法

LambdaUpdateWrapper<Orders> wrapper=new LambdaUpdateWrapper<Orders>();
wrapper.set(Orders::getRemark,"贵州");
wrapper.eq(Orders::getId,7L);
ordersMapper.update(null,wrapper);

链式表达

LambdaUpdateWrapper<Orders> wrapper = new LambdaUpdateWrapper<Orders>()
        .set(Orders::getRemark,"贵州")
        .eq(Orders::getId , 7L);
ordersMapper.update(null,wrapper);

自定义方法

如果我们想在自定义方法中使用条件构造器,可按照如下顺序操作

定义mapper方法

public interface UserMapper extends BaseMapper<User> {
  public User findByWrapper(@Param(Constants.WRAPPER) Wrapper<User> wrapper);
}

此处Constants.WRAPPER代表传入xml方法的参数名前缀,该值为:String WRAPPER = "ew";也可以自定义。

自定义sql

<select id="findByWrapper" resultType="com.simon.app.domain.User">
select * from user ${ew.customSqlSegment}
</select>

使用

@Test
public void testWrapper(){
    LambdaQueryWrapper<User> wr = new LambdaQueryWrapper<>();
    wr.eq(User::getId,1L);
    User user = userMapper.findByWrapper(wr);
    System.out.println(user);
}

使用@select注解

也可以不在xml中定义sql,而直接使用@select注解

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

public interface UserMapper extends BaseMapper<User> {
  @Select("SELECT * FROM user ${ew.customSqlSegment}")
  public User findUserByAnnotation(@Param(Constants.WRAPPER) Wrapper wrapper);
}

测试

@Test
public void testSelectAnnotation(){
    LambdaQueryWrapper<User> wr = new LambdaQueryWrapper<>();
    wr.eq(User::getId,1L);
    User user = userMapper.findUserByAnnotation(wr);
    System.out.println(user);
}

分页

准备

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;

@Configuration
public class MyBatisPlusConfig {

    /**
     * 分页插件
     */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }
}

此处PaginationInnerInterceptor的参数指定数据库类型。

使用

使用内置方法分页

@Test
public void getPage(){
    IPage<User> page=new Page<User>();
    page.setSize(10);
    page.setCurrent(1);
    userMapper.selectPage(page, null);
    System.out.println(page.getRecords());
    System.out.println(page.getTotal());
}

通过内置拦截器分页

加入我们要查询orders表,并且要知道每个order对应人的真实姓名,按以下步骤操作

扩展pojo

在原有Orders类上增加一个userName属性,也可新建一个OrderVo类添加该属性。

@Data
public class OrdersVo implements Serializable {
    private Long id;
    private Integer price;
    private String remark;
    private Integer userId;
    private Date updateTime;
    private Date createTime;
    private Integer version;
    private Integer delFlag;
    private String createBy;
    private String updateBy;
    private String userName;
    private static final long serialVersionUID = 1L;
}
mapper接口定义
public interface OrdersMapper extends BaseMapper<Orders> {
    public IPage<OrdersVo> findAllOrdersByPage(Page<OrdersVo> page);
}

此处必须要传入Page参数,用于保存每一页记录数及页码,返回类型为IPage。

定义接口方法
<select id="findAllOrdersByPage" resultType="com.simon.app.domain.OrdersVo">
    select o.*,u.user_name from orders o join user as u on o.user_id=u.id
</select>
测试
@Test
public void getOrdersByPage(){
    Page<OrdersVo> page = new Page<>();
    page.setSize(2);
    page.setCurrent(2);
    IPage<OrdersVo> pages = ordersMapper.findAllOrdersByPage(page);
    System.out.println(pages.getRecords());
    System.out.println(pages.getTotal());
}

service接口

基本使用

service接口定义

import com.baomidou.mybatisplus.extension.service.IService;
import com.simon.app.domain.User;

public interface UserService extends IService<User> {
}

service接口实现定义

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.simon.app.domain.User;
import com.simon.app.mapper.UserMapper;
import com.simon.app.service.UserService;
import org.springframework.stereotype.Service;

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

}

测试

@Test
public void testList(){
    List<User> list = userService.list();
    System.out.println(list);
}

lambda表达式

这个是方法返回结果不止一条则会抛出异常。

@Test
public void getOne() {
    User one = userService.getOne(Wrappers.<User>lambdaQuery().eq(User::getAge, 48),false);
    System.out.println(one);
}
/**
 * lombda查询
 */
@Test
public void lambdaQuery(){
    List<User> list = userService.lambdaQuery().eq(User::getAge, 18).list();
    list.forEach(System.out::println);
}

/**
 * lombda修改
 */
@Test
public void lambdaUpdate(){
    boolean update = userService.lambdaUpdate().eq(User::getAge, 18).set(User::getAge, 31).update();
    System.out.println(update);
}

/**
 * lombda删除
 */
@Test
public void lambdaRemove(){
    boolean remove = userService.lambdaUpdate().eq(User::getAge, 18).remove();
    System.out.println(remove);
}

自定义方法

如果IService中通用的方法无法满足要求,就需要在service中定义方法,并在serviceimpl实现。

service中自定义方法

public interface UserService extends IService<User> {
    public User userCheck();
}

service接口实现

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.simon.app.domain.OrdersVo;
import com.simon.app.domain.User;
import com.simon.app.mapper.OrdersMapper;
import com.simon.app.mapper.UserMapper;
import com.simon.app.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

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

    @Autowired
    private OrdersMapper ordersMapper;

    @Override
    public User userCheck() {

        UserMapper userMapper = getBaseMapper();
        List<User> users = userMapper.selectList(null);

        List<OrdersVo> allOrders = ordersMapper.findAllOrders();
        return users.get(0);
    }
}

有两点需要注意:

  1. 调用userMapper不需要通过@Autowired来声明userMapper,只需要通过getBaseMapper()方法即可得到userMapper
  2. 要使用其他mapper需要通过@Autowired来绑定。

代码生成器

引入包

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-generator</artifactId>
    <version>3.5.3</version>
</dependency>
<dependency>
    <groupId>org.freemarker</groupId>
    <artifactId>freemarker</artifactId>
    <version>2.3.31</version>
    <scope>compile</scope>
</dependency>

生成器类

package com.simon.app.generator;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.converts.MySqlTypeConvert;
import com.baomidou.mybatisplus.generator.config.querys.MySqlQuery;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import com.baomidou.mybatisplus.generator.keywords.MySqlKeyWordsHandler;
import lombok.Data;

import java.util.Collections;

/**
 * 3.5.x 新版生成器 可连远程数据库 ,旧版远程报错
 * new MyBatisGenerate.Builder()
 * .setDbName("universal_portal")
 * .setModule("")
 * .setPrefix(new String[]{""})
 * .setParentPackage("generate")
 * .setDbHostAndPort("localhost:3306")
 * .setDbUserName("root")
 * .setDbPsw("123456")
 * .setTables(new String[]{"user"})
 * .build()
 * .generate();
 *
 * @author bufei
 * @email 。。。
 * @date 2022/3/22 15:22
 */
@Data
public class MyBatisGenerate {

    /**
     * 数据库名称
     */
    private String dbName;
    /**
     * 模块名称
     */
    private String module;
    /**
     * 去除表前缀如t_ tb_
     */
    private String[] prefix;
    /**
     * 父级包名称如appenv
     */
    private String parentPackage;
    /**
     * 数据库host和端口
     */
    private String dbHostAndPort;
    /**
     * 数据库用户名
     */
    private String dbUserName;
    /**
     * 数据库密码
     */
    private String dbPsw;
    /**
     * 表名称 ,string数组
     */
    private String[] tables;

    private MyBatisGenerate(String dbName, String module, String[] prefix, String parentPackage, String dbHostAndPort, String dbUserName, String dbPsw, String[] tables) {
        this.dbName = dbName;
        this.module = module;
        this.prefix = prefix;
        this.parentPackage = parentPackage;
        this.dbHostAndPort = dbHostAndPort;
        this.dbUserName = dbUserName;
        this.dbPsw = dbPsw;
        this.tables = tables;
    }

    /**
     * 代码生成
     */
    public void generate() {
        // 数据源配置
        String url = "jdbc:mysql://" + dbHostAndPort + "/" + dbName + "?characterEncoding=utf8&useSSL=true&serverTimezone=Hongkong&strictUpdates=false&autoReconnect=true";
        DataSourceConfig dsb = new DataSourceConfig.Builder(url, dbUserName, dbPsw)
                .dbQuery(new MySqlQuery())
                // 库名
                .schema(dbName)
                .typeConvert(new MySqlTypeConvert())
                .keyWordsHandler(new MySqlKeyWordsHandler()).build();
        // 获取当前项目路径
        String projectPath = System.getProperty("user.dir");
        // 全局配置
        GlobalConfig gc = new GlobalConfig.Builder()
                // 输出目录
                .outputDir(projectPath + "/src/main/java")
                // 覆盖已生成文件
                .fileOverride()
                // 作者
                .author("bufei")
                // 启用swagger
                .enableSwagger()
                .dateType(DateType.TIME_PACK)
                .commentDate("yyyy-MM-dd HH:mm:ss")
                .build();
        // 包配置
        PackageConfig pc = new PackageConfig.Builder()
                .parent(parentPackage)
                // 设置父包模块名
                .moduleName(module)
                // 设置实体包
                .entity("com.simon.app.model")
                // 服务类
                .service("com.simon.app.service")
                // 服务类实现
                .serviceImpl("com.simon.app.service.impl")
                .mapper("com.simon.app.mapper")
                .xml("mapper.xml")
                .controller("com.simon.app.controller")
                // 路径信息
                .pathInfo(Collections.singletonMap(OutputFile.xml, projectPath + "/src/main/resources/mybatis/mapper/"))
                .build();
        // 模板配置 不配无法生成
        TemplateConfig tc = new TemplateConfig.Builder()
                .disable(TemplateType.ENTITY)
                .entity("/templates/entity.java")
                .service("/templates/service.java")
                .serviceImpl("/templates/serviceImpl.java")
                .mapper("/templates/mapper.java")
                .xml("/templates/mapper.xml")
                .controller("/templates/controller.java")
                .build();
        // 注入配置
        InjectionConfig ic = new InjectionConfig.Builder()
                .beforeOutputFile((tableInfo, objectMap) -> {
                    System.out.println("tableInfo: " + tableInfo.getEntityName() + " objectMap: " + objectMap.size());
                })
                // 没有自定义配置map对象
                // 没有模板文件
                .build();
        // 策略配置
        StrategyConfig sc = new StrategyConfig.Builder()
                // 策略 开启大写命名
                .enableCapitalMode()
                .enableSkipView()
                // 禁用SQL过滤
                .disableSqlFilter()
                // 表名
                .addInclude(tables)
                // 要移除的表前缀
                .addTablePrefix(prefix)
                // 配置实体策略
                .entityBuilder()
                // 父类
                .superClass(Model.class)
                // 禁用序列化
                .disableSerialVersionUID()
                // 启用链式编程
                .enableChainModel()
                //启用Lombok
                .enableLombok()
                // 启用表字段注解
                .enableTableFieldAnnotation()
                // 乐观锁
                .versionColumnName("version")
                .versionPropertyName("version")
                // 逻辑删除
                .logicDeleteColumnName("del_flag")
                .logicDeletePropertyName("delFlag")
                // 表名驼峰
                .naming(NamingStrategy.underline_to_camel)
                // 列名驼峰命名
                .columnNaming(NamingStrategy.underline_to_camel)
                .idType(IdType.AUTO)
                // 格式化文件名称
                .formatFileName("%sModel")
                // 配置controller 策略
                .controllerBuilder()
                // 设置父类,没有,不配
                // .superClass(BaseController.class)
                // RestController
                .enableRestStyle()
                .formatFileName("%sController")
                // 配置serveice 策略
                .serviceBuilder()
                // BaseRepository impl
//                .superServiceClass(BaseRepository.class)
//                .superServiceImplClass(BaseRepositoryImpl.class)
                .formatServiceFileName("%sService")
                .formatServiceImplFileName("%sServiceImpl")
                // 配置mapper策略
                .mapperBuilder()
//                // 父类
//                .superClass(SuperMapper.class)
                // 启用mapper注解
                .enableMapperAnnotation()
                // 启用 BaseResultMap
                .enableBaseResultMap()
                .enableBaseColumnList()
                .formatMapperFileName("%sMapper")
                .formatXmlFileName("%sMapper")
                .build();
        // 执行生成
        new AutoGenerator(dsb)
                // 全局配置
                .global(gc)
                .packageInfo(pc)
                .injection(ic)
                .strategy(sc)
                .template(tc)
                // 默认VelocityTemplateEngine引擎,改为freemark引擎
                .execute(new FreemarkerTemplateEngine());

    }

    public static class Builder {
        public Builder() {
        }

        private String dbName;
        private String module;
        private String[] prefix;
        private String parentPackage;
        private String dbHostAndPort;
        private String dbUserName;
        private String dbPsw;
        private String[] tables;

        /**
         * 设置数据库名称
         *
         * @param dbName 数据库名称
         * @return
         */
        public Builder setDbName(String dbName) {
            this.dbName = dbName;
            return this;
        }

        /**
         * 设置模块名称
         *
         * @param module 模块名称如 app-env
         * @return
         */
        public Builder setModule(String module) {
            this.module = module;
            return this;
        }

        /**
         * 设置要去除的表前缀
         *
         * @param prefix 要去除的表前缀 如t_;tbl_
         * @return
         */
        public Builder setPrefix(String[] prefix) {
            this.prefix = prefix;
            return this;
        }

        /**
         * 设置父级包名称
         *
         * @param parentPackage 父级包名称 如 appenv
         * @return
         */
        public Builder setParentPackage(String parentPackage) {
            this.parentPackage = parentPackage;
            return this;
        }

        /**
         * 设置数据库host:port
         *
         * @param dbHostAndPort 数据库host:port
         * @return
         */
        public Builder setDbHostAndPort(String dbHostAndPort) {
            this.dbHostAndPort = dbHostAndPort;
            return this;
        }

        /**
         * 设置数据库用户名
         *
         * @param dbUserName 数据库用户名
         * @return
         */
        public Builder setDbUserName(String dbUserName) {
            this.dbUserName = dbUserName;
            return this;
        }

        /**
         * 设置数据库密码
         *
         * @param dbPsw 数据库密码
         * @return
         */
        public Builder setDbPsw(String dbPsw) {
            this.dbPsw = dbPsw;
            return this;
        }

        /**
         * 设置表名称
         *
         * @param tables 数据库表名称数组
         * @return
         */
        public Builder setTables(String[] tables) {
            this.tables = tables;
            return this;
        }

        public MyBatisGenerate build() {
            return new MyBatisGenerate(dbName, module, prefix, parentPackage, dbHostAndPort, dbUserName, dbPsw, tables);
        }
    }

}

执行生成器类


public class Test {
    public static void main(String[] args) {
        new MyBatisGenerate.Builder()
                .setDbName("mybatis")
                .setModule("")//没有分模块
                .setPrefix(new String[]{""})//没有需要移除的前缀
                .setParentPackage("generate")//当前项目的包名
                .setDbHostAndPort("localhost:3306")
                .setDbUserName("root")
                .setDbPsw("root")
                .setTables(new String[]{"orders","user"})
                .build()
                .generate();
    }
}

自动填充

为pojo添加注解 @TableField

@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updateTime;

@TableField(fill = FieldFill.INSERT)
private Date createTime;

实现接口 MetaObjectHandler


import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.Date;

@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
    private static final Logger LOGGER = LoggerFactory.getLogger(MyMetaObjectHandler.class);

    //MP添加时执行
    @Override
    public void insertFill(MetaObject metaObject) {
        LOGGER.info("start insert fill ....");
        //根据名称设置属性值
        this.setFieldValByName("createTime",new Date(),metaObject);
        this.setFieldValByName("updateTime",new Date(),metaObject);
    }
    //MP修改时执行
    @Override
    public void updateFill(MetaObject metaObject) {
        LOGGER.info("start update fill ....");
        this.setFieldValByName("updateTime",new Date(),metaObject);
    }
}

测试

新增

@Test
public void testInsertByHandler(){
    Orders order=new Orders();
    order.setId(7L);
    order.setPrice(188);
    order.setRemark("新疆");
    order.setUserId(1);
    ordersMapper.insert(order);
}

修改

    @Test
    public void testUpdateByHandler(){
        LambdaUpdateWrapper<Orders> wrapper=new LambdaUpdateWrapper<Orders>();
        wrapper.set(Orders::getRemark,"贵州");
        wrapper.eq(Orders::getId,7L);
        ordersMapper.update(new Orders(),wrapper);

    }
  • update(T t,Wrapper updateWrapper)时t不能为空,否则自动填充失效

逻辑删除

什么是逻辑删除

逻辑删除是名义上的删除,就是对要删除的数据打上一个删除标记,在逻辑上数据是被删除的,但数据本身依然存在,可通过修改删除标记来恢复数据。

特别说明

只对自动注入的 sql 起效,自己在mapper.xml中写的sql不生效:
插入: 不作限制
查找: 追加 where 条件过滤掉已删除数据
更新: 追加 where 条件防止更新到已删除数据
删除: 转变为更新

yml配置

mybatis-plus:
  global-config:
    db-config:
      logic-delete-field: delFlag # 全局逻辑删除的实体字段名,在mybatisplus3.3.0之前还必须在实体类字段上加上@TableLogic注解
      logic-delete-value: 1 # 逻辑已删除值
      logic-not-delete-value: 0 # 逻辑未删除值

测试

@Test
public void testDelflag(){
    LambdaQueryWrapper<Orders> wrapper = new LambdaQueryWrapper<>();
    wrapper.eq(Orders::getId,7L);
    ordersMapper.delete(wrapper);
    //ordersMapper.deleteById(7L);

}

事务

https://www.cnblogs.com/konglxblog/p/16456782.html

  1. springboot中使用事务就很简单了,首先引入依赖spring-tx,但是mybatis-plus的依赖中已经引入,因此又少了一步

  2. 开启事务,在Springboot的启动类,或者某个@Configuration的类上加上@EnableTransactionManagement开启事务。因为这是数据库相关,所以我加在了mybatis-plus的配置类上

    @Configuration
    @EnableTransactionManagement
    @MapperScan("com.simon.app.mapper")
    public class MyBatisPlusConfig {
    
    }
    
  3. 只要在需要使用事务的方法上加上@Transactional就可以开启事务了,当然也可以加到service类上。

注意点:

  1. @Transactional默认回滚的是RuntimeException也就是说如果抛出的不是RuntimeException的异常,数据库是不会回滚的。但是所幸的是,在spring框架下,所有的异常都被org.springframework重写为RuntimeException,因此不需要太担心

    @Transactional
    public void buy() throws Exception {
        1. 扣钱
        throw new 非RuntimeException异常("发生异常");
        2. 扣库存
    }
    
    // 有一种处理方法是指定回滚的异常
    @Transactional(rollbackFor = Exception.class)
        public void buy() throws Exception {
        1. 扣钱
        throw new 非RuntimeException异常("发生异常");
        2. 扣库存
    }
    
  2. 如果在异常发生时,程序员自己手动捕获处理了,异常也不会回滚

    @Transactional
    public void buy() throws Exception {
        try{
        1. 扣钱
        } catch (Exception e) {
            catch了自己处理,也就是异常被自己吞了,外层并不知道,此时也不会回滚
        }
        3. 扣库存
    }
    

其他

假如在查询的时候不想查询该字段,可以在字段上加上 @TableField(select = false)注解

posted @ 2022-10-03 22:01  疯狗强尼  阅读(230)  评论(0编辑  收藏  举报