草庐IT

SpringBoot中MyBatis的TypeHandler相关报错汇总以及正确写法。Type handler was null、Class Not Found等情况

晓晓先生 2023-03-28 原文

迁移之前的老项目的时候,老项目中使用了一些MyBatis的TypeHandler相关的东西。但是老项目并非写在mapper.xml文件里面,而是使用@Select注解,把SQL写在了一个Class中。
在改造的过程中,我将TypeHandler迁移到了xml文件中,然后报了一些错误,比如:

Type handler was null on parameter mapping for property 'xxx'.

再比如:

ClassNotFound:com.xxx.XXXTypeHandler

解决时间也不算太长,但是还是记录一下,方便出现这类问题的人或者自己下次使用。
其实不管出现什么问题,肯定是TypeHandler没有配置好,所以我们直接说一下MyBatis的TypeHandler要怎么配置。

  1. 先看一下需要用到TypeHandler的实体类:
@Data
public class MyConfig implements Serializable {
    private Long id;
    private DetailJson detail;
}
  1. 然后是TypeHandler类:
public class MyConfigDetailJsonHandler extends BaseTypeHandler<DetailJson> {
    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, DetailJson parameter, JdbcType jdbcType) throws SQLException {
        ps.setString(i, JSON.toJSONString(parameter));
    }
    @Override
    public DetailJson getNullableResult(ResultSet rs, String columnName) throws SQLException {
        String string = rs.getString(columnName);
        if(StringUtils.isBlank(string) || !string.startsWith("{") || !string.endsWith("}")) {
            return null;
        }
        DetailJson javaObject = JSON.toJavaObject(JSON.parseObject((rs.getString(columnName))), DetailJson.class);
        return javaObject;
    }
    @Override
    public DetailJson getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        return null;
    }
    @Override
    public DetailJson getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        return null;
    }
}
  1. mapper.xml文件中的写法:
  • resultMap:
<resultMap id="BaseResultMap" type="com.xxx.MyConfig">
        <id column="id" jdbcType="BIGINT" property="id"/>
        <result column="detail" jdbcType="VARCHAR" property="detail" typeHandler="com.abc.typehandler.MyConfigDetailJsonHandler"/>
</resultMap>
  • select:
<select id="selectByPrimaryKey" parameterType="java.lang.Long" resultMap="BaseResultMap">
    select *
    from my_config
    where id = #{id,jdbcType=BIGINT}
</select>
  • insert:
<insert id="insert" parameterType="com.xxx.MyConfig">
    insert into my_config (id, detail)
    values (#{id,jdbcType=BIGINT}, #{detail,jdbcType=VARCHAR})
</insert>

这里需要注意,TypeHandler只在resultMap中写就可以了,insert和update语句不需要写,否则会报错。
上述代码能简化就简化了,像select * 这种并不是提倡的写法。

  1. 配置数据库Factory的时候,把TypeHandler所在的路径配上,也可以直接配置TypeHandler类:
  • 配置TypeHandler路径:
@Primary
@Bean("sqlSessionFactory")
public SqlSessionFactory sqlSessionFactory(@Qualifier("dataSource") DataSource dataSource) throws Exception {
    SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
    bean.setDataSource(dataSource);
    bean.setTypeHandlersPackage("com.abc.typehandler");
    bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:mapper/*.xml"));
    return bean.getObject();
}
  • 直接配置TypeHandler:
@Primary
@Bean("sqlSessionFactory")
public SqlSessionFactory sqlSessionFactory(@Qualifier("dataSource") DataSource dataSource) throws Exception {
    SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
    bean.setDataSource(dataSource);
    bean.setTypeHandlers(new MyConfigDetailJsonHandler());
    bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:mapper/*.xml"));
    return bean.getObject();
}

有关SpringBoot中MyBatis的TypeHandler相关报错汇总以及正确写法。Type handler was null、Class Not Found等情况的更多相关文章

  1. ruby - 什么是填充的 Base64 编码字符串以及如何在 ruby​​ 中生成它们? - 2

    我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%

  2. ruby - 默认情况下使选项为 false - 2

    这是在Ruby中设置默认值的常用方法:classQuietByDefaultdefinitialize(opts={})@verbose=opts[:verbose]endend这是一个容易落入的陷阱:classVerboseNoMatterWhatdefinitialize(opts={})@verbose=opts[:verbose]||trueendend正确的做法是:classVerboseByDefaultdefinitialize(opts={})@verbose=opts.include?(:verbose)?opts[:verbose]:trueendend编写Verb

  3. ruby - 在没有 sass 引擎的情况下使用 sass 颜色函数 - 2

    我想在一个没有Sass引擎的类中使用Sass颜色函数。我已经在项目中使用了sassgem,所以我认为搭载会像以下一样简单:classRectangleincludeSass::Script::FunctionsdefcolorSass::Script::Color.new([0x82,0x39,0x06])enddefrender#hamlengineexecutedwithcontextofself#sothatwithintemlateicouldcall#%stop{offset:'0%',stop:{color:lighten(color)}}endend更新:参见上面的#re

  4. ruby - 在不使用 RVM 的情况下在 Mac 上卸载和升级 Ruby - 2

    我最近决定从我的系统中卸载RVM。在thispage提出的一些论点说服我:实际上,我的决定是,我根本不想担心Ruby的多个版本。我只想使用1.9.2-p290版本而不用担心其他任何事情。但是,当我在我的Mac上运行ruby--version时,它告诉我我的版本是1.8.7。我四处寻找如何简单地从我的Mac上卸载这个Ruby,但奇怪的是我没有找到任何东西。似乎唯一想卸载Ruby的人运行linux,而使用Mac的每个人都推荐RVM。如何从我的Mac上卸载Ruby1.8.7?我想升级到1.9.2-p290版本,并且我希望我的系统上只有一个版本。 最佳答案

  5. 【鸿蒙应用开发系列】- 获取系统设备信息以及版本API兼容调用方式 - 2

    在应用开发中,有时候我们需要获取系统的设备信息,用于数据上报和行为分析。那在鸿蒙系统中,我们应该怎么去获取设备的系统信息呢,比如说获取手机的系统版本号、手机的制造商、手机型号等数据。1、获取方式这里分为两种情况,一种是设备信息的获取,一种是系统信息的获取。1.1、获取设备信息获取设备信息,鸿蒙的SDK包为我们提供了DeviceInfo类,通过该类的一些静态方法,可以获取设备信息,DeviceInfo类的包路径为:ohos.system.DeviceInfo.具体的方法如下:ModifierandTypeMethodDescriptionstatic StringgetAbiList​()Obt

  6. 深度学习部署:Windows安装pycocotools报错解决方法 - 2

    深度学习部署:Windows安装pycocotools报错解决方法1.pycocotools库的简介2.pycocotools安装的坑3.解决办法更多Ai资讯:公主号AiCharm本系列是作者在跑一些深度学习实例时,遇到的各种各样的问题及解决办法,希望能够帮助到大家。ERROR:Commanderroredoutwithexitstatus1:'D:\Anaconda3\python.exe'-u-c'importsys,setuptools,tokenize;sys.argv[0]='"'"'C:\\Users\\46653\\AppData\\Local\\Temp\\pip-instal

  7. 阿里云国际版免费试用:如何注册以及注意事项 - 2

    作为新的阿里云用户,您可以50免费试用多种优惠,价值高达1,700美元(或8,500美元)。这将让您了解和体验阿里云平台上提供的一系列产品和服务。如果您以个人身份注册免费试用,您将获得价值1,700美元的优惠。但是,如果您是注册公司,您可以选择企业免费试用,提交基本信息通过企业实名注册验证,即可开始价值$8,500的免费试用!本教程介绍了如何设置您的帐户并使用您的免费试用版。​关于免费试用在我们开始此试用之前,您还必须遵守以下条款和条件才能访问您的免费试用:只有在一年内创建的账户才有资格获得阿里云免费试用。通过此免费试用优惠,用户可以免费试用免费试用活动页面上列出的每种产品一次。如果您有多个帐

  8. ruby - 在什么情况下会使用 Sinatra 或 Merb? - 2

    我正在学习Rails,对Sinatra和Merb知之甚少。我想知道您会在哪些情况下使用Merb/Sinatra。感谢您的反馈! 最佳答案 Sinatra是一个比Rails更小、更轻的框架。如果你想让一些东西快速运行,只需发送几个URL并返回一些简单的内容,就可以使用它。看看Sinatrahomepage;这就是启动和运行“Hello,World”所需的全部内容,而在Rails中,您需要生成整个项目结构、设置Controller和View、设置路由等等(我还没有有一段时间写了一个Rails应用程序,所以我不知道“Hello,World

  9. ruby - 是否可以在不实际发送或读取数据的情况下查明 ruby​​ 套接字是否处于 ESTABLISHED 或 CLOSE_WAIT 状态? - 2

    s=Socket.new(Socket::AF_INET,Socket::SOCK_STREAM,0)s.connect(Socket.pack_sockaddr_in('port','hostname'))ssl=OpenSSL::SSL::SSLSocket.new(s,sslcert)ssl.connect从这里开始,如果ssl连接和底层套接字仍然是ESTABLISHED,或者它是否在默认值7200之后进入CLOSE_WAIT,我想检查一个线程几秒钟甚至更糟的是在实际上不需要.write()或.read()的情况下关闭。是用select()、IO.select()还是其他方法完成

  10. ruby-on-rails - 在这种情况下我如何模拟一个对象?没有明显的方法可以用模拟替换对象 - 2

    假设我在Store的模型中有这个非常简单的方法:defgeocode_addressloc=Store.geocode(address)self.lat=loc.latself.lng=loc.lngend如果我想编写一些不受地理编码服务影响的测试脚本,这些脚本可能已关闭、有限制或取决于我的互联网连接,我该如何模拟地理编码服务?如果我可以将地理编码对象传递到该方法中,那将很容易,但我不知道在这种情况下该怎么做。谢谢!特里斯坦 最佳答案 使用内置模拟和stub的rspecs,你可以做这样的事情:setupdo@subject=MyCl

随机推荐