当前位置: 首页 > news >正文

网站建设方式今日最新消息新闻

网站建设方式,今日最新消息新闻,广州江湾大酒店电子商务网站建设,电子商务网站建设的主要内容🎮 作者主页:点击 🎁 完整专栏和代码:点击 🏡 博客主页:点击 文章目录 原始 JDBC 存在的问题自定义 TypeHandler 实现TypeHandler详解BaseTypeHandler类TypeReference类型参考器43个类型处理器类型注册表&a…

🎮 作者主页:点击
🎁 完整专栏和代码:点击
🏡 博客主页:点击

文章目录

  • 原始 JDBC 存在的问题
  • 自定义 TypeHandler 实现
  • TypeHandler详解
  • BaseTypeHandler类
  • TypeReference类型参考器
  • 43个类型处理器
  • 类型注册表:3个
  • 注解类
  • 枚举类

原始 JDBC 存在的问题

MyBatis 之所以设计了 TypeHandler(类型处理器),是为了解决 JDBC 在处理 数据类型映射 时存在的问题,简化开发者操作,并提供更灵活的类型转换机制。在 JDBC 中,我们需要手动将数据库字段与 Java 对象的属性进行映射。通常涉及调用 ResultSet.getXXX() 和 PreparedStatement.setXXX() 方法,如:

PreparedStatement stmt = connection.prepareStatement("SELECT * FROM user WHERE id = ?");
stmt.setInt(1, 123);
ResultSet rs = stmt.executeQuery();
if (rs.next()) {int id = rs.getInt("id");String name = rs.getString("name");Date birthDate = rs.getDate("birth_date");
}

这种映射需要针对每种数据类型手动写 get 和 set 方法,代码繁琐且容易出错。
数据库中的数据类型(如 VARCHAR、DATE、TIMESTAMP、NUMERIC 等)与 Java 的数据类型(如 String、int、double、Date 等)不完全对应,导致在处理数据时需要进行额外的类型转换。例如,数据库中的 DATE 类型可能需要转换为 Java 的 LocalDate 或 java.util.Date。
如果数据库字段的数据类型发生变化,开发者需要修改所有相关的 JDBC 代码,非常容易出错且维护成本高。原生 JDBC 无法直接处理数据库中的复杂数据类型(如 JSON、XML、枚举等)。如果需要支持这些类型,需要在代码中手动解析和转换,增加了开发难度。

自定义 TypeHandler 实现

在 MyBatis 中,我们可以通过自定义 TypeHandler 来处理 特殊的数据类型映射。一个常见的应用场景是将数据库中的 JSON 字符串与 Java 对象之间进行自动转换。下面将介绍如何自定义 TypeHandler 实现 JSON 类型的转换。
在这里插入图片描述
t_user表的jsonInfo存储的是json文本字符串,我希望在查询t_user数据的时候可以直接解析出来这个json文本信息为对象。
在这里插入图片描述

public class UserBean {private Integer id;private String name;private String mobile_no;private MyObject jsonInfo;
}
@Data
public class MyObject {private String name;private Integer age;
}

实现自定义 TypeHandler

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.zy.client.bean.MyObject;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;import java.sql.*;public class JsonTypeHandler extends BaseTypeHandler<MyObject> {private final ObjectMapper objectMapper = new ObjectMapper();@Overridepublic void setNonNullParameter(PreparedStatement ps, int i, MyObject parameter, JdbcType jdbcType) throws SQLException {try {// 将 Java 对象序列化为 JSON 字符串String json = objectMapper.writeValueAsString(parameter);ps.setString(i, json);} catch (JsonProcessingException e) {throw new SQLException("Failed to convert  JSON string.", e);}}@Overridepublic MyObject getNullableResult(ResultSet rs, String columnName) throws SQLException {String json = rs.getString(columnName);return parseJson(json);}@Overridepublic MyObject getNullableResult(ResultSet rs, int columnIndex) throws SQLException {String json = rs.getString(columnIndex);return parseJson(json);}@Overridepublic MyObject getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {String json = cs.getString(columnIndex);return parseJson(json);}private MyObject parseJson(String json) throws SQLException {try {if (json != null && !json.isEmpty()) {return objectMapper.readValue(json, MyObject.class);}} catch (JsonProcessingException e) {throw new SQLException("Failed to convert JSON string to MyObject.", e);}return null;}
}

在 mybatis-config.xml 中注册自定义的 TypeHandler:

  <typeHandlers><typeHandler handler="com.zy.client.test.JsonTypeHandler" javaType="java.util.List"/></typeHandlers>

或者通过 @Mapper 的 @TypeHandler 注解:

  @Select("select * from t_user where id=#{id}")@Result(column = "jsonInfo", property = "jsonInfo", typeHandler = JsonTypeHandler.class)UserBean selectDataById(int id);

测试类:

  @Testpublic void test2() throws SQLException, IOException {InputStream resource = Resources.getResourceAsStream(MybatisTest.class.getClassLoader(), "mybatis-config.xml");SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resource);Configuration configuration = sqlSessionFactory.getConfiguration();// 手动注册mapperconfiguration.addMapper(UserMapper.class);configuration.setProxyFactory(new MyLoggingProxyFactory());SqlSession sqlSession = sqlSessionFactory.openSession();UserMapper mapper = sqlSession.getMapper(UserMapper.class);UserBean userBean = mapper.selectDataById(1);System.out.println(userBean);}
输出结果:
UserBean(id=1, name=zhangSan, mobile_no=188, jsonInfo=MyObject(name=Alice, age=18))

通过自定义 TypeHandler,MyBatis 可以方便地处理复杂的数据类型,避免繁琐的手动类型转换操作。尤其在处理 JSON 数据时,通过 TypeHandler 实现自动序列化和反序列化,可以极大简化代码逻辑,提高开发效率。

TypeHandler详解

public interface TypeHandler<T> {void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException;T getResult(ResultSet rs, String columnName) throws SQLException;T getResult(ResultSet rs, int columnIndex) throws SQLException;T getResult(CallableStatement cs, int columnIndex) throws SQLException;}

TypeHandler接口中定义了4个方法,setParameter()方法用于为PreparedStatement对象参数的占位符设置值,另外3个重载的getResult()方法用于从ResultSet对象中获取列的值,或者获取存储过程调用结果。
在这里插入图片描述

BaseTypeHandler类

MyBatis中的BaseTypeHandler类实现了TypeHandler接口,对调用setParameter()方法,参数为Null的情况做了通用的处理。对调用getResult()方法,从ResultSet对象或存储过程调用结果中获取列的值出现的异常做了处理。因此,当我们需要自定义TypeHandler时,只需要继承BaseTypeHandler类即可。
在类型处理器相关类的设计中采用了模板模式,BaseTypeHandler<T>作为所有类型处理器的基类,定义了模板的框架。而在各个具体的实现类中,则实现了具体的细节。

以BaseTypeHandler中 getResult(ResultSet,String)方法为例,该方法完成了异常处理等统一的工作,而与具体类型相关的 getNullableResult(ResultSet,String)操作则通过抽象方法交给具体的类型处理器实现。这就是典型的模板模式。

  @Overridepublic T getResult(ResultSet rs, String columnName) throws SQLException {try {return getNullableResult(rs, columnName);} catch (Exception e) {throw new ResultMapException("Error attempting to get column '" + columnName + "' from result set.  Cause: " + e, e);}}public abstract T getNullableResult(ResultSet rs, String columnName) throws SQLException;

BaseTypeHandler<T>交给具体的类型处理器实现的抽象方法一共只有四个。在每个类型处理器都需要实现这四个方法。
· void setNonNullParameter(PreparedStatement,int,T,JdbcType)​:向PreparedStatement对象中的指定变量位置写入一个不为 null的值;
· T getNullableResult(ResultSet,String)​:从 ResultSet 中按照字段名读出一个可能为null的数据;
· T getNullableResult(ResultSet,int)​:从 ResultSet 中按照字段编号读出一个可能为null的数据;
· T getNullableResult(CallableStatement,int)​:从 CallableStatement中按照字段编号读出一个可能为 null的数据。

因为上面的抽象方法跟具体的类型相关,因此存在泛型参数 T。在每种类型处理器中,都给出了泛型参数的值。以 IntegerTypeHandler 为例,它设置泛型参数值为Integer。

public class IntegerTypeHandler extends BaseTypeHandler<Integer>

TypeReference类型参考器

43个类型处理器可以处理不同 Java类型的数据,而这些类型处理器都是 TypeHandler接口的子类,因此可以都作为 TypeHandler来使用。

那会不会遇到一个问题,当 MyBatis取到某一个 TypeHandler 时,却不知道它到底是用来处理哪一种 Java类型的处理器?
为了解决这一问题,MyBatis 定义了一个 TypeReference 类。它能够判断出一个TypeHandler用来处理的目标类型。而它判断的方法也很简单:取出 TypeHandler实现类中的泛型参数 T的类型,这个值的类型也便是该 TypeHandler能处理的目标类型。该功能由getSuperclassTypeParameter方法实现,该方法能将找出的目标类型存入类中的 rawType属性。

  Type getSuperclassTypeParameter(Class<?> clazz) {Type genericSuperclass = clazz.getGenericSuperclass();if (genericSuperclass instanceof Class) {// try to climb up the hierarchy until meet something usefulif (TypeReference.class != genericSuperclass) {return getSuperclassTypeParameter(clazz.getSuperclass());}throw new TypeException("'" + getClass() + "' extends TypeReference but misses the type parameter. "+ "Remove the extension or add a type parameter to it.");}Type rawType = ((ParameterizedType) genericSuperclass).getActualTypeArguments()[0];if (rawType instanceof ParameterizedType) {rawType = ((ParameterizedType) rawType).getRawType();}return rawType;}

TypeReference 类是 BaseTypeHandler 的父类,因此所有的类型处理器都继承了TypeReference 的功能。这意味着对任何一个类型处理器调用getSuperclassTypeParameter方法,都可以得到该处理器用来处理的目标类型。

43个类型处理器

type 包共有 43 个类型处理器,这些类型处理器的名称也均以“TypeHandler”结尾。而 TypeHandler和 BaseTypeHandler则分别是类型处理器接口和类型处理器基类。
MyBatis 提供了多种内置的 TypeHandler,如 StringTypeHandler、IntegerTypeHandler 等,也可以自定义 TypeHandler 来满足特定需求。
StringTypeHandler 用于处理 String 类型的数据,在以下场景中会自动使用:
• 当 MyBatis 映射的 Java 类型为 String,而数据库字段的类型为 VARCHAR、CHAR、TEXT 等字符串类型时。
• 当没有为 String 类型字段显式配置 TypeHandler 时,MyBatis 会默认使用 StringTypeHandler。

public class StringTypeHandler extends BaseTypeHandler<String> {@Overridepublic void setParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException {if (parameter == null) {ps.setNull(i, Types.VARCHAR);} else {ps.setString(i, parameter);}}@Overridepublic String getResult(ResultSet rs, String columnName) throws SQLException {return rs.getString(columnName);}@Overridepublic String getResult(ResultSet rs, int columnIndex) throws SQLException {return rs.getString(columnIndex);}@Overridepublic String getResult(CallableStatement cs, int columnIndex) throws SQLException {return cs.getString(columnIndex);}
}

类型注册表:3个

SimpleTypeRegistry:基本类型注册表,内部使用 Set 维护了所有 Java 基本数据类型的集合;-TypeAliasRegistry:类型别名注册表,内部使用 HashMap维护了所有类型的别名和类型的映射关系;
TypeHandlerRegistry:类型处理器注册表,内部维护了所有类型与对应类型处理器的映射关系。

定义了大量的类型处理器之后,MyBatis 还需要在遇到某种类型的数据时,快速找到与数据的类型对应的类型处理器。这个过程就需要各种类型注册表的帮助。
type 包中的类型注册表有三个:SimpleTypeRegistry、TypeAliasRegistry 和TypeHandlerRegistry。SimpleTypeRegistry 是一个非常简单的注册表,其内部使用一个 SIMPLE_TYPE_SET变量维护所有 Java基本类型。SIMPLE_TYPE_SET中的赋值是在 static代码块中进行的。这说明在 SimpleTypeRegistry初始化结束后,就已经将所有的Java基本类型维护到了 SIMPLE_TYPE_SET中。

public class SimpleTypeRegistry {private static final Set<Class<?>> SIMPLE_TYPE_SET = new HashSet<>();static {SIMPLE_TYPE_SET.add(String.class);SIMPLE_TYPE_SET.add(Byte.class);SIMPLE_TYPE_SET.add(Short.class);SIMPLE_TYPE_SET.add(Character.class);SIMPLE_TYPE_SET.add(Integer.class);SIMPLE_TYPE_SET.add(Long.class);SIMPLE_TYPE_SET.add(Float.class);SIMPLE_TYPE_SET.add(Double.class);SIMPLE_TYPE_SET.add(Boolean.class);SIMPLE_TYPE_SET.add(Date.class);SIMPLE_TYPE_SET.add(Class.class);SIMPLE_TYPE_SET.add(BigInteger.class);SIMPLE_TYPE_SET.add(BigDecimal.class);}

TypeAliasRegistry是一个类型别名注册表,其内部使用 typeAliases变量维护类型的别名与类型的对应关系。有了这个注册表,我们就可以在很多场合使用类型的别名来指代具体的类型。

public class TypeAliasRegistry {private final Map<String, Class<?>> typeAliases = new HashMap<>();public TypeAliasRegistry() {registerAlias("string", String.class);registerAlias("byte", Byte.class);registerAlias("long", Long.class);registerAlias("short", Short.class);registerAlias("int", Integer.class);registerAlias("integer", Integer.class);registerAlias("double", Double.class);registerAlias("float", Float.class);registerAlias("boolean", Boolean.class);registerAlias("byte[]", Byte[].class);registerAlias("long[]", Long[].class);registerAlias("short[]", Short[].class);registerAlias("int[]", Integer[].class);registerAlias("integer[]", Integer[].class);registerAlias("double[]", Double[].class);registerAlias("float[]", Float[].class);registerAlias("boolean[]", Boolean[].class);registerAlias("_byte", byte.class);registerAlias("_long", long.class);registerAlias("_short", short.class);registerAlias("_int", int.class);registerAlias("_integer", int.class);registerAlias("_double", double.class);registerAlias("_float", float.class);registerAlias("_boolean", boolean.class);registerAlias("_byte[]", byte[].class);registerAlias("_long[]", long[].class);registerAlias("_short[]", short[].class);registerAlias("_int[]", int[].class);registerAlias("_integer[]", int[].class);registerAlias("_double[]", double[].class);registerAlias("_float[]", float[].class);registerAlias("_boolean[]", boolean[].class);registerAlias("date", Date.class);registerAlias("decimal", BigDecimal.class);registerAlias("bigdecimal", BigDecimal.class);registerAlias("biginteger", BigInteger.class);registerAlias("object", Object.class);registerAlias("date[]", Date[].class);registerAlias("decimal[]", BigDecimal[].class);registerAlias("bigdecimal[]", BigDecimal[].class);registerAlias("biginteger[]", BigInteger[].class);registerAlias("object[]", Object[].class);registerAlias("map", Map.class);registerAlias("hashmap", HashMap.class);registerAlias("list", List.class);registerAlias("arraylist", ArrayList.class);registerAlias("collection", Collection.class);registerAlias("iterator", Iterator.class);registerAlias("ResultSet", ResultSet.class);}

TypeHandlerRegistry 是这三个注册表中最为核心的一个,数据类型和相关处理器的对应关系就是由它维护的。

public final class TypeHandlerRegistry {private final Map<JdbcType, TypeHandler<?>>  jdbcTypeHandlerMap = new EnumMap<>(JdbcType.class);private final Map<Type, Map<JdbcType, TypeHandler<?>>> typeHandlerMap = new ConcurrentHashMap<>();private final TypeHandler<Object> unknownTypeHandler;private final Map<Class<?>, TypeHandler<?>> allTypeHandlersMap = new HashMap<>();private static final Map<JdbcType, TypeHandler<?>> NULL_TYPE_HANDLER_MAP = Collections.emptyMap();private Class<? extends TypeHandler> defaultEnumTypeHandler = EnumTypeHandler.class;/*** The default constructor.*/public TypeHandlerRegistry() {this(new Configuration());}/*** The constructor that pass the MyBatis configuration.** @param configuration a MyBatis configuration* @since 3.5.4*/public TypeHandlerRegistry(Configuration configuration) {this.unknownTypeHandler = new UnknownTypeHandler(configuration);register(Boolean.class, new BooleanTypeHandler());register(boolean.class, new BooleanTypeHandler());register(JdbcType.BOOLEAN, new BooleanTypeHandler());register(JdbcType.BIT, new BooleanTypeHandler());register(Byte.class, new ByteTypeHandler());register(byte.class, new ByteTypeHandler());register(JdbcType.TINYINT, new ByteTypeHandler());register(Short.class, new ShortTypeHandler());register(short.class, new ShortTypeHandler());register(JdbcType.SMALLINT, new ShortTypeHandler());register(Integer.class, new IntegerTypeHandler());register(int.class, new IntegerTypeHandler());register(JdbcType.INTEGER, new IntegerTypeHandler());register(Long.class, new LongTypeHandler());register(long.class, new LongTypeHandler());register(Float.class, new FloatTypeHandler());register(float.class, new FloatTypeHandler());register(JdbcType.FLOAT, new FloatTypeHandler());register(Double.class, new DoubleTypeHandler());register(double.class, new DoubleTypeHandler());register(JdbcType.DOUBLE, new DoubleTypeHandler());}

注解类

Alias:使用该注解可以给类设置别名,设置后,别名和类型的映射关系便存入TypeAliasRegistry中;
MappedJdbcTypes:有时我们想使用自己的处理器来处理某些JDBC 类型,只需创建 BaseTypeHandler 的子类,然后在上面加上该注解,声明它要处理的JDBC类型即可;
MappedTypes:有时我们想使用自己的处理器来处理某些Java类型,只需创建BaseTypeHandler的子类,然后在上面加上该注解,声明它要处理的 Java类型即可。

枚举类

JdbcType:在 Enum中定义了所有的 JDBC类型,类型来源于java.sql.Types。

public enum JdbcType {ARRAY(Types.ARRAY),BIT(Types.BIT),TINYINT(Types.TINYINT),SMALLINT(Types.SMALLINT),INTEGER(Types.INTEGER),BIGINT(Types.BIGINT),FLOAT(Types.FLOAT),REAL(Types.REAL),DOUBLE(Types.DOUBLE),NUMERIC(Types.NUMERIC)
....
}
http://www.zhongyajixie.com/news/16905.html

相关文章:

  • 怎么查看网站域名企业网站排名优化价格
  • 佛山网站策划公司目前较好的crm系统
  • 如何做自己官方网站百度做广告费用
  • 苗木网站模板互联网宣传方式有哪些
  • 动态网站制作教程百度号码认证平台官网首页
  • 哪些网站做推广营销培训内容有哪些
  • 网站做好了怎么办爱站网关键词挖掘工具熊猫
  • javaee做的是网站吗李江seo
  • 政府网站群建设sem是什么意思职业
  • 深圳建设局网站投诉电话网站推广优化服务
  • 咨询公司成本费用包括哪些内容网站seo设计
  • 国家建设材料检测网站免费推广
  • 网站开发发展方向北京营销型网站
  • 查做空运磁检的网站爱站网关键词查询工具
  • 创业网站模板免费下载直播代运营公司
  • 中国铁道工程建设协会查证网站如何建立企业网站
  • 佛山专业网站制作百度域名购买
  • 医院网站可信认证必须做吗专门做排名的软件
  • python做网站 要学多久360摄像头海澳門地区限制解除
  • 做外贸的如何上国外网站seo还有前景吗
  • 合肥网站建设开发电话郑州本地seo顾问
  • cad外包网站网推什么平台好用
  • 网站图片上传不上去怎么办产品软文范例
  • 网站建设公司的职责百度上广告怎么搞上去的
  • 可以做免费的网站吗吉林关键词排名优化软件
  • 让别人访问自己做的网站烘焙甜点培训学校
  • 内销网站要怎么做seo描述是什么意思
  • 绍兴柯桥建设局网站百度站长提交
  • gif网站banner怎么做免费培训seo网站
  • 哪个网站的域名到期直接注册表电商软文范例300字