R.V*_*.V. 16 java mysql enums mybatis
我知道之前已经问过这个问题,但是根据我到目前为止找到的信息,我无法实现解决方案.所以也许有人可以向我解释.
我有一张桌子"状态".它有两列:id和name.id是PK.
我想使用枚举,而不是使用POJO状态.我创建了如下枚举:
public enum Status {
NEW(1), READY(2), CLOSED(3);
private int id;
public void setId(int id) {
this.id = id;
}
public int getId() {
return this.id;
}
Status(int id) {
this.id = id;
}
}
Run Code Online (Sandbox Code Playgroud)
这是我的映射器
<select id="getStatusByName" resultType="Status" parameterType="String">
SELECT ls.id, ls.name
FROM status AS ls
WHERE ls.name = #{name}
</select>
Run Code Online (Sandbox Code Playgroud)
但出于某种原因,当我尝试检索枚举时,某些东西会中断,但不会抛出任何异常.
quu*_*x00 18
我从几个角度研究了这个问题,这是我的发现.警告:我使用MyBatis-3.1.1进行了所有这些调查,因此在早期版本中可能会有不同的表现.
首先,MyBatis有一个内置的EnumTypeHandler.默认情况下,只要将Java枚举指定为resultType或parameterType,就会处理该类型.对于查询,当尝试将数据库记录转换为Java枚举时,EnumTypeHandler只接受一个参数并尝试查找与该值对应的Java枚举值.
一个例子将更好地说明.假设您的上述查询返回,2并且"Ready"当我传入"Ready"作为参数时.在那种情况下,我收到错误消息No enum constant com.foo.Status.2.如果我颠倒SELECT语句的顺序
SELECT ls.name, ls.id
Run Code Online (Sandbox Code Playgroud)
那么错误信息是No enum constant com.foo.Status.Ready.我假设您可以推断出MyBatis在做什么.请注意,EnumTypeHandler忽略从查询返回的第二个值.
将查询更改为
SELECT UPPER(ls.name)
Run Code Online (Sandbox Code Playgroud)
使它工作:返回Status.READY枚举.
接下来我尝试为Status枚举定义自己的TypeHandler.不幸的是,与默认值一样EnumTypeHandler,我只能获得其中一个值(id或name)以引用正确的Enum,而不是两者.因此,如果数据库ID与您上面硬编码的值不匹配,那么您将不匹配.如果确保数据库ID始终与您在枚举中指定的id匹配,那么数据库中所需的只是名称(转换为大写).
然后我想我会聪明并实现一个MyBatis ObjectFactory,同时获取int id和String名称并确保它们在我传回的Java枚举中匹配,但是这不起作用,因为MyBatis没有调用ObjectFactory Java枚举类型(至少我无法使其工作).
所以我的结论是只要你只需要将数据库中的名称与枚举常量名称匹配,MyBatis中的Java枚举就很容易 - 要么使用内置的EnumTypeHandler,要么在定义UPPER(name)时定义自己的名称. SQL不足以匹配Java枚举名称.在许多情况下,这就足够了,因为枚举值可能只是列上的检查约束,并且它只有单个值,而不是id.如果还需要匹配int id和名称,则在设置Java enum和/或数据库条目时手动匹配ID.
最后,如果您想看到一个有效的例子,请参阅我的MyBatis公案中的koan 23:https://github.com/midpeter444/mybatis-koans.如果您只想查看我的解决方案,请查看completed-koans/koan23目录.我还有一个例子,通过Java枚举将记录插入数据库.
您可以使用Custom TypeHandler将结果直接转换为ENUM,这样您就不需要将数据库中的所有值都设置为UPPER CASE ENUM Names.
这就是Status Enum Custom Handler的样子
public class StatusTypeHandler implements TypeHandler<Status> {
public Status getResult(ResultSet rs, String param) throws SQLException {
return Status.getEnum(rs.getInt(param));
}
public Status getResult(CallableStatement cs, int col) throws SQLException {
return Status.getEnum(cs.getInt(col));
}
public void setParameter(PreparedStatement ps, int paramInt, Status paramType, JdbcType jdbctype)
throws SQLException {
ps.setInt(paramInt, paramType.getId());
}
}
Run Code Online (Sandbox Code Playgroud)
通过添加此代码,定义您的TypeHandler以在mybatis-config.xml中默认处理Status.
<typeHandlers>
<typeHandler javaType='Status' handler='StatusTypeHandler' />
</typeHandlers>
Run Code Online (Sandbox Code Playgroud)
现在让我们考虑一个例子,你在Dao中有以下两个函数,
Status getStatusById(int code);
Status getStatusByName(String name);
Run Code Online (Sandbox Code Playgroud)
你的映射器看起来像
<select id="getStatusById" resultType="Status" parameterType="int">
SELECT ls.id
FROM status AS ls
WHERE ls.id = #{id}
</select>
<select id="getStatusByName" resultType="Status" parameterType="String">
SELECT ls.id
FROM status AS ls
WHERE ls.name = #{name}
</select>
Run Code Online (Sandbox Code Playgroud)
现在,因为mapper的resultType是Status,myBatis将使用CustomTypeHandler作为此类型,即StatusTypeHandler而不是默认情况下用于处理枚举的EnumTypeHandler,因此不需要在数据库中维护正确的Enum名称.