【MyBatis】@Results注解的使用

@Results 注解详解

在 MyBatis 中,@Results 注解用于将数据库的字段和 Java 实体类的属性进行映射,特别是在 字段名与属性名不一致 的情况下。

MyBatis 默认会使用 自动映射,但如果数据库字段使用 snake_case(下划线命名法),而 Java 类使用 camelCase(驼峰命名法),就可能需要手动指定映射关系。这时可以使用 @Results 注解。(或者也可以在配置文件中设置<setting name="mapUnderscoreToCamelCase" value="true"/>

1. @Results 的基本用法

示例:基本映射

假设 t_user 表的字段如下:

iduser_nameuser_email
1Alicealice@example.com
2Bobbob@example.com

对应的 User 实体类:

public class User {
    private Integer id;
    private String userName;  // 和数据库的 user_name 字段不匹配
    private String email;     // 和数据库的 user_email 不匹配

    // getter & setter 略
}

UserMapper 接口:

import org.apache.ibatis.annotations.*;

import java.util.List;

public interface UserMapper {

    @Select("SELECT id, user_name, user_email FROM t_user")
    @Results({
        @Result(property = "userName", column = "user_name"),
        @Result(property = "email", column = "user_email")
    })
    List<User> selectUsers();
}

解释

  • @Results({ ... }):定义字段与属性的映射
    • @Result(property = "userName", column = "user_name"):将数据库的 user_name 字段映射到 userName 属性
    • @Result(property = "email", column = "user_email"):将数据库的 user_email 字段映射到 email 属性

这样,查询结果中的 user_nameuser_email 就能正确映射到 User 类的 userNameemail 变量。

2. @Result 的常用参数

@Result(
    property = "实体类属性名",  // Java 实体类中的属性
    column = "数据库字段名",   // 数据库表的字段名
    id = true/false,         // 是否为主键
    javaType = Java类型.class,  // 指定 Java 类型
    jdbcType = JdbcType.VARCHAR, // 指定 JDBC 类型
    typeHandler = 自定义TypeHandler.class, // 自定义类型转换器
    one = @One(select = "方法路径"), // 一对一映射,和 <association> 类似
    many = @Many(select = "方法路径")  // 一对多映射,和 <collection> 类似
)

3. id = true(标识主键)

如果某个字段是 主键,需要使用 id = true 来标识:

@Results({
    @Result(property = "id", column = "id", id = true),
    @Result(property = "userName", column = "user_name"),
    @Result(property = "email", column = "user_email")
})

4. @Result 指定 javaTypejdbcType

如果数据库的字段类型和 Java 类型不匹配,可以在@Result 注解中显式指定 javaTypejdbcType

例子:

假设我们有一个数据库表 tab_user,其字段类型与 Java 类型不完全匹配,且需要明确指定转换规则。比如,tab_user 表中的 birth_date 字段是 VARCHAR 类(存储日期字符串),但想将其映射为 Date 类。

数据库表 tab_user

idusernameagebirth_date
1Alice251996-05-15
2Bob301991-08-22

注意:MyBatis 会使用内置的类型处理器,自动将符合yyyy-MM-dd格式的 VARCHAR 日期字符串转换为 Date 类型,所以这里我们不用自己写,只需指定 javaType 和 jdbcType。

对应的 Java 实体类 User

import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;

@Data
@NoArgsConstructor
public class User {
    private Integer id;
    private String username;
    private Integer age;
    private Date birthDate;        // 对应 VARCHAR 类型(日期字符串)
}

UserMapper 接口:

package org.example.mb_study.mapper;

import org.apache.ibatis.annotations.*;
import org.apache.ibatis.type.JdbcType;
import org.example.mb_study.entity.User;

import java.util.Date;
import java.util.List;

public interface UserMapper {

    @Select("SELECT id, username, age, birth_date FROM tab_user")
    @Results({
            @Result(property = "birthDate", column = "birth_date", javaType = Date.class, jdbcType = JdbcType.VARCHAR)
    })
    List<User> selectUsers();
}

解释

  • @Result(property = "birthDate", column = "birth_date", javaType = Date.class, jdbcType = JdbcType.VARCHAR)
    • 数据库中的 birth_date 字段类型是 VARCHAR(字符串),但是我们希望将它映射为 Java 中的 Date 类型。为了确保正确转换,我们需要指定 javaTypeDate.classjdbcTypeJdbcType.VARCHAR

为什么需要显式指定 javaTypejdbcType

  1. jdbcType:当数据库中字段的类型和 Java 类型不一致时,比如,数据库中的日期字段可能是 VARCHAR 类型存储日期字符串,而不是 DATETIMESTAMP,此时需要显式指定 jdbcType = JdbcType.VARCHAR,以避免自动映射时产生错误。
  2. javaType:在一些情况下,MyBatis 会尝试自动推断 Java 类型,但有时这种推断并不准确,尤其是当数据库列的类型无法直接映射到 Java 类型时。显式指定 javaType 可以确保正确转换数据类型。

5. @Result + @One(一对一映射)

如果一个 User 关联了 Address,可以用 @One 进行查询:

表结构

idusernameaddress_id
1Alice101
2Bob102
idstreet
101123 Main St
102456 Oak Ave

实体类

public class Address {
    private Integer id;
    private String street;
    // getter & setter
}

public class User {
    private Integer id;
    private String userName;
    private Address address;  // 一对一映射
    // getter & setter
}

查询 User 时,自动查询 Address

@Select("SELECT id, username, address_id FROM t_user")
@Results({
    @Result(property = "address", column = "address_id",
            one = @One(select = "org.example.mapper.AddressMapper.selectById"))
})
List<User> selectUsers(); 
  • @One(select = "org.example.mapper.AddressMapper.selectById")
    • address_id 通过 AddressMapper.selectById 方法查找 Address 信息
    • 相当于 select * from t_address where id = #{address_id}

6. @Result + @Many(一对多映射)

如果 User 关联多个 Order,可以用 @Many 进行查询:

表结构

user_idorder_idorder_name
11001Phone
11002Laptop
21003Keyboard

实体类

public class Order {
    private Integer id;
    private String orderName;
}

public class User {
    private Integer id;
    private String userName;
    private List<Order> orders;  // 一对多映射:一个用户对应多个订单
}

查询 User 时,自动查询 Order

@Select("SELECT id, username FROM t_user")
@Results({
    @Result(property = "id", column = "id"),
    @Result(property = "userName", column = "username"),
    @Result(property = "orders", column = "id",
            many = @Many(select = "org.example.mapper.OrderMapper.selectByUserId"))
})
List<User> selectUsers();
  • @Many(select = "org.example.mapper.OrderMapper.selectByUserId")
    • orders 通过 OrderMapper.selectByUserId 查找订单列表
    • 相当于 select * from t_order where user_id = #{id}

总结

功能关键用法
字段映射@Result(property, column)
标识主键id = true
指定 Java 类型javaType = Integer.class
指定 JDBC 类型jdbcType = JdbcType.INTEGER
一对一查询one = @One(select = "...")
一对多查询many = @Many(select = "...")

@Results字段名与属性名不一致查询需要复杂映射 时非常有用。如果查询结构复杂,建议使用 resultMap 进行映射。

相关链接:

@Many
@One
@Results与<resultMap>的比较

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值