mybatis处理枚举类型

前言:mybatis自带两种对枚举类的处理方式,分别为EnumTypeHandler(默认使用)和EnumOrdinalTypeHandler, 可以使用这两种方式插入枚举对象的name值和序号值.但在实际的开发中我们常常希望存储的是枚举类中自定义的一个属性值(一般是一个int类型的value值),这种情况下我们可以通过以下方式来实现

一: 定义一个通用的泛型枚举接口

package org.power.quickbuy.enums;

public interface IntEnum<E extends Enum<E>> {
	int getIntValue();
}

二:自定义一个Handler类并继承于BaseTypeHandler

package org.power.quickbuy.enums;

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;

public class IntEnumTypeHandler<E extends Enum<E> & IntEnum<E>> extends BaseTypeHandler<IntEnum> {
	private Class<IntEnum> type;

	public IntEnumTypeHandler(Class<IntEnum> type) {
		if (type == null)
			throw new IllegalArgumentException("Type argument cannot be null");
		this.type = type;
	}

	private IntEnum convert(int status) {
		IntEnum[] objs = type.getEnumConstants();
		for (IntEnum em : objs) {
			if (em.getIntValue() == status) {
				return em;
			}
		}
		return null;
	}

	@Override
	public IntEnum getNullableResult(ResultSet rs, String columnName) throws SQLException {
		return convert(rs.getInt(columnName));
	}

	@Override
	public IntEnum getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
		return convert(rs.getInt(columnIndex));
	}

	@Override
	public IntEnum getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
		return convert(cs.getInt(columnIndex));
	}

	@Override
	public void setNonNullParameter(PreparedStatement ps, int i, IntEnum enumObj, JdbcType jdbcType)
			throws SQLException {
		// baseTypeHandler已经帮我们做了parameter的null判断
		ps.setInt(i, enumObj.getIntValue());

	}
}

三:创建自己的枚举类并实现IntEnum接口

package org.power.quickbuy.enums;

public enum EmpStatus implements IntEnum<EmpStatus> {
	ON_LINE("在线", 1), OFF_LINE("下线", 0), AWAY("离开", 5);
	private String tagName;
	private Integer value;

	private EmpStatus(String tagName, Integer value) {
		this.tagName = tagName;
		this.value = value;
	}

	public String getTagName() {
		return tagName;
	}

	public Integer getValue() {
		return value;
	}

	@Override
	public int getIntValue() {
		// 该处返回的值即为我们希望在数据库中存储的值
		return this.value; 
	}

}

四: 在Mapper.xml文件的插入、查询等操作中对指定的枚举类型字段添加typeHandler处理

<?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="org.power.quickbuy.dao.EmpMapper">

	<!--实体映射-->
	<resultMap id="empResultMap" type="org.power.quickbuy.entity.Emp">
		<id property="id" column="id" />
		<result property="name" column="name" />
		<result property="status" column="status" typeHandler="org.power.quickbuy.enums.IntEnumTypeHandler" />
	</resultMap>

	<!-- 查询(根据主键ID查询) -->
	<select id="selectByPrimaryKey" resultMap="empResultMap" parameterType="java.lang.Integer">
		 SELECT
		 	id,
			name,
			status
		 FROM emp
		 WHERE id = #{id}
	</select>

	<!-- 添加 -->
	<insert id="insert" parameterType="emp">
		INSERT IGNORE INTO emp(
			<include refid="Base_Column_List" />
		)VALUES(
			#{id},
			#{name},
			#{status, typeHandler=org.power.quickbuy.enums.IntEnumTypeHandler}
		) 
	</insert>

</mapper>


<think>嗯,我现在要介绍MyBatis如何映射枚举类型。首先,我需要回忆一下MyBatis的基本处理机制。MyBatis处理Java枚举类型时,默认会使用EnumTypeHandler,这个处理器会把枚举实例转换成其名称的字符串形式,也就是调用name()方法得到的值。比如,一个枚举Status有ACTIVE和INACTIVE两个值,存入数据库时会变成"ACTIVE"和"INACTIVE"。但用户可能需要不同的存储方式,比如使用ordinal()的值,或者自定义的某个字段。这时候可能需要换用EnumOrdinalTypeHandler,或者自定义TypeHandler。 接下来,我应该分步骤说明不同的处理方式。首先是默认的EnumTypeHandler,举例子说明存入的是枚举的名称。然后,如果用户想存序号,可以用EnumOrdinalTypeHandler,这时候存入的是0、1这样的数字。但用户可能有更复杂的需求,比如数据库中存的是其他值,比如代码或者描述,这时候就需要自定义TypeHandler了。需要详细说明如何创建自定义的TypeHandler,实现TypeHandler接口或者继承BaseTypeHandler,重写四个方法:setParameter、getResult等。然后,在映射文件中配置这个处理器,或者在MyBatis的配置文件中注册。 另外,可能还要提到在MyBatis配置文件中如何全局配置TypeHandler,或者在resultMap或具体的字段上通过typeHandler属性指定。还需要注意,当使用注解方式时,如何在@Result注解中指定typeHandler。同时,可能会遇到枚举类型和数据库字段类型不匹配的问题,需要确保数据库字段的类型与TypeHandler处理类型一致,比如VARCHAR对应字符串,INT对应序号等。 还需要考虑枚举类型的转换在查询时的处理MyBatis如何从结果集中读取数据并转换成对应的枚举实例。例如,当数据库存的是代码'A',自定义TypeHandler需要根据这个代码找到对应的枚举实例。举一个具体的例子,比如用户状态枚举UserStatus,包含ACTIVE('A')和INACTIVE('I'),数据库中的字段是CHAR(1),这时候自定义TypeHandler需要将'A'映射到ACTIVE,反之亦然。 另外,可能需要注意在MyBatis 3.4.5及以上版本中,对枚举处理的支持是否有变化,或者是否有更简便的方式。例如,是否可以使用@EnumValue注解(如果有的话),或者结合其他框架如MyBatis-Plus的增强功能。 总结步骤应该是:1. 默认处理方式;2. 使用内置的序号处理器;3. 自定义处理器的实现和配置;4. 示例演示;5. 常见问题和注意事项。需要确保结构清晰,逐步引导用户理解如何根据需求选择合适的映射方式,并提供代码示例帮助理解。</think>MyBatis 映射枚举类型的实现方式可分为以下步骤,通过不同处理器满足多样化需求: --- ### 一、默认处理方式:`EnumTypeHandler` MyBatis **默认使用`EnumTypeHandler`处理枚举**,将枚举值转换为`name()`的字符串形式。 **示例**: ```java public enum Status { ACTIVE, INACTIVE } // 数据库字段类型:VARCHAR // Java属性:Status status; // INSERT时,"ACTIVE"或"INACTIVE"被存入数据库 ``` --- ### 二、使用序号处理器:`EnumOrdinalTypeHandler` 若需存储枚举的**序号**(即`ordinal()`值),改用`EnumOrdinalTypeHandler`。 **配置方式**: ```xml <typeHandlers> <typeHandler handler="org.apache.ibatis.type.EnumOrdinalTypeHandler" javaType="com.example.Status"/> </typeHandlers> <!-- 或在字段映射中指定 --> <result column="status" property="status" typeHandler="org.apache.ibatis.type.EnumOrdinalTypeHandler"/> ``` **示例**: ```java // 数据库字段类型:INT // Status.ACTIVE.ordinal() = 0,Status.INACTIVE.ordinal() = 1 ``` --- ### 三、自定义处理器:实现`TypeHandler`接口 当需要**复杂映射**(如存储枚举的某个字段)时,需自定义`TypeHandler`。 #### 步骤 1:定义枚举类 ```java public enum UserStatus { ACTIVE("A"), INACTIVE("I"); private final String code; UserStatus(String code) { this.code = code; } public String getCode() { return code; } // 根据code获取枚举实例 public static UserStatus fromCode(String code) { return Arrays.stream(values()) .filter(e -> e.code.equals(code)) .findFirst() .orElse(null); } } ``` #### 步骤 2:实现自定义TypeHandler ```java public class UserStatusTypeHandler implements TypeHandler<UserStatus> { @Override public void setParameter(PreparedStatement ps, int i, UserStatus parameter, JdbcType jdbcType) throws SQLException { ps.setString(i, parameter.getCode()); // 存储code到数据库 } @Override public UserStatus getResult(ResultSet rs, String columnName) throws SQLException { return UserStatus.fromCode(rs.getString(columnName)); // 从结果集解析 } @Override public UserStatus getResult(ResultSet rs, int columnIndex) throws SQLException { return UserStatus.fromCode(rs.getString(columnIndex)); } @Override public UserStatus getResult(CallableStatement cs, int columnIndex) throws SQLException { return UserStatus.fromCode(cs.getString(columnIndex)); } } ``` #### 步骤 3:注册TypeHandler **方式 1:全局注册(mybatis-config.xml)** ```xml <typeHandlers> <typeHandler handler="com.example.handler.UserStatusTypeHandler" javaType="com.example.enums.UserStatus"/> </typeHandlers> ``` **方式 2:局部指定(Mapper XML)** ```xml <resultMap id="userResultMap" type="User"> <result column="status" property="status" typeHandler="com.example.handler.UserStatusTypeHandler"/> </resultMap> ``` --- ### 四、注解方式配置 在`@Result`注解中直接指定: ```java @Results({ @Result(column = "status", property = "status", typeHandler = UserStatusTypeHandler.class) }) User selectUserById(Integer id); ``` --- ### 五、注意事项 1. **类型一致性**:确保数据库字段类型处理器逻辑匹配(如`VARCHAR`对应字符串,`INT`对应序号)。 2. **性能影响**:频繁的自定义转换可能影响性能,建议在复杂场景下使用。 3. **空值处理**:在`TypeHandler`中需处理`null`值,避免`NullPointerException`。 4. **枚举更新同步**:若枚举定义变更(如修改code),需同步更新数据库历史数据。 --- ### 六、完整示例 **数据库表**: ```sql CREATE TABLE user ( id INT PRIMARY KEY, name VARCHAR(50), status CHAR(1) -- 存储'A'或'I' ); ``` **Java实体类**: ```java public class User { private Integer id; private String name; private UserStatus status; // Getters & Setters } ``` **Mapper XML**: ```xml <insert id="insertUser" parameterType="User"> INSERT INTO user (id, name, status) VALUES (#{id}, #{name}, #{status, typeHandler=com.example.handler.UserStatusTypeHandler}) </insert> <select id="selectUser" resultMap="userResultMap"> SELECT * FROM user WHERE id = #{id} </select> ``` 通过上述方式,MyBatis 可灵活处理枚举类型,适应不同存储需求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值