Featured image of post 全栈开发日志 Part.4

全栈开发日志 Part.4

与数据库交互:MyBatis (Plus)

与数据库交互:MyBatis (Plus)

ORM

ORM(Object Relational Mapping,对象关系映射)是为了解决面向对象与 关系数据库存在的互不匹配现象的一种技术。

MyBatis (Plus)

  • MyBatis是一款优秀的数据持久层ORM框架,,广泛地应用于应用系统。

  • MyBatis能够非常灵活地实现动态SQL,可以使用XML或注解来配置和映射原生信息,能够轻松地将Java的POJO(Plain Ordinary Java Object,普通的Java对象)与数据库中的表和字段进行映射关联。

  • MyBatis Plus是一个MyBatis的增强工具,在MyBatis的基础上做了增强,简化了开发。

添加如下依赖:

1
2
3
4
5
6
//mybatis-plus
implementation 'com.baomidou:mybatis-plus-boot-starter:3.5.16'
//mysql驱动
implementation 'com.mysql:mysql-connector-j:9.5.0'
//数据连接池druid
implementation 'com.alibaba:druid-spring-boot-starter:1.2.27'

连接池技术可以一次性申请多个数据库连接,提高效率。

SpringBoot的配置修改如下

1
2
3
4
5
6
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/mydb?useSSL=false
spring.datasource.username=root
spring.datasource.password=051008
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

其中mydb应该修改为你数据库的名称。

在SpringBoot的启动类里面加上注解:

1
@MapperScan("dev.mczs.springbootstu.mapper")

其中mapper包中放置操作数据库相关的类,这个包名是约定俗成的。

  • Mybatis Plus的版本与Spring Boot的版本需要匹配。具体参考安装 | MyBatis-Plus

  • 旧的 MySQL 驱动类com.mysql.jdbc.Driver已废弃,推荐使用com.mysql.cj.jdbc.Driver

如何MyBatis利用编写一个Mapper

Swagger 默认生成小写开头的变量名,其遵循了 JavaBean 规范、JSON 行业通用惯例,以及前后端数据交互的主流标准,这个设计是为了让 API 文档更贴合实际开发,降低前后端对接成本,所以无论数据库还是Java代码,变量的命名都尽量遵守JavaBean规范JSON 行业惯例

如果你有命名不规范的情况,请查看MyBatis Plus的开发文档中的相关注解,下面这个配置参数在某些情况下可能有用:

1
mybatis-plus.configuration.map-underscore-to-camel-case=false
  1. 对于你要做查询的表,编写好一个类来对应其属性(类中的定义可以只保留你需要的变量)。

IDEA中使用Alt+Insert可以快速写出GetterSetter或其它常用的方法。

  1. 编写一个Mapper类,其方法类应该是一个接口的声明,MyBatis会自动接管并帮我们实现这个以这接口为父类的实现类,所以我们写的接口类当含有@Mapper注解,对于常见的SQL操作,我们需要编写方法声明,其实现参考下面示例。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
@Mapper
public interface MemberInfoMapper {

    //查询所有用户
    //@Select()注解里面编写SQL语句
    @Select("select * from t_memberinfo")
    public List<User> queryAll();

    // 插入用户
    @Insert("INSERT INTO t_memberinfo (MemberID, Name, Gender, Age, WorkUnit, Contact, LevelID, Points) " +
            "VALUES (#{MemberID}, #{Name}, #{Gender}, #{Age}, #{WorkUnit}, #{Contact}, #{LevelID}, #{Points})")
    int insertUser(User user);
}

常见注解如下

注解 功能
@Insert 实现插入
@Update 实现更新
@Delete 实现删除
@Select 实现查询
@Result 实现结果集封装
@Results 可以与@Result一起使用,封装多个结果集
@One 实现一对一结果集封装
@Many 实现一对多结果集封装
  1. Mapper调用的时候需要实例化该接口的实现类,MyBatis会处理这个问题,其应该在实例化的时候加上@Autowired注解,对上述Mapper的应用如下。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
@RestController
public class UserController {

    @Autowired
    //添加@Autowired注解表示该类的实现及实例化交给MyBatis
    private MemberInfoMapper memberInfoMapper;

    @GetMapping("/user")
    //这里返回List给前端的时候会自动转换为Json
    public List<User> quert() {
        return memberInfoMapper.queryAll();
    }

    @PostMapping("/user")
    public String insertUser(@RequestBody User user) {
        int val = memberInfoMapper.insertUser(user);
        if (val > 0){
            return  "success";
        }
        return "fail";
    }
}

如何利用MyBatis Plus编写Mapper

  1. 对于你要做查询的表,编写好一个类来对应其属性(类中的定义可以只保留你需要的变量)。

当表名与编写的类名称不对应时,应该自行在该类头添加@TableName("表名")注解。

例如:

1
2
3
4
5
6
@TableName("t_memberinfo")
public class User {
    private String MemberID;
    private String Name;
    ...
}
  1. Mapper类的实现可以利用MyBatis Plus简化为如下示例。
1
2
3
@Mapper
public interface MemberInfoMapper extends BaseMapper<User> {
}
  1. Mapper调用的时候MyBatis Plus会自动生成方法接口然后动态实现,对上述Mapper的应用如下。(更多方法查看简介 | MyBatis-Plus
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
@RestController
public class UserController {

    @Autowired
    private MemberInfoMapper memberInfoMapper;

    @GetMapping("/user")
    public List<User> query() {
        return memberInfoMapper.selectList(null);
    }

    @PostMapping("/user")
    public String insertUser(@RequestBody User user) {
        int val = memberInfoMapper.insert(user);
        if (val > 0){
            return  "success";
        }
        return "fail";
    }
}

以上代码中的变量命名其实不太遵守规范,Java参照JavaBean规范

SQL命名核心遵循「全小写 + 下划线分隔」(避免大小写敏感问题),不同数据库(MySQL/Oracle)对大小写处理不同,全小写+下划线是跨库兼容的最优解:

命名元素 规则 示例 反例
数据库名 全小写 + 下划线,语义为项目/业务名 supermarket_vip(你的超市会员库) SupermarketVIP超市会员
表名 全小写 + 下划线,推荐加业务前缀(如t_表、idx_索引),避免复数 t_member_info(会员表) tMemberInfoMemberInfo
字段名 全小写 + 下划线,语义清晰,禁止缩写/大写,主键推荐xxx_id member_id(会员ID)、user_namecontact_phone MemberIDUserNametel
主键名 表名+_id(唯一主键),禁止用id(语义模糊) member_info_id IDmemberID
索引名 类型前缀 + 表名 + 字段名,如idx_(普通索引)、uk_(唯一索引) idx_member_info_contact(联系方式索引) index_contactContactIndex
外键名 表名 + _ + 关联表主键名 order_info_member_id(订单关联会员ID) memberIdMemberID

MyBatis原理

MyBatis 框架通过「动态代理」技术为你自动生成了接口的实现类,这是 MyBatis 简化数据库操作的核心设计。

底层技术原理(JDK 动态代理)

MyBatis 实现这一功能的核心是JDK 动态代理(因为 Mapper 是接口,JDK 动态代理只能代理接口),具体执行流程如下:

步骤 1:启动时扫描并注册 Mapper 接口

Spring Boot 集成 MyBatis 后,启动时会通过@MapperScan(或@Mapper注解)扫描所有 Mapper 接口,将这些接口的信息注册到 MyBatis 的容器中,告诉 MyBatis:「这些接口需要生成代理实现类」。

步骤 2:调用 Mapper 方法时创建动态代理对象

当你的代码中通过@Autowired注入MemberInfoMapper并调用queryAll()方法时:

  1. MyBatis 不会直接返回接口本身(接口无法实例化),而是返回一个MapperProxy(MyBatis 内置的代理类)的实例,这个实例实现了MemberInfoMapper接口;

  2. MapperProxy是 JDK 动态代理的核心载体,它会接管所有接口方法的调用。

步骤 3:解析注解 / SQL 并执行数据库操作

MapperProxy接收到queryAll()方法的调用后,会执行以下操作:

  1. 解析方法上的@Select("select * from t_memberinfo")注解,提取出要执行的 SQL 语句;

  2. 通过 Druid 等连接池获取数据库连接;

  3. 预处理并执行 SQL,得到数据库返回的结果集;

  4. 将结果集映射为List<User(根据 User 类的字段和数据库列名匹配);

  5. 关闭数据库连接(连接池管理,并非真正关闭),返回映射后的结果。

步骤 4:返回结果给调用方

动态代理对象将映射后的List<User返回,你在业务代码中拿到的就是最终的查询结果,全程感知不到代理类的存在。

本作品采用知识共享署名-非商业性使用-相同方式共享4.0国际许可协议进行许可(CC BY-NC-SA 4.0)
文章浏览量:Loading
Powered By MC ZBD Studio
发表了57篇文章 · 总计111.20k字
载入天数...载入时分秒...
总浏览量Loading | 访客总数Loading

主题 StackJimmy 设计
由ZephyrBD修改