mybatis的TypeHandler类型转换
java有java的数据类型,数据哭有数据库的类型,当我们把java数据插入数据库的时候,需要讲java数据类型转化为数据库数据类型;当我们从数据库读取数据的时候,需要把数据库类型转化为java类型来处理。这中间的转化,mybatis中是通过TypeHandler类型处理器来处理的。
我们先通过一个例子来了解TypeHandler的实现机制
在这个例子中讲java字符数组String[]转化成数据库varchar类型。如:String[] interests = {"movie", "music"}转为”movie,music",同时也能实现从varchar转化为String[] 数组。
- 自定义类型转化器
@MappedTypes({String[].class})
@MappedJdbcTypes({JdbcType.VARCHAR})
public class StringArrayTypeHandler extends BaseTypeHandler{
/**
* 把Java类型参数转换为对应的数据库类型
* @param ps 当前的PreparedStatement对象
* @param i 当前参数位置
* @param parameter 当前参数的Java对象
* @param jdbcType 当前参数的数据库类型
* @throws SQLException
*/
@Override
public void setNonNullParameter(PreparedStatement ps, int i, String[] parameter, JdbcType jdbcType) throws SQLException {
// 由于BaseTypeHandler中已经把parameter为null的情况做了处理,所以这里我们就不用在判断parameter是否为空,直接用就可以了
StringBuffer result = new StringBuffer();
for (String value : parameter) {
result.append(value).append(",");
}
result.deleteCharAt(result.length() - 1);
ps.setString(i, result.toString());
}
/**
* 获取数据结果集时把数据库类型转换为对应的Java类型
* @param rs 当前的结果集
* @param columnName 当前的字段名称
* @return 转换后的Java对象
* @throws SQLException
*/
@Override
public String[] getNullableResult(ResultSet rs, String columnName) throws SQLException {
return this.getStringArray(rs.getString(columnName));
}
/**
* 通过字段位置获取字段数据时把数据库类型转换为对应的Java类型
* @param rs 当前的结果集
* @param columnIndex 当前字段的位置
* @return 转换后的Java对象
* @throws SQLException
*/
@Override
public String[] getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
return this.getStringArray(rs.getString(columnIndex));
}
/**
* 调用存储过程后把数据库类型的数据转换为对应的Java类型
* @param cs 当前的CallableStatement执行后的CallableStatement
* @param columnIndex 当前输出参数的位置
* @return
* @throws SQLException
*/
@Override
public String[] getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
return this.getStringArray(cs.getString(columnIndex));
}
/**
* 讲”movie,music"转化为数组对象
* @param columnValue
* @return
*/
private String[] getStringArray(String columnValue) {
if (columnValue == null)
return null;
return columnValue.split(",");
}
}
- 配置文件里配置自定义的TypeHandler
如果在自定义类型转化器时通过注解标注了对应的javaType以及jdbcType,则在配置文件中不需要再次声明;如果没有,则需要在配置文件中说明avaType和jdbcType。
- 声明包含String[]数组的学生类
public class Student {
private int student_id;
private String student_name;
private int student_age;
private String student_phone;
private String[] interests;
public Student() {
super();
}
public int getStudent_id() {
return student_id;
}
public void setStudent_id(int student_id) {
this.student_id = student_id;
}
public String getStudent_name() {
return student_name;
}
public void setStudent_name(String student_name) {
this.student_name = student_name;
}
public int getStudent_age() {
return student_age;
}
public void setStudent_age(int student_age) {
this.student_age = student_age;
}
public String getStudent_phone() {
return student_phone;
}
public void setStudent_phone(String student_phone) {
this.student_phone = student_phone;
}
public String[] getInterests() {
return interests;
}
public void setInterests(String[] interests) {
this.interests = interests;
}
@Override
public String toString() {
return "Student{" +
"student_id=" + student_id +
", student_name='" + student_name + '\'' +
", student_age=" + student_age +
", student_phone='" + student_phone + '\'' +
", interests=" + Arrays.toString(interests) +
'}';
}
}
- 在stutent.xml中增加sql语句
insert into student (student_name,student_age,student_phone,interests) values
(#{student_name},#{student_age},#{student_phone},#{interests,javaType=[Ljava.lang.String;,jdbcType=VARCHAR})
- 测试类
/**
* 方式4
* @throws IOException
*/
public static void test04() throws IOException {
// 读取配置文件
Reader reader = Resources.getResourceAsReader("config.xml");
// 创建SqlSeessionFactory工厂
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
Student student = new Student();
String[] interests = {"movie", "music"};
student.setInterests(interests);
student.setStudent_age(12);
student.setStudent_name("yongsheng.su");
student.setStudent_phone("123456");
// 执行sql
SqlSession session = sqlSessionFactory.openSession();
try {
StudentMapper mapper = session.getMapper(StudentMapper.class);
int result = mapper.insertStudent(student);
System.out.println(result);
session.commit();
} finally {
session.close();
}
}
public static void test05() throws IOException {
// 读取配置文件
Reader reader = Resources.getResourceAsReader("config.xml");
// 创建SqlSeessionFactory工厂
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
Student student = null;
// 执行sql
SqlSession session = sqlSessionFactory.openSession();
try {
StudentMapper mapper = session.getMapper(StudentMapper.class);
student = mapper.selectStudent(7);
System.out.println(student);
session.commit();
} finally {
session.close();
}
System.out.println(student);
}
mybatis类型映射实现说明
通过上面的例子,可以发现要实现自定义TypeHandler,只需要继承BaseTypeHandler,然后实现相应的转换规则就可以。其实除了继承BaseTypeHadler以外,还可以自己实现TypeHandler。通过下面代码,可以发现,BaseHandler也是继承自TypeHandler,并提供了一些默认的实现,对null值做了一些处理,这样我们继承BaseTypeHandler时就不需要对null值做处理了。
- TypeHandler接口
public interface TypeHandler {
void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException;
T getResult(ResultSet rs, String columnName) throws SQLException;
T getResult(ResultSet rs, int columnIndex) throws SQLException;
T getResult(CallableStatement cs, int columnIndex) throws SQLException;
}
- BaseTypeHandler类实现
public abstract class BaseTypeHandler extends TypeReference implements TypeHandler {
protected Configuration configuration;
public void setConfiguration(Configuration c) {
this.configuration = c;
}
@Override
public void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException {
if (parameter == null) {
if (jdbcType == null) {
throw new TypeException("JDBC requires that the JdbcType must be specified for all nullable parameters.");
}
try {
ps.setNull(i, jdbcType.TYPE_CODE);
} catch (SQLException e) {
throw new TypeException("Error setting null for parameter #" + i + " with JdbcType " + jdbcType + " . " +
"Try setting a different JdbcType for this parameter or a different jdbcTypeForNull configuration property. " +
"Cause: " + e, e);
}
} else {
try {
setNonNullParameter(ps, i, parameter, jdbcType);
} catch (Exception e) {
throw new TypeException("Error setting non null for parameter #" + i + " with JdbcType " + jdbcType + " . " +
"Try setting a different JdbcType for this parameter or a different configuration property. " +
"Cause: " + e, e);
}
}
}
@Override
public T getResult(ResultSet rs, String columnName) throws SQLException {
T result;
try {
result = getNullableResult(rs, columnName);
} catch (Exception e) {
throw new ResultMapException("Error attempting to get column '" + columnName + "' from result set. Cause: " + e, e);
}
if (rs.wasNull()) {
return null;
} else {
return result;
}
}
@Override
public T getResult(ResultSet rs, int columnIndex) throws SQLException {
T result;
try {
result = getNullableResult(rs, columnIndex);
} catch (Exception e) {
throw new ResultMapException("Error attempting to get column #" + columnIndex+ " from result set. Cause: " + e, e);
}
if (rs.wasNull()) {
return null;
} else {
return result;
}
}
@Override
public T getResult(CallableStatement cs, int columnIndex) throws SQLException {
T result;
try {
result = getNullableResult(cs, columnIndex);
} catch (Exception e) {
throw new ResultMapException("Error attempting to get column #" + columnIndex+ " from callable statement. Cause: " + e, e);
}
if (cs.wasNull()) {
return null;
} else {
return result;
}
}
public abstract void setNonNullParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException;
public abstract T getNullableResult(ResultSet rs, String columnName) throws SQLException;
public abstract T getNullableResult(ResultSet rs, int columnIndex) throws SQLException;
public abstract T getNullableResult(CallableStatement cs, int columnIndex) throws SQLException;
}
mybatis提供的默认类型
对于一些常用的java类型,mybatis已经提供了相应的TypeHandler,并且会自动注册他们。mybatis提供了以下集中类型转换器。
register(Boolean.class, new BooleanTypeHandler());
register(boolean.class, new BooleanTypeHandler());
register(JdbcType.BOOLEAN, new BooleanTypeHandler());
register(JdbcType.BIT, new BooleanTypeHandler());
register(Byte.class, new ByteTypeHandler());
register(byte.class, new ByteTypeHandler());
register(JdbcType.TINYINT, new ByteTypeHandler());
register(Short.class, new ShortTypeHandler());
register(short.class, new ShortTypeHandler());
register(JdbcType.SMALLINT, new ShortTypeHandler());
register(Integer.class, new IntegerTypeHandler());
register(int.class, new IntegerTypeHandler());
register(JdbcType.INTEGER, new IntegerTypeHandler());
register(Long.class, new LongTypeHandler());
register(long.class, new LongTypeHandler());
register(Float.class, new FloatTypeHandler());
register(float.class, new FloatTypeHandler());
register(JdbcType.FLOAT, new FloatTypeHandler());
register(Double.class, new DoubleTypeHandler());
register(double.class, new DoubleTypeHandler());
register(JdbcType.DOUBLE, new DoubleTypeHandler());
register(Reader.class, new ClobReaderTypeHandler());
register(String.class, new StringTypeHandler());
register(String.class, JdbcType.CHAR, new StringTypeHandler());
register(String.class, JdbcType.CLOB, new ClobTypeHandler());
register(String.class, JdbcType.VARCHAR, new StringTypeHandler());
register(String.class, JdbcType.LONGVARCHAR, new ClobTypeHandler());
register(String.class, JdbcType.NVARCHAR, new NStringTypeHandler());
register(String.class, JdbcType.NCHAR, new NStringTypeHandler());
register(String.class, JdbcType.NCLOB, new NClobTypeHandler());
register(JdbcType.CHAR, new StringTypeHandler());
register(JdbcType.VARCHAR, new StringTypeHandler());
register(JdbcType.CLOB, new ClobTypeHandler());
register(JdbcType.LONGVARCHAR, new ClobTypeHandler());
register(JdbcType.NVARCHAR, new NStringTypeHandler());
register(JdbcType.NCHAR, new NStringTypeHandler());
register(JdbcType.NCLOB, new NClobTypeHandler());
register(Object.class, JdbcType.ARRAY, new ArrayTypeHandler());
register(JdbcType.ARRAY, new ArrayTypeHandler());
register(BigInteger.class, new BigIntegerTypeHandler());
register(JdbcType.BIGINT, new LongTypeHandler());
register(BigDecimal.class, new BigDecimalTypeHandler());
register(JdbcType.REAL, new BigDecimalTypeHandler());
register(JdbcType.DECIMAL, new BigDecimalTypeHandler());
register(JdbcType.NUMERIC, new BigDecimalTypeHandler());
register(InputStream.class, new BlobInputStreamTypeHandler());
register(Byte[].class, new ByteObjectArrayTypeHandler());
register(Byte[].class, JdbcType.BLOB, new BlobByteObjectArrayTypeHandler());
register(Byte[].class, JdbcType.LONGVARBINARY, new BlobByteObjectArrayTypeHandler());
register(byte[].class, new ByteArrayTypeHandler());
register(byte[].class, JdbcType.BLOB, new BlobTypeHandler());
register(byte[].class, JdbcType.LONGVARBINARY, new BlobTypeHandler());
register(JdbcType.LONGVARBINARY, new BlobTypeHandler());
register(JdbcType.BLOB, new BlobTypeHandler());
register(Object.class, UNKNOWN_TYPE_HANDLER);
register(Object.class, JdbcType.OTHER, UNKNOWN_TYPE_HANDLER);
register(JdbcType.OTHER, UNKNOWN_TYPE_HANDLER);
register(Date.class, new DateTypeHandler());
register(Date.class, JdbcType.DATE, new DateOnlyTypeHandler());
register(Date.class, JdbcType.TIME, new TimeOnlyTypeHandler());
register(JdbcType.TIMESTAMP, new DateTypeHandler());
register(JdbcType.DATE, new DateOnlyTypeHandler());
register(JdbcType.TIME, new TimeOnlyTypeHandler());
register(java.sql.Date.class, new SqlDateTypeHandler());
register(java.sql.Time.class, new SqlTimeTypeHandler());
register(java.sql.Timestamp.class, new SqlTimestampTypeHandler());
参考文章:http://4443915.blog.51cto.com/4433915/1828533