MyBatis无缝转MyBatis-plus+基本使用

1.引入依赖

引入MyBatis-plus依赖取代MyBatis

<!--mybatis-plus起步依赖-->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.5.3.1</version>
</dependency>

2.改造Mapper

继承BaseMapper

public interface 原来的Mapper extends BaseMapper<这里填入这个mapper对应的实体类> {

}

3.改造实体类

需要用到以下三个注解

@TableName("这里填写表名") // 指定数据库表的对应

@TableId(value = "这里填写主键字段名",type = IdType.AUTO) // 指定主键的对应

@TableField("这里填写字段名") // 指定字段的对应

一个完整的实体类参考如下:

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@TableName("table_name")
public class tableName implements Serializable {
    @TableId(value = "table_id",type = IdType.AUTO)
    private Long tableId;
    @TableField("table_field")
    private String tableField;
}

注意:

一般情况下我们并不需要给字段添加@TableField注解,一些特殊情况除外:

  • 成员变量名与数据库字段名不一致

  • 成员变量是以isXXX命名,按照JavaBean的规范,MybatisPlus识别字段时会把is去除,这就导致与数据库不符。

  • 成员变量名与数据库一致,但是与数据库的关键字冲突。使用@TableField注解给字段名添加转义字符:``

支持的其它属性如下:

属性类型必填默认值描述
valueString""数据库字段名
existbooleantrue是否为数据库表字段
conditionString""字段 where 实体查询比较条件,有值设置则按设置的值为准,没有则为默认全局的 %s=#{%s},参考(opens new window)
updateString""字段 update set 部分注入,例如:当在version字段上注解update="%s+1" 表示更新时会 set version=version+1 (该属性优先级高于 el 属性)
insertStrategyEnumFieldStrategy.DEFAULT举例:NOT_NULL insert into table_a(<if test="columnProperty != null">column</if>) values (<if test="columnProperty != null">#{columnProperty}</if>)
updateStrategyEnumFieldStrategy.DEFAULT举例:IGNORED update table_a set column=#{columnProperty}
whereStrategyEnumFieldStrategy.DEFAULT举例:NOT_EMPTY where <if test="columnProperty != null and columnProperty!=''">column=#{columnProperty}</if>
fillEnumFieldFill.DEFAULT字段自动填充策略
selectbooleantrue是否进行 select 查询
keepGlobalFormatbooleanfalse是否保持使用全局的 format 进行处理
jdbcTypeJdbcTypeJdbcType.UNDEFINEDJDBC 类型 (该默认值不代表会按照该值生效)
typeHandlerTypeHander类型处理器 (该默认值不代表会按照该值生效)
numericScaleString""指定小数点后保留的位数

4-1.改造Service

第一种情况:使用条件构造器

QueryWrapper

除了新增以外,修改、删除、查询的SQL语句都需要指定where条件。因此BaseMapper中提供的相关方法除了以id作为where条件以外,还支持更加复杂的where条件。

基本用法:

List<xx> xxList = xxMapper.selectList(new QueryWrapper<xx>());

mapper对象调用方法,里面传递一个queryWrapper对象

其它方法:

UpdateWrapper

基于BaseMapper中的update方法更新时只能直接赋值,对于一些复杂的需求就难以实现。 例如:更新id为1,2,4的用户的余额,扣200,对应的SQL应该是:

UPDATE user SET balance = balance - 200 WHERE id in (1, 2, 4)

SET的赋值结果是基于字段现有值的,这个时候就要利用UpdateWrapper中的setSql功能了:

@Test
void testUpdateWrapper() {
    List<Long> ids = List.of(1L, 2L, 4L);
    // 1.生成SQL
    UpdateWrapper<User> wrapper = new UpdateWrapper<User>()
            .setSql("balance = balance - 200") // SET balance = balance - 200
            .in("id", ids); // WHERE id in (1, 2, 4)
        // 2.更新,注意第一个参数可以给null,也就是不填更新字段和数据,
    // 而是基于UpdateWrapper中的setSQL来更新
    userMapper.update(null, wrapper);
}

LambdaQueryWrapper

无论是QueryWrapper还是UpdateWrapper在构造条件的时候都需要写死字段名称,会出现字符串魔法值。这在编程规范中显然是不推荐的。 那怎么样才能不写字段名,又能知道字段名呢?

其中一种办法是基于变量的gettter方法结合反射技术。因此我们只要将条件对应的字段的getter方法传递给MybatisPlus,它就能计算出对应的变量名了。而传递方法可以使用JDK8中的方法引用Lambda表达式。 因此MybatisPlus又提供了一套基于Lambda的Wrapper,包含两个:

  • LambdaQueryWrapper

  • LambdaUpdateWrapper

分别对应QueryWrapper和UpdateWrapper

其使用方式如下:

@Test
void testLambdaQueryWrapper() {
    // 1.构建条件 WHERE username LIKE "%o%" AND balance >= 1000
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    wrapper.lambda()
            .select(User::getId, User::getUsername, User::getInfo, User::getBalance)
            .like(User::getUsername, "o")
            .ge(User::getBalance, 1000);
    // 2.查询
    List<User> users = userMapper.selectList(wrapper);
    users.forEach(System.out::println);
}

第二种情况:使用自定义SQL

在演示UpdateWrapper的案例中,我们在代码中编写了更新的SQL语句:

这种写法在某些企业也是不允许的,因为SQL语句最好都维护在持久层,而不是业务层。就当前案例来说,由于条件是in语句,只能将SQL写在Mapper.xml文件,利用foreach来生成动态SQL。 这实在是太麻烦了。假如查询条件更复杂,动态SQL的编写也会更加复杂。

所以,MybatisPlus提供了自定义SQL功能,可以让我们利用Wrapper生成查询条件,再结合Mapper.xml编写SQL

基本用法

Service

@Test
void testCustomWrapper() {
    // 1.准备自定义查询条件
    List<Long> ids = List.of(1L, 2L, 4L);
    QueryWrapper<User> wrapper = new QueryWrapper<User>().in("id", ids);
​
    // 2.调用mapper的自定义方法,直接传递Wrapper
    userMapper.deductBalanceByIds(200, wrapper);
}

Mapper

package com.itheima.mp.mapper;
​
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.itheima.mp.domain.po.User;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Update;
import org.apache.ibatis.annotations.Param;
​
public interface UserMapper extends BaseMapper<User> {
    @Select("UPDATE user SET balance = balance - #{money} ${ew.customSqlSegment}")
    void deductBalanceByIds(@Param("money") int money, @Param("ew") QueryWrapper<User> wrapper);
}

多表关联

理论上来讲MyBatisPlus是不支持多表查询的,不过我们可以利用Wrapper中自定义条件结合自定义SQL来实现多表查询的效果。 例如,我们要查询出所有收货地址在北京的并且用户id在1、2、4之中的用户 要是自己基于mybatis实现SQL,大概是这样的:

<select id="queryUserByIdAndAddr" resultType="com.itheima.mp.domain.po.User">
      SELECT *
      FROM user u
      INNER JOIN address a ON u.id = a.user_id
      WHERE u.id
      <foreach collection="ids" separator="," item="id" open="IN (" close=")">
          #{id}
      </foreach>
      AND a.city = #{city}
  </select>

可以看出其中最复杂的就是WHERE条件的编写,如果业务复杂一些,这里的SQL会更变态。

但是基于自定义SQL结合Wrapper的玩法,我们就可以利用Wrapper来构建查询条件,然后手写SELECT及FROM部分,实现多表查询。

查询条件这样来构建:

@Test
void testCustomJoinWrapper() {
    // 1.准备自定义查询条件
    QueryWrapper<User> wrapper = new QueryWrapper<User>()
            .in("u.id", List.of(1L, 2L, 4L))
            .eq("a.city", "北京");
​
    // 2.调用mapper的自定义方法
    List<User> users = userMapper.queryUserByWrapper(wrapper);
​
    users.forEach(System.out::println);
}

然后在UserMapper中自定义方法:

@Select("SELECT u.* FROM user u INNER JOIN address a ON u.id = a.user_id ${ew.customSqlSegment}")
List<User> queryUserByWrapper(@Param("ew")QueryWrapper<User> wrapper);

当然,也可以在UserMapper.xml中写SQL:

<select id="queryUserByIdAndAddr" resultType="com.itheima.mp.domain.po.User">
    SELECT * FROM user u INNER JOIN address a ON u.id = a.user_id ${ew.customSqlSegment}
</select>

4-2.IService使用

4-1的查询数据库的方式相比Mybatis已经很方便了,至少不用再手写sql语句。

但是还可以更简便,我们可以直接在Controller接口层实现数据库的调用。

首先和4-1一样,需要提前准备Mapper、pojo、Service、ServiceImpl、Controller

改造Service层

public interface xxService extends IService<你的pojo> {
}

改造ServiceImpl层

@Service
public class xxServiceImpl extends ServiceImpl<你的Mapper, 你的pojo> implements xxService {
}

然后就可以在Controller使用了

新增

- save是新增单个元素
- saveBatch是批量新增
- saveOrUpdate是根据id判断,如果数据存在就更新,不存在则新增
- saveOrUpdateBatch是批量的新增或修改

删除

- removeById:根据id删除
- removeByIds:根据id批量删除
- removeByMap:根据Map中的键值对为条件删除
- remove(Wrapper<T>):根据Wrapper条件删除

修改

- updateById:根据id修改
- update(Wrapper<T>):根据UpdateWrapper修改,Wrapper中包含set和where部分
- update(T,Wrapper<T>):按照T内的数据修改与Wrapper匹配到的数据
- updateBatchById:根据id批量修改

查询

- getById:根据id查询1条数据
- getOne(Wrapper<T>):根据Wrapper查询1条数据
- getBaseMapper:获取Service内的BaseMapper实现,某些时候需要直接调用Mapper内的自定义SQL时可以用这个方法获取到Mapper
​
- listByIds:根据id批量查询
- list(Wrapper<T>):根据Wrapper条件查询多条数据
- list():查询所有
​
- count():统计所有数量
- count(Wrapper<T>):统计符合Wrapper条件的数据数量
MyBatis Plus 是基于 MyBatis 的增强工具,提供了更加便捷的开发方式。如果你想将项目中的 MyBatis 升级到 MyBatis Plus,可以按照以下步骤进行操作: 1. 添加 MyBatis Plus 依赖:在项目的 `pom.xml`(如果是 Maven 项目)或者 `build.gradle`(如果是 Gradle 项目)文件中添加 MyBatis Plus 的依赖。 2. 修改 MyBatis 的配置文件:将原先的 MyBatis 配置文件中的相关配置修改为 MyBatis Plus 的配置方式。具体的修改内容可以参考 MyBatis Plus 的官方文档。 3. 重新生成代码:如果你使用MyBatis Generator 来自动生成代码,需要重新运行生成器来生成基于 MyBatis Plus 的代码。这样可以确保生成的实体类、Mapper 接口等与 MyBatis Plus 的使用方式保持一致。 4. 修改业务代码:对于已经编写好的业务代码,你可能需要进行一些修改以适应 MyBatis Plus 的使用方式。例如,替换原先使用MyBatis 接口和注解为 MyBatis Plus 提供的对应接口和注解。 5. 测试和调试:在修改完代码后,建议进行全面的测试和调试,确保升级后的项目正常运行,并且功能正常。 6. 学习和使用新特性:MyBatis Plus 提供了很多便捷的特性和功能,可以节省开发时间和提高开发效率。你可以花些时间学习和使用这些新特性,以充分发挥 MyBatis Plus 的优势。 需要注意的是,升级 MyBatisMyBatis Plus 并不会改变原有的 MyBatis 逻辑和使用方式,而是在其基础上提供更多的便利功能。因此,升级过程中需要仔细检查和修改相关代码,确保没有遗漏或者冲突的地方。另外,建议先在一个小规模的项目上进行升级测试,再应用到大型项目中。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值