前言
今天在開發練習項目時遇到兩個mybatis使用問題
第一個問題是mapper方法參數問題,在參數大於一個時,mybatis不會自動識別參數命名
第二個問題是Pojo中使用Joda DateTime類型的字段,mybatis並不天然支持DateTime,這個問題想必有眾多開發者都遇到過
兩個問題均得到有效解決,在此進行總結記錄
Mapper中針對多參數的方法正確聲明方式
UserMapper interface中包含如下方法定義,用於刪除用戶權限
// 錯誤定義,此為演示
void deleteAuthority(String username, Authority authority);
對應UserMapper.xml中內容如下
<delete id="deleteAuthority">
DELETE FROM authorities WHERE username = #{username} AND authority = #{authority};
</delete>
執行時出錯,提示無法找到username與authority參數
修復方式,在方法聲明中,參數增加@Param注解,如下
void deleteAuthority(@Param("username") String username, @Param("authority") Authority authority);
支持Joda DateTime
例如 Pojo/Model 類型定義如,ctime表示用戶創建時間,使用joda DateTime類型
public class User {
private String username;
private String password;
private DateTime ctime;
private List<UserAuthority> authorities;
... 各種 get set 方法
}
mapper中addUser方法定義如下,對於ctime字段,Mybatis默認不支持DateTime類型,且沒有提供對應的TypeHander,因此需自行實現,如下的實現必然報錯
錯誤案例
<insert id="addUser" parameterType="user">
INSERT INTO users(username, password, ctime) VALUES(#{username}, #{password}, #{ctime})
</insert>
自定義實現DateTimeTypeHandler
參考此處外國友人的討論 Mybatis Joda Time Support
參考其源碼 LukeL99/joda-time-mybatis的實現
以下是是本人對DateTimeTypeHandler的實現,前人基礎上稍作重構
public class DateTimeTypeHandler implements TypeHandler<DateTime> {
@Override
public void setParameter(PreparedStatement preparedStatement, int i, DateTime dateTime, JdbcType jdbcType)
throws SQLException {
if (dateTime != null) {
preparedStatement.setTimestamp(i, new Timestamp(dateTime.getMillis()));
} else {
preparedStatement.setTimestamp(i, null);
}
}
@Override
public DateTime getResult(ResultSet resultSet, String s) throws SQLException {
return toDateTime(resultSet.getTimestamp(s));
}
@Override
public DateTime getResult(ResultSet resultSet, int i) throws SQLException {
return toDateTime(resultSet.getTimestamp(i));
}
@Override
public DateTime getResult(CallableStatement callableStatement, int i) throws SQLException {
return toDateTime(callableStatement.getTimestamp(i));
}
private static DateTime toDateTime(Timestamp timestamp) {
if (timestamp != null) {
return new DateTime(timestamp.getTime(), DateTimeZone.UTC);
} else {
return null;
}
}
}
正確使用方式,在mapper xml中需要指定DateTime類型參數對應的 typeHandler
<insert id="addUser" parameterType="user">
INSERT INTO users(username, password, ctime) VALUES(#{username}, #{password},
#{ctime, typeHandler=DateTimeTypeHandler})
</insert>
這里的DateTimeTypeHandler為使用完全限定名(無命名空間),原因是我已經在配置中加好了alias,方法請參考本人上一篇博客,即在構建sqlSessionFactoryBean時,通過setTypeAliases方法指定使用的類型