Mybatis 自定义 TypeHandler 不能正常工作
My Batis custom TypeHandler does not work properly
我对带有 H2 的 IBatis 自定义映射器有疑问。
我有一个 H2 TEXT 列 (CLOB),其中有一个字符串,当我 运行 查询时:
@Select("select issue, count(*) from complaints WHERE company = #{companyName} group by issue order by 2 desc;")
fun getIssueCountsByCompanyName(@Param("companyName") companyName: String): List<Pair<String, Long>>
我有一个自定义 TypeMapper,我可以看到 运行从 CLOB 中正确提取字符串:
@MappedJdbcTypes(JdbcType.VARCHAR, JdbcType.CLOB, JdbcType.CHAR, JdbcType.NVARCHAR)
@MappedTypes(String::class)
class ClobTypeHandler: TypeHandler<String> {
override fun setParameter(ps: PreparedStatement?, i: Int, parameter: String?, jdbcType: JdbcType?) {
TODO("Not yet implemented")
}
fun getFromCol(col: Any?): String{
if(col == null){ return "" }
if(col is JdbcClob){
val returnValue =StreamUtils.copyToString(col.asciiStream, UTF_8)
// Examining with debugger shows `returnValue` is the correct String here
return returnValue
}
else {
return col.toString()
}
}
override fun getResult(rs: ResultSet?, columnName: String?): String {
return getFromCol(rs?.getObject(columnName))
}
override fun getResult(rs: ResultSet?, columnIndex: Int): String {
return getFromCol(rs?.getObject(columnIndex))
}
override fun getResult(rs: CallableStatement?, columnIndex: Int): String {
return getFromCol(rs?.getObject(columnIndex))
}
}
这是我的测试:
@Test
fun test_getIssues(){
var issueCounts = complaintMapper.getIssueCounts();
var issueCount = issueCounts.get(0)
assertFalse(issueCount.first.startsWith("clob"))
}
我收到这个错误:
org.h2.jdbc.JdbcClob 无法转换为 java.lang.String
java.lang.ClassCastException: org.h2.jdbc.JdbcClob 无法转换为 java.lang.String
因此,看起来 MYBatis 以某种方式调用了我期望的方法并且该方法返回了正确的字符串值,但是当 MYBatis 将数据放入它返回的对象中时,它放入了错误的值(CLOB 而不是它从映射器获得的字符串)
这是怎么回事?是聚合导致的吗,没看懂...
事实证明这解决了问题:
@Results(Result(column = "first", property = "first", typeHandler = H2ClobTypeHandler::class))
@Select("select issue as first, count(*) as second from complaints WHERE company = #{companyName} group by issue order by 2 desc;")
fun getIssueCountsByCompanyName(@Param("companyName") companyName: String): List<Pair<String, Long>>
当H2列是TEXT类型时,它与selecting into一个用String类型的泛型有关。
我对带有 H2 的 IBatis 自定义映射器有疑问。
我有一个 H2 TEXT 列 (CLOB),其中有一个字符串,当我 运行 查询时:
@Select("select issue, count(*) from complaints WHERE company = #{companyName} group by issue order by 2 desc;")
fun getIssueCountsByCompanyName(@Param("companyName") companyName: String): List<Pair<String, Long>>
我有一个自定义 TypeMapper,我可以看到 运行从 CLOB 中正确提取字符串:
@MappedJdbcTypes(JdbcType.VARCHAR, JdbcType.CLOB, JdbcType.CHAR, JdbcType.NVARCHAR)
@MappedTypes(String::class)
class ClobTypeHandler: TypeHandler<String> {
override fun setParameter(ps: PreparedStatement?, i: Int, parameter: String?, jdbcType: JdbcType?) {
TODO("Not yet implemented")
}
fun getFromCol(col: Any?): String{
if(col == null){ return "" }
if(col is JdbcClob){
val returnValue =StreamUtils.copyToString(col.asciiStream, UTF_8)
// Examining with debugger shows `returnValue` is the correct String here
return returnValue
}
else {
return col.toString()
}
}
override fun getResult(rs: ResultSet?, columnName: String?): String {
return getFromCol(rs?.getObject(columnName))
}
override fun getResult(rs: ResultSet?, columnIndex: Int): String {
return getFromCol(rs?.getObject(columnIndex))
}
override fun getResult(rs: CallableStatement?, columnIndex: Int): String {
return getFromCol(rs?.getObject(columnIndex))
}
}
这是我的测试:
@Test
fun test_getIssues(){
var issueCounts = complaintMapper.getIssueCounts();
var issueCount = issueCounts.get(0)
assertFalse(issueCount.first.startsWith("clob"))
}
我收到这个错误:
org.h2.jdbc.JdbcClob 无法转换为 java.lang.String java.lang.ClassCastException: org.h2.jdbc.JdbcClob 无法转换为 java.lang.String
因此,看起来 MYBatis 以某种方式调用了我期望的方法并且该方法返回了正确的字符串值,但是当 MYBatis 将数据放入它返回的对象中时,它放入了错误的值(CLOB 而不是它从映射器获得的字符串)
这是怎么回事?是聚合导致的吗,没看懂...
事实证明这解决了问题:
@Results(Result(column = "first", property = "first", typeHandler = H2ClobTypeHandler::class))
@Select("select issue as first, count(*) as second from complaints WHERE company = #{companyName} group by issue order by 2 desc;")
fun getIssueCountsByCompanyName(@Param("companyName") companyName: String): List<Pair<String, Long>>
当H2列是TEXT类型时,它与selecting into一个用String类型的泛型有关。