背景
mybatis在3.4.5及之后版本中,新增了一个指定全局默认枚举类型处理器的配置项;
- 需要将mybatis-spring-boot-starter更新到2.1.4
- 对应mybatis-spring版本2.0.6
- 对应mybatis版本3.5.6
- 相应地需要更新druid到1.1.21以上
配置
1 2 3 4 5 6 7 8 9 10 11 12
| public SqlSessionFactory sqlSessionFactory(DataSource dataSource, PageHelper pageHelper, MybatisInterceptor mybatisInterceptor) throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean(); bean.setDefaultEnumTypeHandler(CodeIdentifyEnumHandler.class);
bean.setTypeHandlersPackage("com.xxx.model.enums"); return bean.getObject(); }
|
源码解析
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| private Map<JdbcType, TypeHandler<?>> getJdbcHandlerMap(Type type) { Map<JdbcType, TypeHandler<?>> jdbcHandlerMap = typeHandlerMap.get(type); if (NULL_TYPE_HANDLER_MAP.equals(jdbcHandlerMap)) { return null; } if (jdbcHandlerMap == null && type instanceof Class) { Class<?> clazz = (Class<?>) type; if (Enum.class.isAssignableFrom(clazz)) { Class<?> enumClass = clazz.isAnonymousClass() ? clazz.getSuperclass() : clazz; jdbcHandlerMap = getJdbcHandlerMapForEnumInterfaces(enumClass, enumClass); if (jdbcHandlerMap == null) { register(enumClass, getInstance(enumClass, defaultEnumTypeHandler)); return typeHandlerMap.get(enumClass); } } else { jdbcHandlerMap = getJdbcHandlerMapForSuperclass(clazz); } } typeHandlerMap.put(type, jdbcHandlerMap == null ? NULL_TYPE_HANDLER_MAP : jdbcHandlerMap); return jdbcHandlerMap; }
|
判断是Enum类型,且没有在全局map中拿到handler,会调用defaultEnumTypeHandler,在初始化时会将 enumClass 传入,因此生成的就是子类的 typeHandler。
1 2 3 4 5 6
| public CodeIdentifyEnumHandler(Class<T> type) { if (type == null) { throw new IllegalArgumentException("Type argument cannot be null"); } this.type = type; }
|
问题
1. 初始化报错
CodeIdentifyEnumHandler 类需要去掉abstract修饰,且添加无参构造函数,否则拿不到合适的构造器,初始化会报错。
2. JSR支持
MyBatis 3.4.1 之后内置了对 jsr310 的支持,导致调用LocalDateTimeTypeHandler等处理器报错,需要升级druid包版本到1.1.21以上。
因为内置的处理器会调用 ResultSet 的getObject() 方法:
1 2 3 4
| @Override public LocalDateTime getNullableResult(ResultSet rs, String columnName) throws SQLException { return rs.getObject(columnName, LocalDateTime.class); }
|
而因为使用druid,实际使用中使用的实现类是 DruidPooledResultSet,在1.1.21版本以前getObject()方法并未实现,会直接抛出SQLFeatureNotSupportedException异常。