红茶的个人站点

  • 首页
  • 专栏
  • 开发工具
  • 其它
  • 隐私政策
Awalon
Talk is cheap,show me the code.
  1. 首页
  2. 专栏
  3. Spring Boot 学习笔记
  4. 正文

从零开始 Spring Boot 4:Mybatis Plus

2022年4月30日 1169点热度 0人点赞 0条评论

spring boot

图源:简书 (jianshu.com)

虽然上篇文章从零开始 Spring Boot 3:数据库 - 魔芋红茶's blog (icexmoon.cn)介绍了如何在Spring Boot中连接并使用数据库,但可以看到,默认提供的JdbcTemplate并不是很好用。

因此,本篇文章将介绍一个更好用的数据库连接组件MyBatis-Plus,并展示如何用在我们的示例中用MyBatis-Plus取代JdbcTemplate完成相关数据库操作。

你可以通过learn_spring_boot(github.com)获取本篇文章用于修改的基础示例代码。

什么是 MyBatis-Plus

MyBatis是一个优秀的持久层框架,可以利用它创建实体层对数据库的映射(其作用类似各种ORM框架)。

而 MyBatis-Plus 是在MyBatis的基础上发展而来,相比于MyBatis,无需配置各种XML文件,更容易使用。

MyBatis-Plus是一个国人开发的框架,所以文档资料很容易查看和获取,其官方网站为:

  • MyBatis-Plus

因此这里不做过多介绍,直接看如何在我们的示例项目中使用MyBatis-Plus。

添加依赖

与其它第三方组件类似,需要先添加依赖:

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

目前最新的版本是3.5.1。

Model

和其它ORM框架一样,为了建立对数据库的映射关系,需要给实体类添加注解:

package cn.icexmoon.my_first_app.model;
​
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
​
@Data
@TableName("user")
public class User {
    @TableId(type = IdType.AUTO)
    private Long id;
    @TableField
    private String name;
    @TableField
    private Integer age;
}

@TableName注解指定表名,@TableId注解指定主键,@TableField注解指定普通表字段。@TableId注解有一个type属性,是一个枚举值,可以用来指定主键类型。比如这里用IdType.AUTO指定主键是自增的。

Mapper

可以添加一个Mapper接口作为对数据库的映射,我们可以通过操作这个接口来操作数据库:

package cn.icexmoon.my_first_app.mapper;
​
import cn.icexmoon.my_first_app.model.User;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
​
public interface UserMapper extends BaseMapper<User> {
​
}

Mapper接口需要继承自BaseMapper<T>接口,这里的类型参数T必须是对应的实体类,这里就是User。

为了能让MyBatis Plus扫描到Mapper,还需要在入口类上添加一个@MapperScan注解:

package cn.icexmoon.my_first_app;
​
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
​
@SpringBootApplication
@MapperScan("cn.icexmoon.my_first_app.mapper")
public class MyFirstAppApplication {
​
    public static void main(String[] args) {
​
        SpringApplication.run(MyFirstAppApplication.class, args);
    }
​
}

这里@MapperScan的value属性应该指定为Mapper接口所在的包名。

接下来我们只需要修改Service层,让UserService使用Mapper操作数据库即可:

package cn.icexmoon.my_first_app.service;
​
import cn.icexmoon.my_first_app.mapper.UserMapper;
import cn.icexmoon.my_first_app.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
​
import java.util.List;
​
@Service
public class UserService {
    @Autowired
    private UserMapper userMapper;
​
    public long addUser(User user) {
        userMapper.insert(user);
        return user.getId();
    }
​
    public void deleteUser(long id) {
​
        userMapper.deleteById(Long.valueOf(id));
    }
​
    public List<User> getUsers() {
        return userMapper.selectList(null);
    }
​
    public User getUser(long id) {
        return userMapper.selectById(Long.valueOf(id));
    }
​
    public void updateUser(User user) {
        userMapper.updateById(user);
    }
}

这里对UserMapper的调用都比较简单,所以不一一说明。需要说明的是,通过UserMapper.insert方法添加数据后,只需要通过User.getId就可以获取到自增主键,因为我们已经在实体类中通过注解指定了主键对应的属性以及其类型为自增。

可以看到,使用MyBatis Plus实现相同的功能相比JDBCTemplate要容易很多,代码量也少很多。

  • 更多的Mapper接口调用方式可以阅读CRUD 接口 | MyBatis-Plus。

  • 需要注意的是,MyBatis Plus中很多类似于selectById这样的方法,接受的都是一个Serializable类型的参数,所以是不能传入基础类型的,需要使用包装类进行转换。

Service

实际上除了通过Mapper操作数据库,MyBatis Plus还支持利用Mapper创建简单的Service。

这里为了更好的复用代码,不删除已有的UserService实现,添加一个UserServiceInterface接口:

package cn.icexmoon.my_first_app.service;
​
import cn.icexmoon.my_first_app.model.User;
​
import java.util.List;
​
public interface UserServiceInterface {
    long addUser(User user);
    void deleteUser(long id);
    List<User> getUsers();
    User getUser(long id);
    void updateUser(User user);
}

UserService继承该接口:

@Service
public class UserService implements UserServiceInterface {
    ...
}

UserController使用UserServiceInterface接口而非具体实现:

@RestController
@RequestMapping("/user")
public class UserController {
    private UserService userService;
    private UserServiceInterface userServiceInterface;
​
    @Autowired
    public UserController(UserService userService){
        userServiceInterface = userService;
    }
    ...
}

UserController中各种方法都需要修改为使用userServiceInterface而非userService,这里不一一展示。

这里需要注意的是,因为要通过UserController的构造器来为userServiceInterface指定一个具体实现,所以这里不再通过为属性添加@Autowired注解的方式,而是直接为构造器添加@Autowired注解来注入UserService对象。

如果不这么做,就会产生NULLPointException,原因是@Autowired标记的属性注入发生在构造器调用之后,所以userServiceInterface不会被正确初始化。

这里可以测试一下当前重构后的代码是否有问题。

下面使用MyBatis Plus创建Service层,并在Controller中进行调用。

要用MyBatis Plus创建Service,必须要先创建一个从IService扩展的接口:

package cn.icexmoon.my_first_app.service;
​
import cn.icexmoon.my_first_app.model.User;
import com.baomidou.mybatisplus.extension.service.IService;
​
interface UserServiceMP extends IService<User> {
}

然后利用该接口创建一个Service:

package cn.icexmoon.my_first_app.service;
​
import cn.icexmoon.my_first_app.mapper.UserMapper;
import cn.icexmoon.my_first_app.model.User;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
​
import java.util.List;
​
@Service
public class UserServiceMPImpl extends ServiceImpl<UserMapper, User> implements UserServiceMP,UserServiceInterface{
​
    @Override
    public long addUser(User user) {
        this.save(user);
        return user.getId();
    }
​
    @Override
    public void deleteUser(long id) {
        this.removeById(Long.valueOf(id));
    }
​
    @Override
    public List<User> getUsers() {
        return this.list();
    }
​
    @Override
    public User getUser(long id) {
        return this.getById(Long.valueOf(id));
    }
​
    @Override
    public void updateUser(User user) {
        this.updateById(user);
    }
}

UserServiceMPImpl继承自ServiceImpl<Mapper<T>, T>,这里类型参数Mapper<T>对应的是Mapper接口,T是实体类。该类还需要实现我们之前创建的UserServiceMP接口。

这里实现UserServiceInterface接口并不是通过MyBatis Plus生成Service的习惯做法,只不过是我们的示例项目之前重构旧代码的需要。

因为UserServiceMPImpl实现了UserServiceInterface接口,所以可以很容易地在Controller中替换UserServiceInterface的实现:

@RestController
@RequestMapping("/user")
public class UserController {
    private UserService userService;
    private UserServiceInterface userServiceInterface;
​
    @Autowired
    public UserController(UserService userService, UserServiceMPImpl userServiceMPImpl){
        userServiceInterface = userServiceMPImpl;
    }
    ...
}
  • 这里不再使用UserService,应当将其删除,不过出于比较两者实现的考虑,没有这么做。

  • 因为旧代码的关系,我这里的Service层命名有些混乱,可以用UserService作为接口名称,用UserServiceImpl作为具体实现类的命名,用UserServiceMp作为使用MyBatis Plus定义的Service接口,用UserServiceMpImpl作为对应的实现类。。

现在再试一下,会发现和原来的实现没有任何区别。

具体使用Service还是Mapper取决于你,其实两者提供的功能是类似的。

更多的Service接口调用方式可以阅读CRUD 接口 | MyBatis-Plus。

今天的内容就到这里了,谢谢阅读。

参考资料

  • MyBatis中文网

  • MyBatis-Plus

  • @Autowired注解你真的会用吗?Spring官方有话说 - 云+社区 - 腾讯云 (tencent.com)

  • MyBatis-Plus 通用IService的使用 - 简书 (jianshu.com)

本作品采用 知识共享署名 4.0 国际许可协议 进行许可
标签: java spring boot
最后更新:2022年8月29日

魔芋红茶

加一点PHP,加一点Go,加一点Python......

点赞
< 上一篇
下一篇 >

文章评论

取消回复

*

code

COPYRIGHT © 2021 icexmoon.cn. ALL RIGHTS RESERVED.
本网站由提供CDN加速/云存储服务

Theme Kratos Made By Seaton Jiang

宁ICP备2021001508号

宁公网安备64040202000141号