Mybatis-实体类属性名与数据库字段名不同的查询方法

查询语句是 MyBatis 中最常用的元素之一,本文涉及mybatis的单表查询操作,关联表有关的查询会后续补充。

  巧妇难为无米之炊,要想从数据库中表中取出数据并转化为javaBean,所以,我们要先准备javabean以及与其对应的数据表。

javaBean:

public class President {

	private int id;
	private String name;
	
	@Override
	public String toString() {
		return "President [id=" + id + ", name=" + name + "]";
	}
       //get set 方法.....
}
创建两个对应的数据库表,并插入两条数据:

create table president1(
    p_id int not null auto_increment primary key,
    p_name varchar(50) not null
);

insert into president1(p_name) values('lily'),('Tom');

create table president2(
    id int not null auto_increment primary key,
    name varchar(50) not null
);
insert into president2(name) values('lily'),('Tom');
创建两个数据库是为了测试两个不同的查询状况,

数据库字段名与实体类属性名相同

从sql表可以看出president2的字段名与javabean:President的属性名完全相同,这种情况下mybatis的select操作非常简单:
	<!-- 从表 president2中查询-->
	<select id="getPreByIdPresident2" parameterType="int" resultType="President">
		select * from president2 where id=#{id}
	</select>
此时mybatis运用反射机制会将查询返回的结果(id,name)封装成President对象。

如果从表president1中查询,同样采用上面的sql语句
	<!-- 从表 president1中查询-->
	<select id="getPreByIdPresident1" parameterType="int" resultType="President">
		<span style="white-space:pre">		</span>President p1 = session.selectOne(statement+"getPreByIdPresident1", 1);
<span style="white-space:pre">		</span>System.out.println("表president1中查询"+p1);
	</select>
此时如果用getPreByIdPresident1进行查询,返回的结果会是null,我们将上面的sql语句在mysql中执行下:

有结果返回,但是返回的字段名为(p_id,p_name)这种结果mybatis在解析时无法与President类对应。多数情况下实体类属性名与数据库表的字段名都会有差异,这种情况如果mybatis不能处理也就太low了。

数据库字段名与实体类属性名不相同

mybatis针对该种情况有两种解决方法,但是归根到底都是同一种实现。

Method1:定义一个ResultMap将数据库字段名与实体类属性名做个映射

我们欲从表president1中查询数据,此时的mapper配置如下:
	<resultMap type="President" id="getFromPresident2">
		<!-- 主键必须用id标签映射,其他的用非集合用result映射 集合类用collection映射 -->
		<!-- column为数据库字段名,property为实体类属性名 -->
		<id column="p_id" property="id" />
		<result column="p_name" property="name" />
	</resultMap>
	<select id="getPreByIdPresident1Method1" resultMap="getFromPresident2">
		select * from president1 where p_id=#{id}
	</select>
首先定义了一个resultMap,将数据库表的字段名与实体类属性名做了一一对应,其中type为实体类(此处运用的类别名),id为了在select标签中引用映射结果。
在select标签中并没有用resultType属性,而使用了resultMap,即为上面定义的resultMap,mybatis会根据resultMap中的映射关系去构造President

Method1:直接在sql语句中使用别名

	<!-- 从表 president1中查询 -->
	<select id="getPreByIdPresident1Method2" resultType="President">
		select p_id id,p_name name from president1 where p_id=#{id}
	</select>
这种方法会查到实际的数据,这种方法与字段名和属性名相同都是基于相同的原理: MyBatis 会在幕后自动创建一个 ResultMap,基于属性名来映射列到JavaBean 的属性上。即mybatis底层都是通过创建ResultMap来进行关系的映射,与method1原理相同。。

上面用到的测试用例的源码地址: 用例源码

### MyBatis-Plus 中实体类数据库字段映射关系的获取方式 在 MyBatis-Plus 中,为了实现实体类数据库表之间字段的正确映射,通常会使用注解的方式来指定映射规则。这些规则不仅用于定义表名、主键和字段的关系,还可以帮助开发者动态获取这些映射信息。 #### 1. 使用 `TableInfoHelper` 动态获取表信息 MyBatis-Plus 提供了一个工具类 `TableInfoHelper`,它可以从实体类中提取出其关联的表信息,包括表名、字段列表及其对应关系等。 ```java import com.baomidou.mybatisplus.core.metadata.TableInfo; import com.baomidou.mybatisplus.core.metadata.TableInfoHelper; public TableInfo getTableInfo(Class<?> clazz) { return TableInfoHelper.getTableInfo(clazz); // 获取实体类对应的表信息[^1] } // 示例:假设有一个 User 类作为实体类 TableInfo tableInfo = getTableInfo(User.class); System.out.println("表名:" + tableInfo.getName()); // 输出表名 tableInfo.getFieldList().forEach(field -> { System.out.println("字段名:" + field.getColumn() + ", 属性名:" + field.getProperty()); }); ``` 这段代码展示了如何通过反射机制读取实体类上的注解信息,并将其转化为可操作的对象集合。 --- #### 2. 手动设置字段映射关系 当遇到实体类属性名数据库字段名不完全匹配的情况时,可以借助 `@TableField` 注解手动指定映射关系。 ```java @Data public class User { @TableId(type = IdType.AUTO) // 映射为主键并设置自增策略 private Long userId; @TableField("user_name") // 将 user_name 字段映射到 userName 属性 private String userName; @TableField("create_time") // 将 create_time 字段映射到 createTime 属性 private Date createTime; @TableField(exist = false) // 标记该字段不存在于数据库中 private transient Integer age; } ``` 以上例子说明了即使实体类中的某些字段未存在于数据库表中,也可以通过特定标志位忽略它们的影响,从而避免运行期错误的发生[^3]。 --- #### 3. 自动生成映射文档 对于大规模项目而言,维护大量的实体类及其对应的数据库表可能会变得复杂繁琐。此时可以通过插件或脚本来自动生成一份详细的映射报告。例如,在 Spring Boot 应用程序启动阶段加入如下逻辑即可打印所有已注册的实体类映射详情: ```java import org.springframework.beans.factory.InitializingBean; import org.springframework.stereotype.Component; @Component public class EntityMappingPrinter implements InitializingBean { @Override public void afterPropertiesSet() throws Exception { Arrays.stream(MyApplicationConfig.MAPPER_SCAN_PACKAGES.split(",")) .map(pkg -> ReflectionUtils.getClassesInPackage(pkg)) .flatMap(Collection::stream) .filter(cls -> cls.isAnnotationPresent(Table.class)) .forEach(this::printEntityMapping); } private void printEntityMapping(Class<?> entityClass) { TableInfo tableInfo = TableInfoHelper.getTableInfo(entityClass); if (tableInfo != null) { System.out.printf("[INFO] %s => %s%n", entityClass.getSimpleName(), tableInfo.getName()); tableInfo.getFieldList().forEach(f -> System.out.printf("\t%s (%s)%n", f.getProperty(), f.getColumn()) ); } } } ``` 此组件会在应用初始化完成后遍历指定包路径下的所有 Mapper 文件,并输出每种类型的映射概况至控制台日志文件当中去[^2]。 --- ### 总结 综上所述,无论是静态还是动态条件下,都可以采用多种手段来管理和调试 MyBatis-Plus 下面的实体类数据库表格间存在的各种潜在差异之处;既可以直接查阅源码里的注释声明部分了解基本情况,也能依靠框架自带辅助函数深入挖掘更多细节内容。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值