事情是这样的,我用了Mybatis Plus,使用它生成的实体类的日期类型为LocalDateTime,如果mysql数据库里面的字段类型是datetime的话。
然后我使用Mybatis Plus的查询方法,根据id查找某条数据,然后映射到实体类上。
就在这时,发生了一个让我崩溃的事情:
Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.executor.result.ResultMapException: Error attempting to get column ‘update_date’ from result set. Cause: java.lang.NullPointerException]
虽然我数据库中的datetime类型的 update_date 为空,但你也不必给我抛出一个空指针吧?
我真是丈二和尚摸不着头脑,把这个错误粘贴到百度上一搜索,我去,心中一万个草泥马顿时跑过,怎么每一个都不是讲我这个错误的。
只能耐着性子慢慢 debug,然后发现了不可思议的一幕。
public <T> T getObject(int columnIndex, Class<T> type) throws SQLException {
if (type == null) {
throw SQLError.createSQLException("Type parameter can not be null", "S1009", this.getExceptionInterceptor());
} else if (type.equals(LocalDate.class)) {
return type.cast(this.getDate(columnIndex).toLocalDate());
} else if (type.equals(LocalDateTime.class)) {
return type.cast(this.getTimestamp(columnIndex).toLocalDateTime());
} else if (type.equals(LocalTime.class)) {
return type.cast(this.getTime(columnIndex).toLocalTime());
} else {
if (type.equals(OffsetDateTime.class)) {
try {
return type.cast(OffsetDateTime.parse(this.getString(columnIndex)));
} catch (DateTimeParseException var5) {
}
} else if (type.equals(OffsetTime.class)) {
try {
return type.cast(OffsetTime.parse(this.getString(columnIndex)));
} catch (DateTimeParseException var4) {
}
}
return super.getObject(columnIndex, type);
}
}
请注意第七行代码:
return type.cast(this.getTimestamp(columnIndex).toLocalDateTime());
正是这行代码把我坑了。写这个代码的兄弟,为什么不加个空指针校验呐?兄弟,this.getTimestamp(columnIndex)
这个是空的啊,让我怎么办啊?改代码吗?我怎么改兄弟,我快要哭了。
百度搜索不到解决方案,改代码也改不了,我真是进退两难。
突然我灵机一动,把下面这行代码反手就粘贴到百度搜索框内,熟练地点击了下被我点了不知多少次地百度。
return type.cast(this.getTimestamp(columnIndex).toLocalDateTime());
只见我的眼前,金光闪闪,赫然地立着几个大字:
jdk LocalDateTime mybatis 空指针解决办法 - haole的专栏
我擦,这不是我苦苦寻找地宝典吗?你怎么藏得这么深,非要用这行代码才能把你揪出来。
(附上宝典地地址: 欲练此宝典,话不多说了)
于是我如饥似渴地翻开了神往已久的宝典,第一句就让我荡魂摄魄,出现了一个与版本有关的词。
于是我翻动鼠标,飞似的滑动滚轮,发现眼前的景象是如此地让我痴迷:
public <T> T getObject(int columnIndex, Class<T> type) throws SQLException {
if (type == null) {
throw SQLError.createSQLException("Type parameter can not be null", "S1009", this.getExceptionInterceptor());
} else if (type.equals(LocalDate.class)) {
Date date = this.getDate(columnIndex);
return date == null ? null : type.cast(date.toLocalDate());
} else if (type.equals(LocalDateTime.class)) {
Timestamp timestamp = this.getTimestamp(columnIndex);
return timestamp == null ? null : type.cast(timestamp.toLocalDateTime());
} else if (type.equals(LocalTime.class)) {
Time time = this.getTime(columnIndex);
return time == null ? null : type.cast(time.toLocalTime());
} else {
String string;
if (type.equals(OffsetDateTime.class)) {
try {
string = this.getString(columnIndex);
return string == null ? null : type.cast(OffsetDateTime.parse(string));
} catch (DateTimeParseException var5) {
}
} else if (type.equals(OffsetTime.class)) {
try {
string = this.getString(columnIndex);
return string == null ? null : type.cast(OffsetTime.parse(string));
} catch (DateTimeParseException var4) {
}
}
return super.getObject(columnIndex, type);
}
}
哇哦!非空判断,竟然有了非空判断,这场比赛必定要赢了,非空一出,无人能挡啊!
秘诀是,请你把mysql的驱动升级到 5.1.42及以上,42之前是没有非空判断的。
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
血与泪的教训,千万别用大版本中版本较低的那个,因为低版本的说不定有bug,就像此处的bug。
五的版本这么多,以后铁定用 5.1.48,哼哼。
到此,大功告成。