【JavaEE进阶】MyBatis(5)-MyBatis-plus

欢迎关注个人主页:逸狼


创造不易,可以点点赞吗

如有错误,欢迎指出~


MyBatisGenerator

MyBatisGenerator是⼀个为MyBatis框架设计的代码⽣成⼯具,它可以根据数据库表结构⾃动⽣成相应 的JavaModel,Mapper接⼝以及SQL映射⽂件,简化数据访问层的编码⼯作,使得开发者可以更专注于 业务逻辑的实现. 接下来我们看下,如何使⽤MyBatisGenerator来⽣成代码.

generatorConfig.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
        PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<!-- 配置生成器 -->
<generatorConfiguration>

    <!-- 一个数据库一个context -->
    <context id="MysqlTables" targetRuntime="MyBatis3" defaultModelType="flat">
        <!--去除注释-->
        <commentGenerator>
            <property name="suppressDate" value="true"/>
            <property name="suppressAllComments" value="true" />
        </commentGenerator>

        <!--数据库链接信息-->
        <jdbcConnection driverClass="com.mysql.jdbc.Driver"
                        connectionURL="jdbc:mysql://127.0.0.1:3306/java_blog_spring?serverTimezone=Asia/Shanghai&amp;nullCatalogMeansCurrent=true"
                        userId="root"
                        password="111111">
        </jdbcConnection>

        <!-- 生成实体类 -->
        <javaModelGenerator targetPackage="com.example.demo.model" targetProject="src/main/java" >
            <property name="enableSubPackages" value="false"/>
            <property name="trimStrings" value="true"/>
        </javaModelGenerator>
        <!-- 生成mapxml文件 -->
        <sqlMapGenerator targetPackage="mapper" targetProject="src/main/resources" >
            <property name="enableSubPackages" value="false" />
        </sqlMapGenerator>
        <!-- 生成mapxml对应client,也就是接口dao -->
        <javaClientGenerator targetPackage="com.example.demo.mapper" targetProject="src/main/java" type="XMLMAPPER" >
            <property name="enableSubPackages" value="false" />
        </javaClientGenerator>
        <!-- table可以有多个,每个数据库中的表都可以写一个table,tableName表示要匹配的数据库表,也可以在tableName属性中通过使用%通配符来匹配所有数据库表,只有匹配的表才会自动生成文件 -->
        <table tableName="user_info">
            <property name="useActualColumnNames" value="false" />
            <!-- 数据库表主键 -->
            <generatedKey column="id" sqlStatement="Mysql" identity="true" />
        </table>
    </context>
</generatorConfiguration>

在pom文件添加插件

<plugin>
				<groupId>org.mybatis.generator</groupId>
				<artifactId>mybatis-generator-maven-plugin</artifactId>
				<version>1.3.6</version>
				<executions>
					<execution>
						<id>Generate MyBatis Artifacts</id>
						<phase>deploy</phase>
						<goals>
							<goal>generate</goal>
						</goals>
					</execution>
				</executions>
				<configuration>
					<!--generator配置文件所在位置-->
					<configurationFile>src/main/resources/generator/generatorConfig.xml</configurationFile>
					<!-- 允许覆盖生成的文件, mapxml不会覆盖, 采用追加的方式-->
					<overwrite>true</overwrite>
					<verbose>true</verbose>
					<!--将当前pom的依赖项添加到生成器的类路径中-->
					<includeCompileDependencies>true</includeCompileDependencies>
				</configuration>
				<dependencies>
					<dependency>
						<groupId>com.mysql</groupId>
						<artifactId>mysql-connector-j</artifactId>
						<version>8.0.33</version>
					</dependency>
				</dependencies>
			</plugin>

mybatis-plus

MyBatis-Plus(简称MP)是⼀个MyBatis的增强⼯具,在MyBatis的基础上只做增强不做改变,为简化开 发.提⾼效率⽽⽣

特性:

  • 润物⽆声:只做增强不做改变,引⼊它不会对现有⼯程产⽣影响,如丝般顺滑.
  • 效率⾄上:只需简单配置,即可快速进⾏单表CRUD操作,从⽽节省⼤量时间.
  • 丰富功能:代码⽣成、⾃动分⻚、逻辑删除、⾃动填充、拦截器等功能⼀应俱全.
  • ⼴泛认可:连续5年获得开源中国年度最佳开源项⽬殊荣,Github累计16KStar.

⽀持数据库:

PostgreSQL,MySQL,MariaDB,Oracle,SQLServer,OceanBase,H2,DB2... (任何能使⽤MyBatis进⾏增删改查,并且⽀持标准SQL的数据库应该都在MyBatis-Plus的⽀持范围 内)

准备工作

配置yml

# 数据库连接配置
spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/mybatis_test?characterEncoding=utf8&useSSL=false
    username: root
    password: 111111
    driver-class-name: com.mysql.cj.jdbc.Driver

添加依赖,对于springboot3添加下面依赖

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-spring-boot3-starter</artifactId>
    <version>3.5.10.1</version>
</dependency>

数据准备

-- 创建数据库 
DROP DATABASE IF EXISTS mybatis_test;
CREATE DATABASE mybatis_test DEFAULT CHARACTER SET utf8mb4;
-- 使⽤数据数据 
USE mybatis_test;
-- 创建表[⽤⼾表] 
DROP TABLE IF EXISTS user_info;

10CREATE TABLE `user_info` (
 `id` INT ( 11 ) NOT NULL AUTO_INCREMENT,
 `username` VARCHAR ( 127 ) NOT NULL,
 `password` VARCHAR ( 127 ) NOT NULL,
 `age` TINYINT ( 4 ) NOT NULL,
 `gender` TINYINT ( 4 ) DEFAULT '0' COMMENT '1-男 2-⼥ 0-默认',
 `phone` VARCHAR ( 15 ) DEFAULT NULL,
 `delete_flag` TINYINT ( 4 ) DEFAULT 0 COMMENT '0-正常, 1-删除',
 `create_time` DATETIME DEFAULT now(),
 `update_time` DATETIME DEFAULT now(),
 PRIMARY KEY ( `id` ) 
) ENGINE = INNODB DEFAULT CHARSET = utf8mb4; 
-- 添加⽤⼾信息 
INSERT INTO mybatis_test.user_info( username, `password`, age, gender, phone )
VALUES ( 'admin', 'admin', 18, 1, '18612340001' );
INSERT INTO mybatis_test.user_info( username, `password`, age, gender, phone )
VALUES ( 'zhangsan', 'zhangsan', 18, 1, '18612340002' );
INSERT INTO mybatis_test.user_info( username, `password`, age, gender, phone )
VALUES ( 'lisi', 'lisi', 18, 1, '18612340003' );
INSERT INTO mybatis_test.user_info( username, `password`, age, gender, phone )
VALUES ( 'wangwu', 'wangwu', 18, 1, '18612340004' );

 后端代码

UserInfo

package com.example.demo.model;
import lombok.Data;
import java.util.Date;

@Data
public class UserInfo {
    private Integer id;
    private String username;
    private String password;
    private Integer age;
    private Integer gender;
    private String phone;
    private Integer deleteFlag;
    private Date createTime;
    private Date updateTime;
}

UserInfoMapper

package com.example.demo.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.demo.model.UserInfo;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface UserInfoMapper extends BaseMapper<UserInfo> {

}

 BaseMapper提供了众多crud的方法

MyBatis-Plus复杂操作

3.1 常⻅注解

在上⾯的程序中,MyBatis是如何知道,我们要操作的是哪张表,表⾥有哪些字段呢? 我们来看下咱们Mapper的代码 

@Mapper
public interface UserInfoMapper extends BaseMapper<UserInfo> {
}

UserInfoMapper在继承 BaseMapper 时,指定了⼀个泛型,这个UserInfo就是与数据库表相对应的实 体类. MyBatis-Plus会根据这个实体类来推断表的信息.

默认情况下:

  • 1. 表名:实体类的驼峰表⽰法转换成蛇形表⽰法(下划线分割),作为表名.⽐如UserInfo->user_info
  • 2. 字段:根据实体类的属性名转换为蛇形表⽰法作为字段名.⽐如deleteFlag->delete_flag3. 主键:默认为id
  • 3.主键:默认为id

如果实体类和数据库不是按照上述规则定义

MyBatis-Plus也给我们提供了⼀下注解,让我们标 识表的信息.  

@TableName

修改实体类名UserInfo为Userinfo

从⽇志可以看到,默认查找的表名为userinfo. 我们可以通过 @TableName 来标识实体类对应的表

@Data
@TableName("user_info")//绑定表名
public class UserInfo {
    private Integer id;
....}

@TableField

修改属性名deleteFlag为deleteflag,重新执⾏测试⽅法testSelectById

从⽇志可以看到,根据属性名转换后的字段名为:deleteflag. 我们可以通过 @TableField 来标识对应的字段名

@Data
@TableName("user_info")//绑定表名
public class UserInfo {
...
    private String phone;
    @TableField("delete_flag")//标识表名
    private Integer deleteflag;
    private Date createTime;
    private Date updateTime;
}

@TableId

 修改属性名id为userId,重新执⾏测试⽅法testSelectById 运⾏结果报错,程序默认主键为id,这个时候需要可以使用@TableId指定主键

@Data

@TableName("user_info")//绑定表名
public class UserInfo {
    @TableId(value = "id" )
    private Integer userId;
    private String username;

如果属性名和字段名不⼀致,需要在 @TableId 指明对应的字段名

属性名和字段⼀致的情况下,直接加 @TableId 注解就可以. 

    @Test
    void testInsert(){
        UserInfo userInfo = new UserInfo();
        userInfo.setUsername("111");
        userInfoMapper.insert(userInfo);
    }

执⾏测试⽅法testInsert 运⾏结果:

要通过@TableId指定id自增方式

@Data

@TableName("user_info")//绑定表名
public class UserInfo {
    @TableId(type = IdType.AUTO)
    private Integer id;
...}

重新执行结果正常  

打印⽇志

为了⽅便学习,我们可以借助⽇志,查看Mybatis-Plus执⾏的SQL语句,参数和执⾏结果 Mybatis-Plus配置⽇志如下:

mybatis-plus:
 configuration: # 配置打印 MyBatis⽇志 
     log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

条件构造器

⼊⻔程序⾥的使⽤,都是简单的CRUD,在实际的应⽤场景中,我们还需要使⽤更复杂的操作,MyBatisPlus 也给我们提供了相应的⽀持. MyBatis-Plus提供了⼀套强⼤的条件构造器(Wrapper),⽤于构建复杂的数据库查询条件.

Wrapper类 允许开发者以链式调⽤的⽅式构造查询条件,⽆需编写繁琐的SQL语句,从⽽提⾼开发效率并减少SQL 注⼊的⻛险.

以下是主要的Wrapper类及其功能:

  • AbstractWrapper:这是⼀个抽象基类,提供了所有Wrapper类共有的⽅法和属性.详细参考官⽹ 介绍:条件构造器
  • QueryWrapper:⽤于构造查询条件,在AbstractWrapper的基础上拓展了⼀个select⽅法,允许指 定查询字段.
  • UpdateWrapper:⽤于构造更新条件,可以在更新数据时指定条件.
  • LambdaQueryWrapper:基于Lambda表达式的查询条件构造器,它通过Lambda表达式来引⽤ 实体类的属性,从⽽避免了硬编码字段名.
  • LambdaUpdateWrapper:基于Lambda表达式的更新条件构造器,它允许你使⽤Lambda表达 式来指定更新字段和条件,同样避免了硬编码字段名的问题. 接下来通过代码来看下如何使⽤.

查询

QueryWrapper

实现下面sql查询

SELECT id,username,password,age FROM user_info WHERE age = 18 AND username LIKE "%min%"

测试

    @Test
    void testQueryWrapper(){
        //SELECT id,username,password,age FROM user_info WHERE age = 18 AND username LIKE "%min%"
        QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("id", "username", "password", "age")
                .eq("age", 18)
                .like("username", "min");
        userInfoMapper.selectList(queryWrapper).forEach(System.out::println);
    }
  • lt :"lessthan"的缩写,表⽰⼩于.
  • le :"lessthanorequalto"的缩写,表⽰⼩于等于
  • ge :"greaterthanorequalto"的缩写,表⽰⼤于等于.
  • gt :"greaterthan"的缩写,表⽰⼤于.
  • eq :"equals"的缩写,表⽰等于.
  • ne :"notequals"的缩写,表⽰不等于. 

更新

执行下面sql

UPDATE user_info SET delete_flag=? WHERE age < 20

测试

    @Test
    //UPDATE user_info SET delete_flag=? WHERE age < 20
    void testUpdateWrapper(){
        UpdateWrapper<UserInfo> updateWrapper = new UpdateWrapper<>();
        updateWrapper.set("delete_flag", 2)
                .lt("age", 20);
        userInfoMapper.update(updateWrapper);
    }

UpdateWrapper

UPDATE user_info SET delete_flag=0, age=5 WHERE id IN (1,2,3)

测试

    @Test
        //UPDATE user_info SET delete_flag=0, age=5 WHERE id IN (1,2,3)
    void testUpdateWrapper2(){
        UpdateWrapper<UserInfo> updateWrapper = new UpdateWrapper<>();
        updateWrapper.set("delete_flag", 0).set("age",20)
                .in("id", List.of(1,2,3));
        userInfoMapper.update(updateWrapper);
    }

基于SQL更新

UPDATE user_info SET age = age+10 WHERE id IN (1,2,3)

测试

    @Test
        //UPDATE user_info SET age = age+10 WHERE id IN (1,2,3)
    void testUpdateWrapper3(){
        UpdateWrapper<UserInfo> updateWrapper = new UpdateWrapper<>();
        updateWrapper.setSql("age = age + 10")
                .in("id", List.of(1,2,3));
        userInfoMapper.update(updateWrapper);
    }

LambdaQueryWrapper

QueryWrapper和UpdateWrapper存在⼀个问题,就是需要写死字段名,如果字段名发⽣变更,可能会 因为测试不到位酿成事故.MyBatis-Plus给我们提供了⼀种基于Lambda表达式的条件构造器,它通过Lambda表达式来引⽤实体 类的属性,从⽽避免了硬编码字段名,也提⾼了代码的可读性和可维护性.

LambdaQueryWrapper和 LambdaUpdateWrapper 分别对应上述的QueryWrapper和UpdateWrapper 接下来我们看下具体使⽤.

    @Test
//SELECT id,username,password,age FROM user_info WHERE age = 18 AND username LIKE "%min%"
    void testLambdaQueryWrapper(){
        QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda()
                .select(UserInfo::getId, UserInfo::getUsername, UserInfo::getPassword)
                .eq(UserInfo::getAge, 18)
                .like(UserInfo::getUsername, "min");
        userInfoMapper.selectList(queryWrapper).forEach(System.out::println);
    }

    @Test
    void testLambdaUpdateWrapper() {
        //UPDATE user_info SET delete_flag=0, age=5 WHERE id IN (1,2,3)
        UpdateWrapper<UserInfo> updateWrapper = new UpdateWrapper<>();
//            updateWrapper.set("delete_flag", 2).set("age",20)
//                    .in("id", List.of(1,2,3));
        updateWrapper.lambda()
                .set(UserInfo::getDeleteFlag, 2)
                .set(UserInfo::getAge, 20)
                .in(UserInfo::getId, List.of(1, 2, 3));
        userInfoMapper.update(updateWrapper);
    }

⾃定义SQL

在实际的开发中,MyBatis-Plus提供的操作不能满⾜我们的实际需求,MyBatis-Plus也提供了⾃定义 SQL的功能,我们可以利⽤Wrapper构造查询条件,再结合Mapper编写SQL

为了使⽤这⼀功能,mybatis-plus 版本不低于3.0.7

select id,username,password,age FROM user_info WHERE username = "admin"

    //select id,username,password,age FROM user_info WHERE username = "admin"
    @Select("select id,username,password,age FROM user_info ${ew.customSqlSegment}")
    List<UserInfo> selectCustom(@Param(Constants.WRAPPER) Wrapper wrapper);

注意事项:

  1. 参数命名:在⾃定义SQL时,传递Wrapper对象作为参数时,参数名必须为ew ,或者使⽤注解 @Param(Constants.WRAPPER) 明确指定参数为Wrapper对象
  2. 使⽤${ew.customSqlSegment} :在SQL语句中,使⽤${ew.customSqlSegment} 来 引⽤Wrapper对象⽣成的SQL⽚段
  3. 不⽀持基于entity的where语句:⾃定义SQL时,Wrapper对象不会基于实体类⾃动⽣成 where⼦句,你需要⼿动编写完整的SQL语句.

测试

    @Test
    void selectCustom() {
        QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("username", "admin");
        userInfoMapper.selectCustom(queryWrapper).forEach(System.out::println);
    }

使用xml方式

配置yml

mybatis-plus:
 mapper-locations: "classpath*:/mapper/**.xml" # Mapper.xml

mapper 

    List<UserInfo> selectByCustom2(@Param(Constants.WRAPPER) Wrapper wrapper);

编写UserInfoMapper.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.example.demo.mapper.UserInfoMapper">

    <select id="selectByCustom2" resultType="com.example.demo.model.UserInfo">
        select id,username,password,age FROM user_info ${ew.customSqlSegment}
    </select>
</mapper>
    //UPDATE user_info SET delete_flag=0, age=5 WHERE id IN (1,2,3)
    @Update("UPDATE user_info SET age = age + #{age}} ${ew.customSqlSegment}")
    List<UserInfo> update(@Param("age") Integer age, @Param(Constants.WRAPPER) Wrapper wrapper);

测试 

    @Test
    void update() {
        UpdateWrapper<UserInfo> updateWrapper = new UpdateWrapper<>();
        updateWrapper.in("id", List.of(1,2,3))
                .in("id", List.of(1,2,3));
        userInfoMapper.update(10,updateWrapper);
    }

总结

1. MyBatis-Plus是MyBatis的增强⼯具,在MyBatis的基础上只做增强不做改变,可以⽤更少的代码 实现数据库表的CRUD,让我们的开发变得更加简单.

2. MyBatis-Plus⽀持⾃定义SQL,版本不低于3.0.7,传递Wrapper对象作为参数时,参数名必须为ew, 在SQL语句中,使⽤${ew.customSqlSegment}来引⽤Wrapper对象⽣成的SQL⽚段

mybatis-plus报空指针异常可能是因为在普通类调用Mapper接口时,使用了mybatis-plus的功能,但在泛型类中找不到id属性,导致查找到的值为空。这会引发空指针异常(NullPointerException)。为了解决这个问题,可以通过深入学习MyBatis并了解其核心对象、配置文件和映射文件的使用来修复。确保在泛型类中定义了正确的id属性,并正确配置映射文件中的语句映射。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [SpringBoot:在普通类调用 Mapper 接口使用 MybatisPlus 报错:空指针异常(NullPointerException)](https://blog.youkuaiyun.com/weixin_43642521/article/details/124491271)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [MyBatis-plus使用出现空指针异常或者表不纯在](https://blog.youkuaiyun.com/gtq1061414470/article/details/121019792)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [SSM框架的学习与应用JavaEE(第二天)Mybatis的深入学习](https://download.youkuaiyun.com/download/m0_53659738/88241458)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值