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

目录

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驱动依赖。

java 复制代码
<!--	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)

sql 复制代码
-- 创建数据库
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

java 复制代码
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文件, 配置内容如下:

java 复制代码
# 数据库连接配置
  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)

java 复制代码
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目录下,已经自动帮我们创建好了测试类 ,我们可以

直接使用这个测试类来进行测试。

java 复制代码
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文件当中添加):

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

运行结果:

可以看到打印出来的结果比之前的打印结果更加直观了


3.1 增(insert)

增加之前:

SQL语句:

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

java代码:

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

测试代码:

java 复制代码
   @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的注解。

java 复制代码
@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):

java 复制代码
    @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语句:

sql 复制代码
delete from user_info where id=7;

java代码:

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

测试代码:

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

运行结果:

打开数据库并且刷新看是否删除成功:

可以看到成功了。

3.3 改(update)

SQL语句:

sql 复制代码
update user_info set username="lisi" where id=5;

java代码:

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

测试:

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

数据更新前:

启动项目:

运行结果:

打开数据库并且刷新查询是否更新数据成功:

可以看到更新成功了。

3.4 查(select)

SQL语句:

sql 复制代码
select * from user_info;

java代码:

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

测试:

java 复制代码
    @Autowired
private UserInfoMapper userInfoMapper;
    @Test
    void selectAll() {
        System.out.println(userInfoMapper.selectAll());
    }

运行结果:

可以看到查询成功了。

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

启动项目:

我们可以看到这个这里这个没有获取到数据库表的数据。

这个原因是什么呢?

这是数据库表里的字段名字

再看java代码当中的字段名字:

可以看到他们是有区别的。当自动映射查询结果时,MyBatis 会获取结果中返回的列名并在 Java 类中查找相同名字的属性(忽略大小写)。 这意味着如果发现了 ID 列和 id 属性,MyBatis 会将列 ID 的值赋给 id 属性那么怎么解决这个问题呢?
三种方法

1.起别名:

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

2.结果映射:

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

3.驼峰命名(推荐):

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

4.总结

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

相关推荐
长栎1 小时前
写 for 循环写了十年,你却从没用过迭代器模式最狠的那一面
后端
LiaCode1 小时前
Redis 在生产项目的使用
前端·后端
用户559822481221 小时前
Docker Compose Down 导致容器数据误删——ext4 日志恢复全记录
后端
LiaCode1 小时前
一天学完 redis 的爽翻版核心知识总结
前端·后端
大刚测试开发实战1 小时前
如何内网穿透访问本地私有化部署的TestHub
前端·后端·github
xiaodaoluanzha1 小时前
迄今為止,最簡單的編程語言 Nolang
前端·后端
Csvn1 小时前
Docker 容器管理入门 — 从镜像到容器编排
后端
用户762352425911 小时前
ShardingJDBC
后端
行者全栈架构师1 小时前
IDEA 中 Maven 项目的 15 个红色报错快速解决方法
java·后端
令人头秃的代码0_01 小时前
mac(m5)平台编译openjdk
java