MyBatis注解方式:从CRUD到数据映射的全面解析

发布于:2025-03-22 ⋅ 阅读:(45) ⋅ 点赞:(0)

1. MyBatis是什么?

MyBatis 是一个功能强大的持久层框架,专注于简化数据库操作。它通过配置文件或注解来管理 SQL 语句,支持动态 SQL,使开发更加灵活和高效。与 Hibernate 等 ORM(对象关系映射)框架不同,MyBatis 更加注重 SQL 的控制,允许开发者直接编写和优化 SQL 语句。
在这里插入图片描述


简单来说 MyBatis 是更简单完成程序和数据库交互的框架,也就是更简单的操作和读取数据库工具
接下来,我们就通过⼀个入门程序,让大家感受⼀下通过Mybatis如何来操作数据库。

2.准备工作

Mybatis操作数据库的步骤:

  1. 准备工作(创建springboot工程、数据库表准备、实体类)
  2. 引⼊Mybatis的相关依赖,配置Mybatis(数据库连接信息)
  3. 编写SQL语句(注解/XML)
  4. 测试

2.1创建工程

创建springboot工程,并导入 mybatis的起步依赖、mysql的驱动包。
在这里插入图片描述


项目工程创建完成后,自动在pom.xml文件中,导入Mybatis依赖和MySQL驱动依赖。

<!--	Mybatis 依赖包	-->
		<dependency>
			<groupId>org.mybatis.spring.boot</groupId>
			<artifactId>mybatis-spring-boot-starter</artifactId>
			<version>3.0.4</version>
		</dependency>
<!--数据库驱动-->
		<dependency>
			<groupId>com.mysql</groupId>
			<artifactId>mysql-connector-j</artifactId>
			<scope>runtime</scope>
		</dependency>

2.2 数据准备

创建用户表(这里使用的是Navicat)

-- 创建数据库
DROP DATABASE IF EXISTS mybatis_test;

CREATE DATABASE mybatis_test DEFAULT CHARACTER SET utf8mb4;

-- 使用数据数据
USE mybatis_test;

-- 创建表[用户表]
DROP TABLE IF EXISTS user_info;
CREATE 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() ON UPDATE 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

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;
}

配置数据库连接字符串
Mybatis中要连接数据库,需要数据库相关参数配置
• MySQL驱动类
• 登录名
• 密码
• 数据库连接字符串

application.yml文件, 配置内容如下:

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

也可以用.porperties配置文件进行配置,前面文章有介绍,本篇文章统一使用yml配置文件。


注意事项:
如果使用 MySQL 是 5.x 之前的使用的是"com.mysql.jdbc.Driver",如果是大于 5.x 使用的
是“com.mysql.cj.jdbc.Driver

2.3 持久层代码

创建一个Mapper接口(比如UserInfoMapper)

在这里插入图片描述

import com.sliqvers.model.UserInfo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import java.util.List;
// @Mapper 交给spring 进行管理

@Mapper
public interface UserInfoMapper {
    @Select("SELECT * FROM user_info")
    List<UserInfo> selectAll();
}

Mybatis的持久层接口规范⼀般都叫 XxxMapper。
@Mapper注解:表⽰是MyBatis中的Mapper接口,交给Spring进行管理。
• 程序运行时, 框架会自动生成接口的实现类对象(代理对象),并给交Spring的IOC容器管理。
• @Select注解:代表的就是select查询,也就是注解对应方法的具体实现内容。


2.4 单元测试

在创建出来的SpringBoot工程中,在src下的test目录下,已经自动帮我们创建好了测试类 ,我们可以
直接使用这个测试类来进行测试。

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class UserInfoMapperTest {
    @Autowired
private UserInfoMapper userInfoMapper;
    @Test
    void selectAll() {
        System.out.println(userInfoMapper.selectAll());
    }
}

解释:
1.@Spring boot Test 加载Spring运行环境
2.@Autowired注解:为UserInfo进行赋值,否则userInfo为空,则程序报错。
3.@Test注解:这是一个测试方法,可以在测试类进行测试。
启动测试观察结果:
在这里插入图片描述
可以看到成功了。

idea 自动生成测试类的方法:
在这里插入图片描述


3.Mybatis的增删改查操作(使用注解方式)

在学习这些操作之前, 我们先来学习MyBatis日志打印
在前面的运行结果可以看到
在这里插入图片描述
这样子的日志并不直观,那怎么办呢?我们进行一下Mybatis的日志打印配置(在.yml文件当中添加):

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

运行结果:
在这里插入图片描述
可以看到打印出来的结果比之前的打印结果更加直观了


3.1 增(insert)

增加之前:
在这里插入图片描述
SQL语句:

insert into user_info (username, `password`, age, gender, phone) values
("张三","张三",19,1,"1646566787");

java代码:

@Mapper
public interface UserInfoMapper {
    //插入
    @Insert("insert into user_info (username, password, age,phone) values (#{username},#{password},#{age},#{phone})")
   Integer insertUser(UserInfo userinfo);
}

测试代码:

   @Test
    void insertUser() {
        UserInfo userInfo=new UserInfo();
        userInfo.setUsername("张三");
        userInfo.setPassword("张三");
        userInfo.setAge(19);
        userInfo.setPhone("1646566787");
        Integer result=userInfoMapper.insertUser(userInfo);
        System.out.println("影响行数" + result + " ,id" + userInfo.getId());
    }

运行结果:
在这里插入图片描述
刷新数据库,看是否插入成功了
在这里插入图片描述
可以看到插入成功了。


提出问题
我们同时看到那个数据库的id是主动自增了的,但是在控制台输出的id是null,那这个是怎么回事呢?

如果想要拿到⾃增id, 需要在Mapper接口的方法上添加一个Options的注解。

@Mapper
public interface UserInfoMapper {
    //插入
    @Options(useGeneratedKeys = true,keyProperty = "id")
    @Insert("insert into user_info (username, password, age,phone) values (#{username},#{password},#{age},#{phone})")
   Integer insertUser(UserInfo userinfo);
}

useGeneratedKeys:这会令 MyBatis使用 JDBC 的 getGeneratedKeys 方法来取出由数据库内
部生成的主键(比如:像 MySQL 和 SQL Server 这样的关系型数据库管理系统的自动递增字
段),默认值:false.
• keyProperty:指定能够唯⼀识别对象的属性,MyBatis 会使用 getGeneratedKeys 的返回值或
insert 语句的 selectKey 子元素设置它的值,默认值:未设置(unset)

我们在新增加一个数据,看是否可以在控制台获取到id的自增值。
增加之前的数据:
在这里插入图片描述

代码(insert):

    @Test
    void insertUser() {
        UserInfo userInfo=new UserInfo();
        userInfo.setUsername("张si");
        userInfo.setPassword("张si");
        userInfo.setAge(19);
        userInfo.setPhone("1646566787");
        Integer result=userInfoMapper.insertUser(userInfo);
        System.out.println("影响行数" + result + " ,id:" + userInfo.getId());
    }

运行结果:
在这里插入图片描述
刷新数据库:
在这里插入图片描述

可以看到获取到了自增的值,至于为什么这个id是7,原因是因为我之前插入了一条数据,然把她删掉了,然后再插入的时候就是从6开始自增了,这是一个自增的知识点的断点问题。

3.2 删(delete)

SQL语句:

delete from user_info where id=7;

java代码:

@Mapper
public interface UserInfoMapper {
    //删除
    @Delete("delete from user_info where id=#{id}")
    void delete(Integer id);
}

测试代码:


    @Test
    void delete() {
        userInfoMapper.delete(7);
        System.out.println("删除成功");
    }

运行结果:
在这里插入图片描述
打开数据库并且刷新看是否删除成功:
在这里插入图片描述
可以看到成功了。

3.3 改(update)

SQL语句:

update user_info set username="lisi" where id=5;

java代码:

@Mapper
public interface UserInfoMapper {
    //更新
    @Update("update user_info set username=#{username} where id=#{id}")
    void update(Integer id);
}

测试:

   @Test
    void update() {
       UserInfo userInfo=new UserInfo();
       userInfo.setId(5);
       userInfo.setUsername("lisi");
       userInfoMapper.update(userInfo);
        System.out.println("更新成功");
    }

数据更新前:
在这里插入图片描述
启动项目:
运行结果:
在这里插入图片描述
打开数据库并且刷新查询是否更新数据成功:
在这里插入图片描述
可以看到更新成功了。

3.4 查(select)

SQL语句:

select * from user_info;

java代码:

@Mapper
public interface UserInfoMapper {
    //查询
    @Select("SELECT * FROM user_info")
    List<UserInfo> selectAll();
    }

测试:

    @Autowired
private UserInfoMapper userInfoMapper;
    @Test
    void selectAll() {
        System.out.println(userInfoMapper.selectAll());
    }

运行结果:
在这里插入图片描述
可以看到查询成功了。

但是这里会有一个问题:我们先把Mybatis的日志配置取消掉为了便于观察:

启动项目:
在这里插入图片描述
我们可以看到这个这里这个没有获取到数据库表的数据。
这个原因是什么呢?
这是数据库表里的字段名字
在这里插入图片描述
再看java代码当中的字段名字:
在这里插入图片描述
可以看到他们是有区别的。当自动映射查询结果时,MyBatis 会获取结果中返回的列名并在 Java 类中查找相同名字的属性(忽略大小写)。 这意味着如果发现了 ID 列和 id 属性,MyBatis 会将列 ID 的值赋给 id 属性那么怎么解决这个问题呢?

三种方法

1.起别名:

   @Select("select id, username,`password`, age, gender,  phone, " +
            "delete_flag as deleteFlag, create_time as createTime, update_time as updateTime" +
            " from user_info")

2.结果映射:

     @Results(id = "BaseMap", value = {
            @Result(column = "delete_flag", property = "deleteFlag"),
            @Result(column = "create_time", property = "createTime"),
            @Result(column = "update_time", property = "updateTime")
    })

3.驼峰命名(推荐):

mybatis:
  configuration: # 配置打印 MyBatis日志
    map-underscore-to-camel-case: true #配置驼峰⾃动转换
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

4.总结

这篇博客详细介绍了使用MyBatis注解方式实现增删改查操作的全过程,并针对select查询时数据库数据获取不到的问题,提供了三种有效的解决方案:通过取别名、结果映射和设置驼峰大小转换。这些方法能够帮助开发者快速解决数据映射的问题,提高开发效率。下一篇博客中,我们将继续探讨MyBatis的另一配置方式——XML方式,并揭示它在增删改查操作中的独特优势。希望这篇博客能帮助大家更加全面地掌握MyBatis的核心功能,从而在实际项目中游刃有余。