解決mybatis竟然報Invalid value for getInt()的問題
帶你來看看mybatis為什麼報”Invalid value for getInt()”這個錯誤
背景
使用mybatis
遇到一個非常奇葩的問題,錯誤如下:
Cause: org.apache.ibatis.executor.result.ResultMapException: Error attempting to get column ‘name’ from result set. Cause: java.sql.SQLException: Invalid value for getInt() – ‘wo’
場景
還原一下當時的情況:
public interface UserMapper { @Results(value = { @Result(property = "id", column = "id", javaType = Long.class, jdbcType = JdbcType.BIGINT), @Result(property = "age", column = "age", javaType = Integer.class, jdbcType = JdbcType.INTEGER), @Result(property = "name", column = "name", javaType = String.class, jdbcType = JdbcType.VARCHAR) }) @Select("SELECT id, name, age FROM user WHERE id = #{id}") User selectUser(Long id); } @Data @Builder public class User { private Long id; private Integer age; private String name; } public class MapperMain { public static void main(String[] args) throws Exception { MysqlConnectionPoolDataSource dataSource = new MysqlConnectionPoolDataSource(); dataSource.setUser("root"); dataSource.setPassword("root"); dataSource.setUrl("jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8"); TransactionFactory transactionFactory = new JdbcTransactionFactory(); Environment environment = new Environment("development", transactionFactory, dataSource); Configuration configuration = new Configuration(environment); configuration.addMapper(UserMapper.class); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration); try (SqlSession session = sqlSessionFactory.openSession()) { UserMapper userMapper = session.getMapper(UserMapper.class); System.out.println(userMapper.selectUser(1L)); } } }
數據庫如下:
上面是一個很簡單的例子,就是根據id
選出用戶的信息,運行結果如下:
User(id=1, age=2, name=3)
沒有任何問題,但是我再往數據庫裡插入一條數據,如下:
在MapperMain
類中增加一行代碼,如下:
System.out.println(userMapper.selectUser(2L));
運行結果如下:
User(id=1, age=2, name=3)
### Error querying database. Cause: org.apache.ibatis.executor.result.ResultMapException: Error attempting to get column ‘name’ from result set. Cause: java.sql.SQLException: Invalid value for getInt() – ‘lh’
……
可以看出第一條查詢沒有問題,第二條查詢就報錯瞭
初探
其實我的直覺告訴我,是不是因為User
類裡字段順序和SQL
語句裡select字段
的順序不一致導致的,那就來試一下吧
改一下User
類裡字段的順序:
@Data @Builder public class User { private Long id; private String name; private Integer age; }
結果如下:
User(id=1, name=3, age=2)
User(id=2, name=lh, age=3)
果不其然,直覺還是很6的
或者改一下SQL
語句裡select字段
的順序:
@Data @Builder public class User { private Long id; private Integer age; private String name; } public interface UserMapper { @Results(value = { @Result(property = "id", column = "id", javaType = Long.class, jdbcType = JdbcType.BIGINT), @Result(property = "age", column = "age", javaType = Integer.class, jdbcType = JdbcType.INTEGER), @Result(property = "name", column = "name", javaType = String.class, jdbcType = JdbcType.VARCHAR) }) @Select("SELECT id, age, name FROM user WHERE id = #{id}") User selectUser(Long id); }
以我們的直覺,結果肯定也沒問題,果不其然,如下:
User(id=1, age=2, name=3) User(id=2, age=3, name=lh)
再探
其實到上一步,問題已經解決瞭,可以繼續幹活瞭,但是搞不懂為什麼,心裡總覺得不踏實。
找bug
從debug
開始,從下面的入口開始:
追蹤到如下:
可以看出User
這個類是有構造函數的,而且是包含所有字段的構造函數
利用這個構造函數創建實例的時候,參數的順序就是SQL語句選擇字段的順序,不會根據映射關系去選擇
所以就出現瞭類型不匹配
那我們再來看一下問什麼會有一個這樣的構造函數產生,直覺告訴我是@Builder
這個註解
一起來看一下User
編譯後的結果:
public class User { private Long id; private String name; private Integer age; User(final Long id, final String name, final Integer age) { this.id = id; this.name = name; this.age = age; } public static User.UserBuilder builder() { return new User.UserBuilder(); } public static class UserBuilder { private Long id; private String name; private Integer age; UserBuilder() { } public User.UserBuilder id(final Long id) { this.id = id; return this; } public User.UserBuilder name(final String name) { this.name = name; return this; } public User.UserBuilder age(final Integer age) { this.age = age; return this; } public User build() { return new User(this.id, this.name, this.age); } } }
果然如此,UserBuilder.build()
方法就是利用這個構造函數來生成的。
結局
最終解決方案就是給User
類加上無參的構造函數就OK瞭,如下:
@Builder @AllArgsConstructor @NoArgsConstructor public class User { private Integer age; private String name; private Long id; }
字段順序隨便放,最後再執行一下:
User(age=2, name=3, id=1) User(age=3, name=lh, id=2)
到此這篇關於mybatis竟然報”Invalid value for getInt()”的文章就介紹到這瞭,更多相關mybatis報Invalid value for getInt()內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- Mybatis中resultMap的Colum和property屬性詳解
- MyBatis延遲加載策略深入探究
- Mybatis使用@one和@Many實現一對一及一對多關聯查詢
- 解讀Mapper與Mapper.xml文件之間匹配的問題
- Mybatis實現聯表查詢並且分頁功能