MyBatis之枚举类型

枚举可以让代码变得更为优雅,B格更高。

当然MyBatis也是支持枚举类型的啦。

首先,MyBatis内置了Enum的TypeHandler

TypeHandler Java类型 JDBC类型
EnumTypeHandler Enum VARCHAR或任何兼容字符串的类型,
存储的是枚举的名称(而不是索引)
EnumOrdinalTypeHandler Enum 任何兼容NUMERIC或DOUBLE类型
存储的是枚举的索引(而不是名称)

请着重理解 什么叫枚举的索引,什么叫枚举的名称:

//TODO 写一个例子

public enum Color {
	Red(10, "#FF0000"), Green(11, "#00FF00"), BlueGreen(12, "#00FF00");

	private int id;
	private String rgb;

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getRgb() {
		return rgb;
	}

	public void setRgb(String rgb) {
		this.rgb = rgb;
	}

	private Color(int id, String rgb) {
		this.id = id;
		this.rgb = rgb;
	}

	public static void main(String[] args) {
		System.out.println("枚举的名称:[" + Color.Red.name() + "]");
		System.out.println("枚举的索引:[" + Color.Red.ordinal() + "]");
	}
}

#output

枚举的名称:[Red]
枚举的索引:[0]
注意,枚举 Sex中的id和rgb并不是所谓的名称和索引。枚举的名称和索引都是枚举类型本身定义的,开发者并不能对齐进行修改。Enum的源码中也将name和ordinal定义为final类型了。

    /**
     * The name of this enum constant, as declared in the enum declaration.
     * Most programmers should use the {@link #toString} method rather than
     * accessing this field.
     */
    private final String name;

    /**
     * The ordinal of this enumeration constant (its position
     * in the enum declaration, where the initial constant is assigned
     * an ordinal of zero).
     *
     * Most programmers will have no use for this field.  It is designed
     * for use by sophisticated enum-based data structures, such as
     * {@link java.util.EnumSet} and {@link java.util.EnumMap}.
     */
    private final int ordinal;

好了,开始正题。


本文主要测试了以下几点:

1.插入MyBatis枚举类型

2.读取MyBatis枚举类型

3.自定义一个枚举Handler


创建一个表:

CREATE TABLE `t_user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `sex` int(255) DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
)
这张表格有4个字段,显然,Sex,非男即女,可以使用枚举类型,定义一个枚举类型



定义枚举类型:

Sex


准备Mybatis基本使用的一些工具,具体可以看我之前的博客http://blog.csdn.net/tjzhuorui/article/details/66997291

好,现在有了MyBatis可以正常使用了,我可以通过SqlSessionFactoryUtil获取SqlSession了.


创建一个POJO,User

public class User {
	private int id;
	private String name;
	private Sex sex;
	private int age;

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Sex getSex() {
		return sex;
	}

	public void setSex(Sex sex) {
		this.sex = sex;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}
}

创建一个接口UserMapper,定义我们将对数据进行的操作:

public interface UserMapper {
	// 使用MyBatis自带的EnumOrdinalTypeHandler,数据库中对应的枚举字段应该为"数字型"
	int insertByEnumOrdinalTypeHandler(User user);
	User selectByEnumOrdinalTypeHandler(int id);

	// 使用MyBatis自带的insertByEnumTypeHandler,数据库中对应的枚举字段应该为"字符串型",本例中,不使用
	int insertByEnumTypeHandler(User user);
	User selectByEnumTypeHandler(int id);

	// 使用自定义的TypeHandler,来实现
	int insertByCustomerTypeHandler(User user);
	User selectByCustomerTypeHandler(int id);
}
然后,创建user-mapper.xml,并在mybatis-config.xml中关联user-mapper.xml

mybatis-config.xml

	<mappers>
		<mapper resource="com/robin/mapper/config/user-mapper.xml" />
	</mappers>


user-mapper.xml

<mapper namespace="com.robin.mapper.UserMapper">
	<insert id="insertByEnumOrdinalTypeHandler" parameterType="com.robin.pojo.User">
		insert into t_user
		(name,sex,age)values(#{name},#{sex,typeHandler=org.apache.ibatis.type.EnumOrdinalTypeHandler},#{age})
	</insert>
</mapper>
然后测试类:

public class TestEnumOrdinalTypeHandler {

	public static void main(String[] args) {
		SqlSession session = null;
		try {
			session = SqlSessionFactoryUtil.getSqlSession();
			UserMapper mapper = session.getMapper(UserMapper.class);
			User user = new User();
			user.setSex(Sex.Male);
			user.setName("zhangsan");
			user.setAge(22);
			mapper.insertByEnumOrdinalTypeHandler(user);
			session.commit();
		} catch (Exception ex) {
			ex.printStackTrace();
			session.rollback();
		} finally {
			if (session != null)
				session.close();
		}

	}
}

ok,测试成功,能够看到日志输出:

2017-04-07 11:07:09,005 DEBUG [com.robin.mapper.UserMapper.insertByEnumOrdinalTypeHandler]
 ==>  Preparing: insert into t_user (name,sex,age)values(?,?,?)
2017-04-07 11:07:09,059 DEBUG [com.robin.mapper.UserMapper.insertByEnumOrdinalTypeHandler]
 ==> Parameters: zhangsan(String), 0(Integer), 22(Integer)
2017-04-07 11:07:09,061 DEBUG [com.robin.mapper.UserMapper.insertByEnumOrdinalTypeHandler]
 <==    Updates: 1
2017-04-07 11:07:09,062 DEBUG [org.apache.ibatis.transaction.jdbc.JdbcTransaction]
 Committing JDBC Connection [com.mysql.jdbc.JDBC4Connection@5ce81285]

然后看数据库:

数据已经插入了。并且能够看到sex为0,id为11

现在读取id为11的数据。

修改user-map.xml,添加查询部分的配置:

	<resultMap type="com.robin.pojo.User" id="usermap1">
		<result column="id" property="id" />
		<result column="name" property="name" />
		<result column="sex" property="sex"
	typeHandler="org.apache.ibatis.type.EnumOrdinalTypeHandler" />
		<result column="age" property="age" />
	</resultMap>
	<select id="selectByEnumOrdinalTypeHandler" parameterType="int"
		resultMap="usermap1">
		select id,name,sex,age from t_user where id=#{id}
	</select>
再添加,测试查询的部分:

public class TestEnumOrdinalTypeHandler {

	public static void main(String[] args) {
		SqlSession session = null;
		try {
			session = SqlSessionFactoryUtil.getSqlSession();
			UserMapper mapper = session.getMapper(UserMapper.class);
			// testInsert(session, mapper);
			int id = 11;
			testSelectOne(session, mapper, id);

			session.commit();
		} catch (Exception ex) {
			ex.printStackTrace();
			session.rollback();
		} finally {
			if (session != null)
				session.close();
		}
	}

	private static void testSelectOne(SqlSession session, UserMapper mapper,
			int id) {
		User user = mapper.selectByEnumOrdinalTypeHandler(id);
		System.out.println(user);

	}

	private static void testInsert(SqlSession session, UserMapper mapper) {
		User user = new User();
		user.setSex(Sex.Male);
		user.setName("zhangsan");
		user.setAge(22);
		mapper.insertByEnumOrdinalTypeHandler(user);
	}
}
得出结果:User [id=11, name=zhangsan, sex=Male, age=22]。

ok结束,那么现在我有的新的需求:

现在我改变定义了,男人是用10表示,女人是用100表示;并且在查询的时候,如果sex字段是10显示男,如果是100显示女,其他字段,返回null;

回顾一下,Mybatis自带的枚举TypeHandler显然已经无法满足我们的需求了,那么现在我们就需要自定义TypeHandler了。

重新定义一下Sex:

public enum Sex {
	Male(10, "男"), Female(100, "女");

	private int tag;
	private String desc;

	public String getDesc() {
		return desc;
	}

	public int getTag() {
		return tag;
	}

	public void setTag(int tag) {
		this.tag = tag;
	}

	public void setDesc(String desc) {
		this.desc = desc;
	}

	private Sex(int tag, String desc) {
		this.tag = tag;
		this.desc = desc;
	}
}
可以看到的是,添加了一个tag和的desc.

然后,自定义MyEnumSexTypeHandler implements TypeHandler<Sex>

public class MyEnumSexTypeHandler implements TypeHandler<Sex> {

	@Override
	public Sex getResult(ResultSet rs, String columnName) throws SQLException {
		int tag = rs.getInt(columnName);
		for (Sex sex : Sex.values()) {
			if (sex.getTag() == tag)
				return sex;
		}
		return null;
	}

	@Override
	public Sex getResult(ResultSet rs, int columnIndex) throws SQLException {
		int tag = rs.getInt(columnIndex);
		for (Sex sex : Sex.values()) {
			if (sex.getTag() == tag)
				return sex;
		}
		return null;
	}

	@Override
	public Sex getResult(CallableStatement cs, int columnIndex)
			throws SQLException {
		int tag = cs.getInt(columnIndex);
		for (Sex sex : Sex.values()) {
			if (sex.getTag() == tag)
				return sex;
		}
		return null;
	}

	@Override
	public void setParameter(PreparedStatement pstmt, int index, Sex sex,
			JdbcType jdbcType) throws SQLException {
		pstmt.setInt(index, sex.getTag());// 这里,不在是使用Sex的oridinal了
	}

}
然后在mybatis-config.xml中,注册MyEnumSexTypeHandler

    <typeHandlers>
        <typeHandler handler="com.robin.type.custom.MyEnumSexTypeHandler" />
    </typeHandlers>

然后在user-mapper.xml中,配置sql语句

	<insert id="insertByCustomerTypeHandler" parameterType="com.robin.pojo.User">
		insert
		into t_user
		(name,sex,age)values(#{name},#{sex,typeHandler=com.robin.type.custom.MyEnumSexTypeHandler},#{age})
	</insert>

最后,写测试类:

public class TestCustomEnumTypeHandler {
	public static void main(String[] args) {
		SqlSession session = null;
		try {
			session = SqlSessionFactoryUtil.getSqlSession();
			UserMapper mapper = session.getMapper(UserMapper.class);
			testInsert(session, mapper);
			// int id = 11;
			// testSelectOne(session, mapper, id);

			session.commit();
		} catch (Exception ex) {
			ex.printStackTrace();
			session.rollback();
		} finally {
			if (session != null)
				session.close();
		}
	}

	private static void testInsert(SqlSession session, UserMapper mapper) {
		User user = new User();
		user.setName("wang55");
		user.setAge(99);
		user.setSex(Sex.Female);
		mapper.insertByCustomerTypeHandler(user);

	}
}

运行,然后看到数据库中确实插入了:

注意看sex,是不是100呀,ok,这样就满足我们的需求了。

关于查询,与MyBatis自带的EnumOrdinalTypeHandler类似,这里,笔者就不粘贴了。感兴趣可以自己去试试。













發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章