前言

最近看有些同学去找了实习,大部分都是使用的mybatis-plus进行开发,由于团队开发的项目是中小型项目比较多,所以就很少接触过Mybatis,基于此我去了解下基本用法。

MyBatis、Hibernate 与 MyBatis-Plus 的对比分析

什么是Hibernate?

Hibernate帮你管理 Java 对象和数据库之间的转换,让你不用写 SQL 也能操作数据库。你只需要定义 Java 类,Hibernate 就能自动把它们映射到数据库表,并且处理增删改查。相比 MyBatis 需要自己写 SQL,Hibernate 更像是全自动模式,它会帮你生成 SQL,但有时候可能会执行额外的查询,影响性能。

image.png

什么是 MyBatis?

MyBatis 就像是一个SQL 助手,它帮你省去了一堆麻烦,比如连接数据库、执行 SQL 语句这些底层操作。你只需要专注于写 SQL,它就能帮你把数据库查询的结果自动转换成 Java 对象,或者把 Java 对象的数据存进数据库。相比 JPA 这种全自动 ORM 框架,MyBatis 让你能手动控制 SQL,保证性能,同时又不会像原生 JDBC 那样写一堆重复代码。

什么是Mybatis-plus?

MyBatis-Plus是基于 MyBatis 的增强工具,旨在简化 MyBatis 的开发,提升效率。它提供了许多开箱即用的功能,例如 单表 CRUD、分页、Lambda 表达式查询、逻辑删除 等,让开发者可以更专注于业务逻辑,而无需编写大量的 SQL 代码。

image.png

右侧部分展示了 MyBatis-Plus 的核心组件:

annotation(注解模块)
提供 实体映射注解,如:

  • @TableName(指定表名)
  • @TableId(主键标识)
  • @TableField(字段映射)
  • @Version(乐观锁)

core(核心模块)
包含 MyBatis-Plus CRUD 基础功能,如:

  • BaseMapper、LambdaQueryWrapper 等 API
  • 自动分页
  • 逻辑删除等

extension(扩展模块)
ServiceImpl 提供 Service 层 封装

  • Wrapper 查询构造器
  • Interceptor 插件(分页、数据权限)

generator(代码生成器)
自动生成:

  • Entity(实体类)
  • Mapper(数据访问层)
  • Service(业务逻辑层)
  • Controller(接口层)

MyBatis-plus实践案例

导入maven依赖

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

创建数据库表,并插入一些数据

CREATE TABLE user (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(50) NOT NULL,
    age INT NOT NULL,
    email VARCHAR(100) UNIQUE
);

DELETE FROM `user`;

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

定义实体类

加上@TableName注解

import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

@Data
@TableName("user")  // 指定表名
public class User {
    @TableId  // 指定主键
    private Long id;
    private String name;
    private Integer age;
    private String email;
}

创建 Mapper 接口

@Mapper
public interface UserMapper extends BaseMapper<User> {
}

查看BaseMapper方法,发现集成了很多写好的方法

image.png

查看Hibernate的CrudRepository,是不是有一种熟悉的感觉

image.png

使用 MyBatis-Plus 基于单表进行 CRUD 操作

@Service
public class UserService {
 private final UserMapper userMapper;

   public int addUser(UserDto.SaveRequest request) {
        User user = new User();
        user.setName(request.getName());
        user.setAge(request.getAge());
        user.setEmail(request.getEmail());
        // // 自动生成 SQL:INSERT INTO user (name, age, email) VALUES (?,?,?)
        return userMapper.insert(user);
    }

    public List<User> getAllUsers() {
        // SELECT * FROM user
        return userMapper.selectList(null); 
    }

    // 条件查询用户(Select with Condition)
    public List<User> getUsersByAge(int minAge) {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.ge("age", minAge); // age >= minAge
        return userMapper.selectList(queryWrapper);
    }

    public int update(Long id, UserDto.UpdateRequest request) {
          User user = new User();
          user.setId(id);
          user.setEmail(request.getEmail());
          // UPDATE user SET email=? WHERE id=?
          return userMapper.updateById(user);
      }

    //  删除用户(Delete)
    public void deleteUser(Long id) {
        // DELETE FROM user WHERE id=?
        userMapper.deleteById(id);  
    }
}

基于多对多查询

数据库增加角色表

CREATE TABLE role (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(50) NOT NULL UNIQUE
);

CREATE TABLE user_role (
    user_id BIGINT,
    role_id BIGINT,
    PRIMARY KEY (user_id, role_id),
    FOREIGN KEY (user_id) REFERENCES user(id) ON DELETE CASCADE,
    FOREIGN KEY (role_id) REFERENCES role(id) ON DELETE CASCADE
);

INSERT INTO `role` (id, name) VALUES
(1, 'Admin'),
(2, 'User'),
(3, 'Manager'),
(4, 'Editor'),
(5, 'Viewer');

INSERT INTO `user_role` (user_id, role_id) VALUES
(1, 1), -- Jone -> Admin
(1, 2), -- Jone -> User
(2, 2), -- Jack -> User
(3, 3), -- Tom -> Manager
(4, 4), -- Sandy -> Editor
(5, 5), -- Billie -> Viewer
(5, 2); -- Billie -> User

增加Role实体和修正User实体

@Data
@TableName("role")
public class Role {
    @TableId(type = IdType.AUTO)
    private Long id;
    private String name;

@Data
@TableName("user")  // 指定表名
public class User {
    @TableId  // 指定主键
    private Long id;
    private String name;
    private Integer age;
    private String email;

    @TableField(exist = false) // 该字段不在数据库表中
    private List<Role> roles;
}

改进 UserMapper.java,这里我们可以看出来,只要涉及到与其他表关联,还是要手写sql

import org.apache.ibatis.annotations.*;
import java.util.List;

@Mapper
public interface UserMapper extends BaseMapper<User> {

   @Select("SELECT id, name, age, email FROM user WHERE id = #{userId}")
    @Results({
            @Result(column = "id", property = "id"),
            @Result(column = "name", property = "name"),
            @Result(column = "age", property = "age"),
            @Result(column = "email", property = "email"),
            @Result(property = "roles", column = "id",
                    many = @Many(select = "com.kxb.api.mapper.UserMapper.getRolesByUserId"))
    })
    User findUserWithRoles(Long userId);

    @Select("SELECT r.id, r.name FROM role r " +
            "LEFT JOIN user_role ur ON r.id = ur.role_id " +
            "WHERE ur.user_id = #{userId}")
    List<Role> getRolesByUserId(Long userId);
}

从这里看到把关联的数据查出来了

image.png

generator(代码生成器)案例

导入代码生成器依赖

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-generator</artifactId>
    <version>3.5.10.1</version>
</dependency>

<dependency>
    <groupId>org.freemarker</groupId>
    <artifactId>freemarker</artifactId>
    <version>2.3.32</version>
</dependency>

通过 builder 模式可以快速生成你想要的代码

public class FastAutoGeneratorTest {
    public static void main(String[] args) {
        FastAutoGenerator.create("jdbc:mysql://localhost:3308/practice?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=false", "root", "yunzhi")
                .globalConfig(builder -> builder
                        .author("kxb")
                        .outputDir(Paths.get(System.getProperty("user.dir")) + "/src/main/java")
                        .commentDate("yyyy-MM-dd")
                )
                .packageConfig(builder -> builder
                        .parent("com.kxb.api")
                        .entity("entity")
                        .mapper("mapper")
                        .service("service")
                        .serviceImpl("service.impl")
                        .xml("mapper.xml")
                )
                .strategyConfig(builder -> builder
                        .entityBuilder()
                        .enableLombok()
                )
                .templateEngine(new FreemarkerTemplateEngine())
                .execute();
    }
}

这里看到没生成前

image.png

执行后,我们这里看到了这里根据我们数据库的表生成文件

image.png

打开IUserService发现接口实现了IService<T>,而UserServiceImpl实现了ServiceImpl<M, T>

组件作用
IService<T>定义通用的CRUD方法
ServiceImpl<M, T>实现类,实现了IService<T>, 封装了MyBatis的操作

ServiceImpl<M, T> 解析

public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
}

等价于

@Service
public class UserServiceImpl implements IUserService {
    
    @Autowired
    private UserMapper userMapper;

    @Override
    public boolean save(User entity) {
        return userMapper.insert(entity) > 0;
    }

    @Override
    public User getById(Serializable id) {
        return userMapper.selectById(id);
    }

    @Override
    public boolean removeById(Serializable id) {
        return userMapper.deleteById(id) > 0;
    }
    
    @Override
    public boolean updateById(User entity) {
        return userMapper.updateById(entity) > 0;
    }
    
    @Override
    public List<User> list() {
        return userMapper.selectList(null);
    }
}

总结

Mybatis-plus 这些功能用起来的效果还是比较适用于单表的单表查询,已经帮我们实现大部份的CRUD方法,而多表查询还是得使用手写SQL的方式。而Hibernate在基于多表查询的时候更简单一些,能自动生成SQL,支持关联查询。使用MyBatis-plus下来的感受就是更适合性能要求高、多表查询复杂的场景,如果不要求性能的话,还是使用Hibernate来的方便,不用自己创建表,也不用手写sql,唯一不足的就是会查出很多冗余数据。


kexb
544 声望23 粉丝

引用和评论

0 条评论