1.MyBatis 关a关XML映射处理CLOB和BLOB类型
2.自定义Mybatis的TypeHandler,轻松应对Mysql的联源联源JSON类型
3.MyBatis 核心配置讲解(上)
4.MyBatis自定义TypeHandler
MyBatis XML映射处理CLOB和BLOB类型
在Mybatis的MapperXML映射文件中,处理CLOB和BLOB类型的码j码数据至关重要。CLOB和BLOB分别代表Character Large Object和Binary Large Object,关a关前者用于存储大量文本(如长篇文章),联源联源后者则用于存储二进制大文件(如、码j码印尼宽带病毒源码音频)。关a关
Blob和CLOB在不同数据库中的联源联源类型对应有所不同,例如在MySQL中,码j码clob对应text或longtext,关a关blob对应blob;在Oracle中,联源联源clob和blob都直接对应自身的码j码名称。在Mapper文件中,关a关例如查询sql的联源联源`queryByList`,若report_summary字段为Oracle的码j码CLOB类型,需要在Java实体类(如myClob)中定义String类型的reportSummary来接收。
在Mapper.xml中,为读取CLOB和BLOB数据,源码 asp 仓储需配置合适的TypeHandler,如默认的mybatis的ClobTypeHandler。如果Clob字段是文本,可以直接用String处理,但若遇到blob类型乱码,可能需要自定义TypeHandler,如BlobToStringTypeHandler,通过继承BaseTypeHandler进行转换。
附录中提供了Mybatis与Oracle、MySQL数据类型的对应列表,若有遗漏,可参考官方文档。总结起来,MyBatis通过灵活的TypeHandler机制处理CLOB和BLOB类型数据,确保数据的正确读取和存储,这对于理解Java框架的持久层操作具有实际指导意义。
自定义Mybatis的通信框架源码TypeHandler,轻松应对Mysql的JSON类型
在MyBatis中,TypeHandler是一个核心组件,负责处理数据库字段与Java对象之间的类型转换。不同数据库系统和Java数据类型之间存在差异,TypeHandler负责确保数据的正确性和一致性转换。本文将深入探讨MyBatis中TypeHandler的相关知识,包括基础原理、编写自定义TypeHandler、处理常见数据类型、高级应用以及性能优化等内容。
TypeHandler的工作原理主要体现在参数设置和结果集映射两个关键环节。如果在Mybatis的xml中指定了TypeHandler,则会直接使用这个Handler。MyBatis通过结果映射配置来确定将结果集中的哪些列映射到Java对象的哪些属性上。当MyBatis从ResultSet中获取某列数据时,它会根据结果映射配置所关联的Java类型,找到相应的同城源码下载TypeHandler。然后,MyBatis调用TypeHandler的getResult方法,将数据库返回的JDBC类型数据转换为Java类型,最终赋值给目标Java对象的属性,确保了数据的正确转换和映射。
在实际开发中,有时需要处理特殊的数据类型或定制化的数据转换逻辑,例如数据库中的某个字段存储的是特定格式的字符串,而Java端需要将其转换为枚举或自定义对象。这时,可以编写自定义的TypeHandler进行数据处理。实现TypeHandler接口或继承BaseTypeHandler抽象类,提供对TypeHandler接口中方法的默认实现,包括空值处理和异常处理,提高了开发效率和代码的规范化。
使用@MappedJdbcTypes和@MappedTypes注解可以清晰地定义TypeHandler处理的JDBC类型和Java类型,确保在正确的刷广告源码地方被应用。全局配置时,可以通过SqlSessionFactoryBean的setTypeHandlers方法指定全局TypeHandler,局部指定时,在映射文件中配置指定字段的TypeHandler。自定义TypeHandler的示例以Mysql的JSON数据类型为例,展示了如何在数据库操作中处理JSON数据与Java对象的相互转换。
在MyBatis框架中,采用自定义TypeHandler实现特定数据类型转换具有优势,确保数据操作的准确性和一致性,避免数据损坏问题。通过精心设计和实现TypeHandler,可以有效处理数据库交互细节,提升代码的可读性和维护性。全局应用自定义的TypeHandler有利于维持数据操作的一致性和标准化,提高项目开发效率和维护质量。
在使用TypeHandler时,需要注意数据准确性和一致性,确保数据正确转换和映射,避免数据丢失或转换错误。TypeHandler还可以用于进行数据校验和转换,添加逻辑来检查数据的有效性、范围等,确保数据完整性和正确性。在TypeHandler的实现中,根据业务需求和数据特点进行性能优化和调整,以提高系统性能和稳定性。
通过深入学习和实践TypeHandler,可以灵活处理各种数据类型和数据格式,为项目顺利进行和未来的发展奠定基础。本文已收录于作者的个人博客,提供Java技术干货,包括Java基础、Spring Boot、Spring Cloud、Mysql、Redis、Elasticsearch、中间件、架构设计、面试题、程序员攻略等。
MyBatis 核心配置讲解(上)
大家好,我是分享硬核 Java 技术的互金摸鱼侠,王有志。
在前两篇文章里,我们探讨了 MyBatis 和其应用组成,今天我们将正式进入 MyBatis 学习的第二阶段:核心应用配置的讲解,从 mybatis-config.xml 开始,涉及映射器、动态 SQL 和集成Spring/Boot。
接下来,我们将逐步讲解 mybatis-config.xml 的核心配置部分,包括 properties、settings、typeAliases、typeHandlers 和 objectFactory。在讲解过程中,会提到 DTD,虽然可能对部分小伙伴不熟悉,但会在文末通过一张图简单介绍。
1. properties 元素(配置)
properties 元素用于声明配置,有两个属性 resource 和 url,以及 property 子元素。resource 和 url 允许从外部配置或网络获取配置,而 property 则直接在配置文件中声明。
2. settings 元素(设置)
settings 元素调整 MyBatis 设置,没有属性,只包含 setting 子元素,用于设置配置项。
3. typeAliases 元素(别名)
typeAliases 为 Java 类型定义别名,包含 typeAlias 和 package 元素,前者用于单个类型,后者针对包下的所有类型。
4. typeHandlers 元素(类型处理器)
typeHandlers 定义类型处理器,处理 Java 类型与数据库类型转换,有 typeHandler 和 package 元素,自定义处理器通过继承 BaseTypeHandler 实现。
5. objectFactory 元素(对象工厂)
objectFactory 创建结果集映射对象,没有属性,通过 property 配置参数,使用 DefaultObjectFactory 作为默认工厂。
附录:简要了解 DTD
DTD 用于定义 XML 结构和约束,mybatis-3-config.dtd 有其特定的语法,可以通过一张图概览。
本文为稀土掘金首发,天内禁止转载,天后需获授权。感谢点赞支持,如有错误,请指正。关注我,王有志,继续学习 MyBatis 的精彩内容。
MyBatis自定义TypeHandler
MyBatis自定义TypeHandler1什么是TypeHandler
TypeHandler根据字面意思即为类型处理器
引用官方文档的描述:MyBatis在设置预处理语句(PreparedStatement)中的参数或从结果集中取出一个值时,都会用类型处理器将获取到的值以合适的方式转换成Java类型
MyBatis存在一些默认的类型处理器,可参考官方文档
2为什么要使用TypeHandler在开发过程中,当默认的TypeHandler无法满足需求时,例如遇到MyBatis不支持的数据类型或需要特殊处理的类型转换,便需要自己定制对应的TypeHandler
笔者会在下面的代码实现中完成如下几种情况的TypeHandler:
逗号分隔保存在数据库中的数据,在对应的Java类中为数组
自定义枚举
3如何自定义TypeHandlerMyBatis提供了接口org.apache.ibatis.type.TypeHandler和类org.apache.ibatis.type.BaseTypeHandler
官方文档给出的示例为继承BaseTypeHandler,笔者在这里也使用这种方式
先来观察一下官方的StringTypeHandler:
publicclassStringTypeHandlerextendsBaseTypeHandler<String>{ @OverridepublicvoidsetNonNullParameter(PreparedStatementps,inti,Stringparameter,JdbcTypejdbcType)throwsSQLException{ ps.setString(i,parameter);}@OverridepublicStringgetNullableResult(ResultSetrs,StringcolumnName)throwsSQLException{ returnrs.getString(columnName);}@OverridepublicStringgetNullableResult(ResultSetrs,intcolumnIndex)throwsSQLException{ returnrs.getString(columnIndex);}@OverridepublicStringgetNullableResult(CallableStatementcs,intcolumnIndex)throwsSQLException{ returncs.getString(columnIndex);}}方法名称和代码都简洁明了,观察可知,只需要完成四个方法的覆盖,即可实现自定义TypeHandler
3.1逗号分隔字符串转数组假设用户表t_user设计如下:
idusernametags1adminadmin,user对应的Java类为:
@Data@NoArgsConstructor@SuperBuilder(toBuilder=true)publicclassUser{ privateStringid;privateStringusername;privateString[]tags;}tags属性在数据库中用逗号分隔的字符串保存,但User类对应的属性为String数组
可以创建StringArrayTypeHandler来解决类型转换的问题:
publicclassStringArrayTypeHandlerextendsBaseTypeHandler<String[]>{ @OverridepublicvoidsetNonNullParameter(PreparedStatementpreparedStatement,inti,String[]strings,JdbcTypejdbcType)throwsSQLException{ preparedStatement.setString(i,StringUtils.join(strings,","));}@OverridepublicString[]getNullableResult(ResultSetresultSet,Strings)throwsSQLException{ returnconvert(resultSet.getString(s));}@OverridepublicString[]getNullableResult(ResultSetresultSet,inti)throwsSQLException{ returnconvert(resultSet.getString(i));}@OverridepublicString[]getNullableResult(CallableStatementcallableStatement,inti)throwsSQLException{ returnconvert(callableStatement.getString(i));}/***将查询值转换为数组**@paramvalue查询值,String*@return转换结果,String[]*/privateString[]convert(Stringvalue){ returnStringUtils.isEmpty(value)?newString[0]:value.split(",");}}3.2自定义枚举如何创建包含中文名称的枚举,可以参考MyBatis中使用Java类与枚举
先创建工具类用于根据code获取枚举实体:
publicclassValueNameEnumUtils{ privateValueNameEnumUtils(){ }publicstatic<EextendsValueNameEnum>EvalueOf(Class<E>enumClass,intvalue){ E[]enumConstants=enumClass.getEnumConstants();for(Ee:enumConstants){ if(e.getValue()==value){ returne;}}returnnull;}}和3.1中的情况不同,枚举的具体类型是不确定,所以我们要使用泛型的方式处理TypeHandler
创建ValueNameEnumTypeHandler:
publicclassValueNameEnumTypeHandler<EextendsValueNameEnum>extendsBaseTypeHandler<ValueNameEnum>{ privatefinalClass<E>type;publicValueNameEnumTypeHandler(Class<E>type){ if(type==null){ thrownewIllegalArgumentException("Typeargumentcannotbenull");}this.type=type;}}泛型虽然名之为泛,但在编译过程中实际会发生类型擦除
总之,对于泛型TypeHandler,我们需要声明一个用来标识具体类型的属性privatefinalClass<E>type和创建对应的构造函数publicValueNameEnumTypeHandler(Class<E>type)
接下来和3.1中的一致,重写四个方法:
publicclassValueNameEnumTypeHandler<EextendsValueNameEnum>extendsBaseTypeHandler<ValueNameEnum>{ privatefinalClass<E>type;publicValueNameEnumTypeHandler(Class<E>type){ if(type==null){ thrownewIllegalArgumentException("Typeargumentcannotbenull");}this.type=type;}@OverridepublicvoidsetNonNullParameter(PreparedStatementps,inti,ValueNameEnumparameter,JdbcTypejdbcType)throwsSQLException{ ps.setInt(i,parameter.getValue());}@OverridepublicEgetNullableResult(ResultSetrs,StringcolumnName)throwsSQLException{ intcode=rs.getInt(columnName);returnrs.wasNull()?null:valueOf(code);}@OverridepublicEgetNullableResult(ResultSetrs,intcolumnIndex)throwsSQLException{ intcode=rs.getInt(columnIndex);returnrs.wasNull()?null:valueOf(code);}@OverridepublicEgetNullableResult(CallableStatementcs,intcolumnIndex)throwsSQLException{ intcode=cs.getInt(columnIndex);returncs.wasNull()?null:valueOf(code);}/***根据枚举值返回枚举示例**@paramcode枚举值*@return枚举实例*/privateEvalueOf(intcode){ try{ returnValueNameEnumUtils.valueOf(type,code);}catch(Exceptionex){ thrownewIllegalArgumentException("Cannotconvert"+code+"to"+type.getSimpleName()+"bycodevalue.",ex);}}}完成上述代码直接启动,会抛出异常:Unabletofindausableconstructorforclasscn.houtaroy.springboot.common.MyBatis.handler.ValueNameEnumTypeHandler
产生异常的源码如下:
public<T>TypeHandler<T>getInstance(Class<?>javaTypeClass,Class<?>typeHandlerClass){ //未指定JavaType,此处为falseif(javaTypeClass!=null){ try{ Constructor<?>c=typeHandlerClass.getConstructor(Class.class);return(TypeHandler<T>)c.newInstance(javaTypeClass);}catch(NoSuchMethodExceptionignored){ //ignored}catch(Exceptione){ thrownewTypeException("Failedinvokingconstructorforhandler"+typeHandlerClass,e);}}try{ //此处抛出异常Constructor<?>c=typeHandlerClass.getConstructor();return(TypeHandler<T>)c.newInstance();}catch(Exceptione){ thrownewTypeException("Unabletofindausableconstructorfor"+typeHandlerClass,e);}}报错的原因直白,没有找到ValueNameEnumTypeHandler的构造函数
首先我们要了解下Java类构造函数的机制:如果定义了构造函数,则使用定义,否则默认生成空构造函数
在3.1中的StringArrayTypeHandler,我们没有定义构造函数,自动生成空构造函数,typeHandlerClass.getConstructor()不会抛出异常
但ValueNameEnumTypeHandler定义了一个构造函数ValueNameEnumTypeHandler(Class<E>type),且没有指定JavaType,typeHandlerClass.getConstructor()自然抛出异常
解决方法有两种:
创造空的构造函数
指定JavaType
笔者推荐第二种,因为第一种方式枚举类属性type会产生NPE(空指针异常),MyBatis官方也我们提供了注解@MappedTypes用于指定JavaType:
@MappedTypes(ValueNameEnum.class)publicclassValueNameEnumTypeHandler<EextendsValueNameEnum>extendsBaseTypeHandler<ValueNameEnum>{ //...}4如何使用TypeHandler在上一章节中,我们完成了编码实现自定义TypeHandler,但完成的TypeHandler还没办法进行使用,需要手动进行配置
有两种配置方式:局部使用和全局使用
以StringArrayTypeHandler举例:
4.1局部使用在ResultMap中使用:
<resultMapid="UserResultMap"type="cn.houtaroy.springboot.common.system.model.User"><idcolumn="id"property="id"/><resultcolumn="tags"property="tags"typeHandler="cn.houtaroy.springboot.extension.mybatis.handler.StringArrayTypeHandler"/></resultMap>在语句中使用:
updatet_usersettags=#{ tags,typeHandler=cn.houtaroy.springboot.extension.mybatis.handler.StringArrayTypeHandler}4.2全局使用使用配置文件指定handler包名:
@Data@NoArgsConstructor@SuperBuilder(toBuilder=true)publicclassUser{ privateStringid;privateStringusername;privateString[]tags;}0注意,此配置类型为String,只能配置一个包,推荐使用下面的方式
手写配置类:
@Data@NoArgsConstructor@SuperBuilder(toBuilder=true)publicclassUser{ privateStringid;privateStringusername;privateString[]tags;}1StringArrayTypeHandler不适合全局配置,它会在全部JavaType为String[]的属性上使用
5拓展阅读MyBatis3官方文档中TypeHandler内容:mybatis–MyBatis3|配置
网上搜索的在SpringBean声明周期中进行全局配置:Mybatis自定义全局TypeHander_chuobenggu的博客-CSDN博客