【MyBatis 深度解析】注解操作与 XML 配置:增删改查全流程实现

文章目录

    • [一、Mybatis 初识](#一、Mybatis 初识)
      • [1.1 Mybatis 定义](#1.1 Mybatis 定义)
      • [1.2 入门案例](#1.2 入门案例)
    • [二、Mybatis 基础操作](#二、Mybatis 基础操作)
      • [2.1 打印日志](#2.1 打印日志)
      • [2.2 参数传递](#2.2 参数传递)
      • [2.3 增(Insert)](#2.3 增(Insert))
      • [2.4 删(Delete)](#2.4 删(Delete))
      • [2.5 改(Update)](#2.5 改(Update))
      • [2.6 查(Select)](#2.6 查(Select))
        • [2.6.1 起别名](#2.6.1 起别名)
        • [2.6.2 结果映射](#2.6.2 结果映射)
        • [2.6.3 开启驼峰命名](#2.6.3 开启驼峰命名)
    • [三、Mybatis XML 配置文件](#三、Mybatis XML 配置文件)
      • [3.1 配置](#3.1 配置)
      • [3.2 入门案例](#3.2 入门案例)
      • [3.1 增(Insert)](#3.1 增(Insert))
      • [3.2 删(Delete)](#3.2 删(Delete))
      • [3.3 改(Update)](#3.3 改(Update))
      • [3.4 查(Select)](#3.4 查(Select))

一、Mybatis 初识

1.1 Mybatis 定义

  • MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。

web应用程序⼀般分为三层,即:Controller、Service、Dao。持久层(Dao)是数据访问层,用来操作数据库。

而 MyBatis 是更简单完成程序和数据库交互的框架,也就是更简单的操作和读取数据库工具。

1.2 入门案例

  1. 数据准备:
sql 复制代码
-- 创建表[用户表]
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' );
  1. 创建对应实体类:
java 复制代码
@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;
}
  1. 配置数据库连接字符串
    Mybatis 中配置连接数据库,需要数据库相关参数配置
    Mysql 驱动类
    登录名
    密码
    数据库连接字符串
yaml 复制代码
spring:
  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
  1. 持久层代码
java 复制代码
@Mapper
public interface UserInfoMapper {
		@Select("select * from user_info")
    List<UserInfo> selectAll();
}

  • 持久层接口的命名规范一般为 XxxMapper
  • @Mapper 注解:用于标识这是 MyBatis 中的 Mapper 接口
  • 程序运行时,框架会自动为该接口生成实现类对象(代理对象),并将其交给 Spring 的 IOC 容器管理
  • @Select 注解:代表一个 select 查询,注解内的内容就是对应方法的具体 SQL 实现

  1. 单元测试
    在创建出来的SpringBoot工程中,在src下的test目录下,已经自动创建好了测试类,可以直接使用这个测试类来进行测试。
java 复制代码
@SpringBootTest
class UserInfoMapperTest {

    @Autowired
    private UserInfoMapper userInfoMapper;

    @Test
    void selectAll() {
        List<UserInfo> userInfos = userInfoMapper.selectAll();
        userInfos.forEach(System.out::println);
    }
}

运行结果如下:

二、Mybatis 基础操作

下面详细讲述MyBatis的增,删,改,查操作。

2.1 打印日志

  • 在 MyBatis 中,我们可以借助日志查看 SQL 语句的执行、执行时传递的参数,以及最终的执行结果
  • 日志功能只需在配置文件中进行配置即可启用
yaml 复制代码
#  配置打印MyBatis⽇志
mybatis:
  configuration: 
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl		

重新运行可以得到如下内容,传递参数和执行结果:

2.2 参数传递

需求:根据id 查询用户,sql select * from user_info where id = ?

  • 问题:如果 SQL 语句中的 id 写为固定数值(如 id=4),则只能查询固定对应的数据,无法满足动态查询的需求。
  • 解决方案:在 selectById 方法中添加参数 (id),将方法的参数传递给 SQL 语句。
  • 具体用法:使用 #{} 的方式获取方法中的参数,从而让 SQL 支持动态数值。

java 复制代码
	@Select("select id,username,`password`,age,gender,phone,delete_flag," +
            "create_time,update_time from user_info where id= #{id}")
    UserInfo selectById(Integer id);

如果mapper接口方法形参只有⼀个普通类型的参数,#{...}里面的属性名可以随便写,如:#{id}、#{value}。建议和参数名保持⼀致。但是参数有多个时,必须和参数名保持一致。

测试用例:

java 复制代码
	@Test
    void selectById() {
        UserInfo userInfo = userInfoMapper.selectById(1);
        System.out.println(userInfo);
    }

结果:

也可以通过 @Param 设置参数的别名,如果使用 @Param 设置别名,#{...} 里面的属性名必须和 @Param 设置的一样,例:

java 复制代码
	@Select("select id,username,`password`,age,gender,phone,delete_flag," +
            "create_time,update_time from user_info where id= #{id}")
    UserInfo selectById(@Param("id") Integer id);

2.3 增(Insert)

java 复制代码
	@Insert("insertinto user_info (username, `password`, age, gender)" +
            "values (#{username},#{password},#{age},#{gender})")
    Integer insertUser(UserInfo userInfo);

可以直接使用UserInfo 对象的属性名来获取参数。也可以写出所有属性来获取参数。

此时返回的是执行的行数。

测试:

java 复制代码
	@Test
    void insertUser() {
        UserInfo userInfo = new UserInfo();
        userInfo.setUsername("java1");
        userInfo.setPassword("java1");
        userInfo.setAge(20);
        userInfo.setGender(1);
        Integer result = userInfoMapper.insertUser(userInfo);
        log.info("影响行数:{}",result);
    }

新增之后可以刷新数据库查看执行结果。

如果设置了 @Param 属性,#{...}需要使用 参数.属性来获取
@Insert("insert INTO user_info (username, password, age, gender) values (#{userInfo.username},#{userInfo.password},#{userInfo.age},#{userInfo.gender})") Integer insertUser2(@Param("userInfo") UserInfo userInfo);

  • 返回主键 @Options
    Insert 语句默认返回的是受影响的行数
    但有些情况下,数据插入之后,还需要有后续的关联操作,需要获取到新插入数据的 id。如果想要拿到 id ,需要在Mapper 接口的方法上添加一个注解 @Options。
java 复制代码
	@Options(useGeneratedKeys = true,keyProperty = "id") // 获得自增ID,通过注解
    @Insert("insertinto user_info (username, `password`, age, gender)" +
            "values (#{username},#{password},#{age},#{gender})")
    Integer insertUser(UserInfo userInfo);
  • useGeneratedKeys:这会令 MyBatis 使用 JDBC 的 getGeneratedKeys 方法来取出由数据库内部生成的主键(比如像 MySQL 和 SQL Server 这样的关系型数据库管理系统的自动递增字段),默认值:false
  • keyProperty:指定能够唯一识别对象的属性,MyBatis 会使用 getGeneratedKeys 的返回值或 insert 语句的 selectKey 子元素设置它的值,默认值:未设置(unset
  • 注意:设置 useGeneratedKeys=true 之后,方法返回值依然是受影响的行数,自增 id 会设置在上述 keyProperty 指定的属性中。

2.4 删(Delete)

Mapper 接口:

java 复制代码
	@Delete("delete from user_info where id = #{id}")
    Integer deleteUserById(Integer id);

测试:

java 复制代码
	@Test
    void deleteUserById() {
        Integer result = userInfoMapper.deleteUserById(11);
    }

2.5 改(Update)

Mapper 接口:

java 复制代码
	@Update("update user_info set gender = #{gender} where id = #{id}")
    void updateUserById(Integer gender,Integer id);

测试:

java 复制代码
	@Test
    void updateUserById() {
        userInfoMapper.updateUserById(0,11);
    }

2.6 查(Select)

在上面查询时发现,有几个字段是没有赋值的,只有 Java 对象属性和数据库字段一模一样时,才会进行赋值。查询结果:

从运行结果上可以看到,我们SQL语句中,查询了delete_flag, create_time, update_time,但是这几个属性却没有赋值。

原因分析:

当自动映射查询结果时,MyBatis会获取结果中返回的列名并在Java类中查找相同名字的属性(忽略大小写)。这意味着如果发现了ID列和id属性,MyBatis会将列ID的值赋给id属性

解决办法:

  1. 起别名
  2. 结果映射
  3. 开启驼峰命名
2.6.1 起别名

在SQL 语句中,给列名起别名,保持别名和实体类属性名一样。

java 复制代码
    @Select("SELECT id,username,`password`,age,gender,phone,delete_flag as deleteFlag, " +
            "create_time as createTime, update_time as updateTime " +
            "from user_info") //起别名
    List<UserInfo> selectAll();
2.6.2 结果映射

使用Spring 提供的注解 @Results :

java 复制代码
    @Results(id = "BaseMap",value = {
            @Result(column = "delete_flag",property = "deleteFlag"),
            @Result(column = "create_time",property = "createTime"),
            @Result(column = "update_time",property = "updateTime"),
    })  //通过注解映射
    @Select("select id,username,`password`,age,gender,phone,delete_flag," +
            "create_time,update_time from user_info")
    List<UserInfo> selectAll();

如果其他SQL 需要复用这个映射关系,可以给这个Results 定义一个名称,如上id = "BaseMap" ,使用 @ResultMap 注解来复用即可,例:

java 复制代码
    @ResultMap("BaseMap")
    @Select("select id,username,`password`,age,gender,phone,delete_flag," +
            "create_time,update_time from user_info where id= #{id}")
    UserInfo selectById(@Param("id") Integer id);
2.6.3 开启驼峰命名

通常数据库列使用蛇形命名法进行命名(下划线分割各个单词),而 Java 属性一般遵循驼峰命名法约定。为了在这两种命名方式之间启用自动映射,需要将 mapUnderscoreToCamelCase 设置为 true

yaml 复制代码
mybatis:
  configuration:
    map-underscore-to-camel-case: true #配置驼峰自动转换

驼峰命名规则:abc_xyz => abcXyz

  • 表中字段名:abc_xyz
  • 类中属性名:abcXyz

Java 代码不做任何处理

通过上面三个方法后,执行查询发现所有字段都可以查询到数据,全部进行正确赋值:


三、Mybatis XML 配置文件

Mybatis 的开发有两种方式:

  1. 注解
  2. XML配置文件

3.1 配置

需要进行数据库连接字符串配置和Mybatis 的 XML 文件配置。

yaml 复制代码
spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/mybatis_test?characterEncoding=utf8&useSSL=false
    username: root
    password: whx041223
    driver-class-name: com.mysql.cj.jdbc.Driver

mybatis:
  mapper-locations: classpath:mapper/**Mapper.xml # 配置 mybatis xml 文件路径;classpath 对应resources
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #  配置打印MyBatis⽇志
    map-underscore-to-camel-case: true #配置驼峰⾃动转换

3.2 入门案例

进行持久层代码编写

  1. 方法定义 Interface,添加Mapper 接口
java 复制代码
@Mapper
public interface UserInfoXmlMapper {
    List<UserInfo> selectAll();
}
  1. 方法实现,添加UserInfoXMLMapper.xml
xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.whx.mybatis.mapper.UserInfoXmlMapper">
    <select id="selectAll" resultType="com.whx.mybatis.entity.UserInfo">
        select id,username,`password`,age,gender,phone,delete_flag,
        create_time,update_time from user_info
    </select>
</mapper>

标签的说明:

  • <mapper> 标签:需要指定 namespace 属性,表示命名空间,值为 mapper 接口的全限定名,包括全包名.类名。
  • <select> 查询标签:是用来执行数据库的查询操作的:
    • id:是和 Interface(接口)中定义的方法名称一样的,表示对接口的具体实现方法。
    • resultType:是返回的数据类型,也就是开头定义的实体类。

3.1 增(Insert)

接口:

java 复制代码
	Integer insertUser(UserInfo userInfo);

方法实现:

xml 复制代码
	<insert id="insertUser" useGeneratedKeys="true" keyProperty="id">
        insert into user_info (username, `password`, age, gender)
        values (#{username},#{password},#{age},#{gender})
    </insert>

返回自增id,接口定义不变,在Mapper.xml 中设置useGeneratedKeys和keyProperty属性。

如果使用 @Param 设置参数名,使用方法和注解类似:

接口:

java 复制代码
	Integer insertUser(@Param("userInfo") UserInfo userInfo);

方法实现:

xml 复制代码
	<insert id="insertUser">
        insert INTO user_info (username, `password`, age, gender)
        values (#{userInfo.username},#{userInfo.password},#{userInfo.age},#{userInfo.gender})
    </insert>

3.2 删(Delete)

接口:

java 复制代码
	Integer deleteUserById(Integer id);

方法实现:

xml 复制代码
	<delete id="deleteUserById">
        delete from user_info where id = #{id}
    </delete>

3.3 改(Update)

接口:

java 复制代码
	void updateUserById(Integer gender,Integer id);

方法实现:

xml 复制代码
	<update id="updateUserById">
        update user_info set gender = #{gender} where id = #{id}
    </update>

3.4 查(Select)

和注解方式一样,使用XML方式查询也存在数据封装的问题。

结果显示:deleteFlag,createTime,updateTime也没有进行赋值。

解决办法和注解一样:

  1. 起别名
  2. 结果映射
  3. 开启驼峰命名

其中1,3的解决办法和注解一样,结果映射在XML中的方法:

xml 复制代码
    <resultMap id="BaseMapXml" type="com.whx.mybatis.entity.UserInfo">
        <id property="id" column="id"></id>
        <result property="deleteFlag" column="delete_flag"></result>
        <result property="createTime" column="create_time"></result>
        <result property="updateTime" column="update_time"></result>
    </resultMap>

	<select id="selectAll" resultMap="BaseMapXml">
        select id,username,`password`,age,gender,phone,delete_flag,
        create_time,update_time from user_info
    </select>

解析:


总结:

本文围绕 MyBatis 轻量级持久层框架展开,总结其核心使用要点。MyBatis 通过注解或 XML 配置简化 JDBC 冗余代码,支持自定义 SQL 与对象映射,兼顾开发效率与灵活性。入门环节涵盖数据库准备、实体类定义、配置编写、Mapper 接口开发及单元测试,可快速搭建运行环境。基础操作中,日志配置能查看 SQL 执行细节,#{}实现单参数、多参数等场景的动态绑定,增删改查操作可通过注解或 XML 配置获取自增主键,查询结果映射提供起别名、resultMap、驼峰命名转换三种方案,解决数据库与 Java 命名适配问题。XML 配置适配复杂 SQL 场景,掌握这些核心点即可应对日常持久层开发。

相关推荐
予枫的编程笔记2 小时前
【JDK版本】JDK版本迁移避坑指南:从8→17/21实操全解析
java·人工智能·jdk
西部风情2 小时前
稳定性质量系列-系统稳定性建设实践
java·开发语言
短剑重铸之日2 小时前
《7天学会Redis》Day 7 - Redisson 全览
java·数据库·redis·后端·缓存·redission
码界奇点2 小时前
基于Spring+SpringMVC+MyBatis+easyUI的后台管理系统设计与实现
java·spring·毕业设计·mybatis·easyui·源代码管理
0和1的舞者2 小时前
《#{} vs ${}:MyBatis 里这俩符号,藏着性能与安全的 “生死局”》
java·数据库·学习·mybatis·intellij idea·mybatis操作
步步为营DotNet2 小时前
深度探究.NET中WeakReference:灵活内存管理的利器
java·jvm·.net
a程序小傲2 小时前
中国邮政Java面试被问:Kafka的Log Compaction实现和删除策略
java·开发语言·后端·python·面试·职场和发展·kafka
hopsky2 小时前
数据服务开源-SqlRest 1.6 idea中启动 (pg版)
java·ide·intellij-idea
indexsunny2 小时前
互联网大厂Java面试实战:音视频场景中的Spring Boot与Kafka技术问答
java·spring boot·redis·面试·kafka·spring security·互联网大厂