mybatis的TypeHandler類型轉(zhuǎn)換
java有java的數(shù)據(jù)類型鞋诗,數(shù)據(jù)哭有數(shù)據(jù)庫的類型峭跳,當我們把java數(shù)據(jù)插入數(shù)據(jù)庫的時候,需要講java數(shù)據(jù)類型轉(zhuǎn)化為數(shù)據(jù)庫數(shù)據(jù)類型稀颁;當我們從數(shù)據(jù)庫讀取數(shù)據(jù)的時候吹菱,需要把數(shù)據(jù)庫類型轉(zhuǎn)化為java類型來處理。這中間的轉(zhuǎn)化吱韭,mybatis中是通過TypeHandler類型處理器來處理的吆豹。
我們先通過一個例子來了解TypeHandler的實現(xiàn)機制
在這個例子中講java字符數(shù)組String[]轉(zhuǎn)化成數(shù)據(jù)庫varchar類型。如:String[] interests = {"movie", "music"}轉(zhuǎn)為”movie,music"理盆,同時也能實現(xiàn)從varchar轉(zhuǎn)化為String[] 數(shù)組痘煤。
- 自定義類型轉(zhuǎn)化器
@MappedTypes({String[].class})
@MappedJdbcTypes({JdbcType.VARCHAR})
public class StringArrayTypeHandler extends BaseTypeHandler<String[]>{
/**
* 把Java類型參數(shù)轉(zhuǎn)換為對應的數(shù)據(jù)庫類型
* @param ps 當前的PreparedStatement對象
* @param i 當前參數(shù)位置
* @param parameter 當前參數(shù)的Java對象
* @param jdbcType 當前參數(shù)的數(shù)據(jù)庫類型
* @throws SQLException
*/
@Override
public void setNonNullParameter(PreparedStatement ps, int i, String[] parameter, JdbcType jdbcType) throws SQLException {
// 由于BaseTypeHandler中已經(jīng)把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());
}
/**
* 獲取數(shù)據(jù)結果集時把數(shù)據(jù)庫類型轉(zhuǎn)換為對應的Java類型
* @param rs 當前的結果集
* @param columnName 當前的字段名稱
* @return 轉(zhuǎn)換后的Java對象
* @throws SQLException
*/
@Override
public String[] getNullableResult(ResultSet rs, String columnName) throws SQLException {
return this.getStringArray(rs.getString(columnName));
}
/**
* 通過字段位置獲取字段數(shù)據(jù)時把數(shù)據(jù)庫類型轉(zhuǎn)換為對應的Java類型
* @param rs 當前的結果集
* @param columnIndex 當前字段的位置
* @return 轉(zhuǎn)換后的Java對象
* @throws SQLException
*/
@Override
public String[] getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
return this.getStringArray(rs.getString(columnIndex));
}
/**
* 調(diào)用存儲過程后把數(shù)據(jù)庫類型的數(shù)據(jù)轉(zhuǎn)換為對應的Java類型
* @param cs 當前的CallableStatement執(zhí)行后的CallableStatement
* @param columnIndex 當前輸出參數(shù)的位置
* @return
* @throws SQLException
*/
@Override
public String[] getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
return this.getStringArray(cs.getString(columnIndex));
}
/**
* 講”movie,music"轉(zhuǎn)化為數(shù)組對象
* @param columnValue
* @return
*/
private String[] getStringArray(String columnValue) {
if (columnValue == null)
return null;
return columnValue.split(",");
}
}
- 配置文件里配置自定義的TypeHandler
<typeHandlers>
<!--<typeHandler handler="com.yongssu.mybatis.demo1.StringArrayTypeHandler" javaType="[Ljava.lang.String;" jdbcType="VARCHAR"/>-->
<typeHandler handler="com.yongssu.mybatis.demo1.StringArrayTypeHandler"/>
</typeHandlers>
如果在自定義類型轉(zhuǎn)化器時通過注解標注了對應的javaType以及jdbcType衷快,則在配置文件中不需要再次聲明;如果沒有姨俩,則需要在配置文件中說明avaType和jdbcType蘸拔。
- 聲明包含String[]數(shù)組的學生類
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語句
<resultMap id="studentResult" type="Student">
<id column="student_id" property="student_id"/>
<result column="student_name" property="student_name"/>
<result column="student_age" property="student_age"/>
<result column="student_phone" property="student_phone"/>
<result column="interests" property="interests"/>
</resultMap>
<insert id="insertStudent" parameterType="Student" useGeneratedKeys="true" keyColumn="id">
insert into student (student_name,student_age,student_phone,interests) values
(#{student_name},#{student_age},#{student_phone},#{interests,javaType=[Ljava.lang.String;,jdbcType=VARCHAR})
</insert>
<select id="findById" parameterType="int" resultMap="studentResult">
select * from student where student_id = #{id}
</select>
- 測試類
/**
* 方式4
* @throws IOException
*/
public static void test04() throws IOException {
// 讀取配置文件
Reader reader = Resources.getResourceAsReader("config.xml");
// 創(chuàng)建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");
// 執(zhí)行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");
// 創(chuàng)建SqlSeessionFactory工廠
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
Student student = null;
// 執(zhí)行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類型映射實現(xiàn)說明
通過上面的例子师郑,可以發(fā)現(xiàn)要實現(xiàn)自定義TypeHandler,只需要繼承BaseTypeHandler调窍,然后實現(xiàn)相應的轉(zhuǎn)換規(guī)則就可以宝冕。其實除了繼承BaseTypeHadler以外,還可以自己實現(xiàn)TypeHandler邓萨。通過下面代碼地梨,可以發(fā)現(xiàn),BaseHandler也是繼承自TypeHandler先誉,并提供了一些默認的實現(xiàn)湿刽,對null值做了一些處理,這樣我們繼承BaseTypeHandler時就不需要對null值做處理了褐耳。
- TypeHandler接口
public interface TypeHandler<T> {
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類實現(xiàn)
public abstract class BaseTypeHandler<T> extends TypeReference<T> implements TypeHandler<T> {
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已經(jīng)提供了相應的TypeHandler,并且會自動注冊他們渴庆。mybatis提供了以下集中類型轉(zhuǎn)換器铃芦。
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());