MyBatis中自定義typeHandler
Mybatis中的TypeHandler是什麼?
無論是 MyBatis 在預處理語句(PreparedStatement)中設定一個引數時,還是從結果集中取出一個值時,都會用型別處理器將獲取的值以合適的方式轉換成 Java 型別。Mybatis預設為我們實現了許多TypeHandler, 當我們沒有配置指定TypeHandler時,Mybatis會根據引數或者返回結果的不同,預設為我們選擇合適的TypeHandler處理。
typeHandlers
無論是 MyBatis 在預處理語句(PreparedStatement)中設定一個引數時,還是從結果集中取出一個值時, 都會用型別處理器將獲取的值以合適的方式轉換成 Java 型別。下表描述了一些預設的型別處理器。
提示 從 3.4.5 開始,MyBatis 預設支援 JSR-310(日期和時間 API) 。
使用場景:mybatis在預處理語句(PreparedStatement)中設定一個引數時,或者從結果集(ResultSet)中取出一個值時,都會用到TypeHandler。它的作用就是將java型別(javaType)轉化為jdbc型別(jdbcType),或者將jdbc型別(jdbcType)轉化為java型別(javaType)。
需求一:
自定義列舉型別的TypeHandler,我們通過User類中有一個屬性性別(Sex)型別,來實現資料庫存sexcode, 取資料出來是sexname
需求二:
User類中有一個屬性叫做interest,這個屬性用來描述使用者的愛好,它的資料型別是一個List集合,那麼我想在把這個List集合存入資料庫的時候能夠自動的變成{XXX,XXX,XXX}這樣一個字串然後存起來,當我從資料庫讀取的時候也是讀取到這樣一個字串,讀取成功之後再自動的將之轉為一個List集合,
系統提供的typeHandler能夠滿足我們日常開發中的大部分需求,如上這兩種特殊的需求就需要我們自己去定義typeHandler了
1、自定義Sex列舉型別(需求一)
public enum SexEnum { MALE(1,"男"), FMALE(0,"女"); private int sexCode; private String sexName; private SexEnum(int sexCode, String sexName) { this.sexCode = sexCode; this.sexName = sexName; } //通過SexCode的值來獲取Sex列舉型別 public static SexEnum getSexEnumFromCode(int sexCode) { if(sexCode == 1) { return MALE; }else if(sexCode == 0) { return FMALE; } return null; } //get set }
2、 自定義列舉型別的TypeHandler
自定義typeHandler我們有兩種方式,一種是實現TypeHandler介面,還有一種就是繼承自BaseTypeHandler類。
@MappedJdbcTypes() 定義的是JdbcType型別,這裡的型別不可自己隨意定義,必須要是列舉類org.apache.ibatis.type.JdbcType所列舉的資料型別。
@MappedTypes() 定義的是JavaType的資料型別,描述了哪些Java型別可被攔截。
在我們啟用了我們自定義的這個TypeHandler之後,資料的讀寫都會被這個類所過濾
在setNonNullParameter / setParameter方法中,我們重新定義要寫往資料庫的資料。
另外三個方法中我們將從資料庫讀出的資料型別進行轉換
採用註解 或者 sql對映檔案指定 JdbcType 和 JavaType 都可以
1) sex屬性型別用自定義Sex列舉型別的TypeHandler(需求一)
public class MySexTypeHandler implements TypeHandler<SexEnum>{
@Override
public void setParameter(PreparedStatement ps, int i, SexEnum parameter, JdbcType jdbcType) throws SQLException {
ps.setInt(i, parameter.getSexCode());
}
@Override
public SexEnum getResult(ResultSet rs, String columnName) throws SQLException {
int sexCode = rs.getInt(columnName);
return SexEnum.getSexEnumFromCode(sexCode);
}
@Override
public SexEnum getResult(ResultSet rs, int columnIndex) throws SQLException {
int sexCode = rs.getInt(columnIndex);
return SexEnum.getSexEnumFromCode(sexCode);
}
@Override
public SexEnum getResult(CallableStatement cs, int columnIndex) throws SQLException {
int sexCode = cs.getInt(columnIndex);
return SexEnum.getSexEnumFromCode(sexCode);
}
}
2)interest屬性型別用自定義List型別的TypeHandler(需求二) 採用註釋
@MappedTypes(List.class)
@MappedJdbcTypes({JdbcType.VARCHAR})
public class MyListTypeHandler extends BaseTypeHandler<List<String>>{
@Override
public void setNonNullParameter(PreparedStatement ps, int i, List<String> parameter, JdbcType jdbcType)
throws SQLException {
if(parameter != null) {
// List集合轉字串
StringBuffer sbBuffer = new StringBuffer();
for(String string : parameter) {
sbBuffer.append(string).append(",");
}
ps.setString(i, sbBuffer.toString().substring(0,sbBuffer.toString().length()-1));
}
}
@Override
public List<String> getNullableResult(ResultSet rs, String columnName) throws SQLException {
if(rs.getString(columnName) != null) {
String[] split = rs.getString(columnName).split(",");
return Arrays.asList(split);
}
return null;
}
@Override
public List<String> getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
String[] split = rs.getString(columnIndex).split(",");
return Arrays.asList(split);
}
@Override
public List<String> getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
String[] split = cs.getString(columnIndex).split(",");
return Arrays.asList(split);
}
}
3、 資料庫 與 java model類
sex屬性型別用自定義SexEnum 列舉型別
public class User {
private Integer id;
private String username;
private String pazzword;
private Integer state;
private Date regDate;
private SexEnum sex; // 1:男, 0:女,用列舉
private List<String> interest; //愛好
...}
4、在sql對映檔案中進行配置
注意: 獲取資料和插入資料 的 配置
<resultMap id="BaseResultMap" type="cn.jq.mybatis.model.User">
<id column="id" jdbcType="INTEGER" property="id" />
<result column="username" jdbcType="VARCHAR" property="username" />
<result column="pazzword" jdbcType="VARCHAR" property="pazzword" />
<result column="state" jdbcType="INTEGER" property="state" />
<result column="reg_date" jdbcType="TIMESTAMP" property="regDate" />
<result column="sex" property="sex"
jdbcType="INTEGER"
javaType="cn.jq.mybatis.enums.SexEnum"
typeHandler="cn.jq.mybatis.enums.MySexTypeHandler"/>
<result column="interest" property="interest"
typeHandler="cn.jq.mybatis.enums.MyListTypeHandler"/>
</resultMap>
<sql id="Base_Column_List">
id, username, pazzword, state, reg_date, sex, interest
</sql>
<select id="selectByPrimaryKey" parameterType="java.lang.Integer" resultMap="BaseResultMap">
select
<include refid="Base_Column_List" />
from t_user
where id = #{id,jdbcType=INTEGER}
</select>
<insert id="insertUser" >
insert into t_user
(username,pazzword,state,reg_date,sex,interest)
values
(#{username},#{pazzword},#{state},#{regDate},
#{sex, jdbcType=INTEGER, javaType=cn.jq.mybatis.enums.SexEnum, typeHandler=cn.jq.mybatis.enums.MySexTypeHandler},
#{interest, typeHandler=cn.jq.mybatis.enums.MyListTypeHandler})
</insert>
5、在全域性配置檔案中註冊自定義的typeHandler
注意標籤配置順序: 在 set 標籤之後
<typeHandlers>
<typeHandler handler="cn.jq.mybatis.enums.MyListTypeHandler" />
<typeHandler handler="cn.jq.mybatis.enums.MySexTypeHandler" />
</typeHandlers>
6、測試
1)insert資料
UserMapper userMapper = session.getMapper(UserMapper.class);
List<String> list = new ArrayList<String>();
list.add("足球");
list.add("排球");
list.add("音樂");
User user = new User();
user.setUsername("ad22");
user.setPazzword("pass22");
user.setState(1);
user.setRegDate(new Date());
user.setSex(SexEnum.FMALE);
//user.setInterest(null); //愛好為空,自定義typeHandle做了判斷
user.setInterest(list);
userMapper.insertUser(user);
session.commit();
System.out.println(user);
資料庫:
2)select 資料
User user1 = userMapper.selectByPrimaryKey(1);
System.out.println(user1);
小結
OK,經過上面的介紹,想必小夥伴對typeHandler的使用已經有一定了解了,總結一下就是讀取時的配置要和插入時的配置分開來做,
讀取時資料轉換我們有兩種配置方式,分別是resultMap和在mybatis配置檔案中配置typeHandlers,
插入時的配置就是在insert節點中進行配置。
參考文章:
https://blog.csdn.net/u012702547/article/details/54572679
https://www.cnblogs.com/dongying/p/4040435.html