ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Mybatis --- 自定义类型转换

2019-07-21 19:07:30  阅读:320  来源: 互联网

标签:类型转换 return 自定义 rs throws columnIndex SQLException Mybatis public


Mybatis — 自定义类型转换

前言

在进行数据库增删改查的时候,因为实体类类型数据库类型不兼容,或者说Mybatis自带的类型转换不够用了,这时候就要自己手动操作了,最常见的就是素组的的操作,根据原有的进行扩展,这样就不用定义一个数组属性,就写一次转换方法。

接口

原生接口org.apache.ibatis.type.TypeHandler<T>

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;
  /**
  用来将查询结果转换成指定实体类,依旧是返回结果列的顺序号,
  只是使用了不同的返回接收接口,写过原生jdbc的应该有印象
  */
  T getResult(CallableStatement cs, int columnIndex) throws SQLException;

}

也可以使用继承的方式扩展,我这里是直接继承 org.apache.ibatis.type.TypeReference<T>,这个可以省很多事情

public abstract class BaseTypeHandler<T> extends TypeReference<T> implements TypeHandler<T> {

  protected Configuration configuration;

  public void setConfiguration(Configuration c) {
    this.configuration = c;
  }

  public void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException {
    if (parameter == null) {
      if (jdbcType == null) {
        throw new TypeException("JDBC requires that the JdbcType must be specified for all nullable parameters.");
      }
      try {
        ps.setNull(i, jdbcType.TYPE_CODE);
      } catch (SQLException e) {
        throw new TypeException("Error setting null for parameter #" + i + " with JdbcType " + jdbcType + " . " +
        		"Try setting a different JdbcType for this parameter or a different jdbcTypeForNull configuration property. " +
        		"Cause: " + e, e);
      }
    } else {
      setNonNullParameter(ps, i, parameter, jdbcType);
    }
  }

  public T getResult(ResultSet rs, String columnName) throws SQLException {
    T result = getNullableResult(rs, columnName);
    if (rs.wasNull()) {
      return null;
    } else {
      return result;
    }
  }

  public T getResult(ResultSet rs, int columnIndex) throws SQLException {
    T result = getNullableResult(rs, columnIndex);
    if (rs.wasNull()) {
      return null;
    } else {
      return result;
    }
  }

  public T getResult(CallableStatement cs, int columnIndex) throws SQLException {
    T result = getNullableResult(cs, columnIndex);
    if (cs.wasNull()) {
      return null;
    } else {
      return result;
    }
  }

  public abstract void setNonNullParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException;

  public abstract T getNullableResult(ResultSet rs, String columnName) throws SQLException;

  public abstract T getNullableResult(ResultSet rs, int columnIndex) throws SQLException;

  public abstract T getNullableResult(CallableStatement cs, int columnIndex) throws SQLException;

}

可以看到已经帮我们把结果或者查询参数为空的情况处理好了,我们只需要把 不为空的情况补充完整即可。

代码实现

我这里是实现了一个将'1,2,3,4' 与 ['1','2','3','4']之间的转换

//这个注解定义的是JdbcType类型,这里的类型不可自己随意定义,必须要是枚举类org.apache.ibatis.type.JdbcType所枚举的数据类型
@MappedJdbcTypes({JdbcType.VARCHAR})
//这里定义的是JavaType的数据类型,描述了哪些Java类型可被拦截
@MappedTypes({List.class})
public class StringListTypeHandler extends BaseTypeHandler<List<String>> {
	private final static Logger logger = Logger.getLogger(StringListTypeHandler.class);

	public StringListTypeHandler(){
		logger.info("initialization StringListTypeHandler ok");
		System.out.println("initialization StringListTypeHandler ok");
	}

	@Override
	public void setNonNullParameter(PreparedStatement ps, int i, List<String> parameter, JdbcType jdbcType) throws SQLException {
		//这个我使用的是 commons.lang3 的包,用来添加 ',' 也可以直接 toString() 后去掉两端的 [] 即可
		ps.setString(i, StringUtils.join(parameter,","));
	}

	@Override
	public List<String> getNullableResult(ResultSet rs, String columnName) throws SQLException {
		String str = rs.getString(columnName);
		if (rs.wasNull())
			return null;
		//解决增加异常,这样做是因为直接放入时操作的是原素组,导致不能增删操作,所以要重新创建一个
		return new ArrayList<String>(Arrays.asList(str.split(",")));
	}

	@Override
	public List<String> getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
		String str = rs.getString(columnIndex);
		if (rs.wasNull())
			return null;

		return new ArrayList<String>(Arrays.asList(str.split(",")));
	}

	@Override
	public List<String> getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
		String str = cs.getString(columnIndex);
		if (cs.wasNull())
			return null;

		return new ArrayList<String>(Arrays.asList(str.split(",")));
	}
}

这样一来,工具就完成了。需要注意的是,如果没有添加 MappedJdbcTypes MappedTypes的话,要在对应的位置声明相应的类型

配置

先说下我使用的是添加了 MappedJdbcTypes MappedTypes注解,所以在spring或者mybatis配置文件里不做处理,即不额外增加配置也是可以生效的,至少我使用的版本是生效的 mybatis-3.2.3.jar mybatis-spring-1.3.1.jar,我猜测,要是没有配置注解的话或许不会生效。都配置上也不会报错,如果报错了,就得优先查看这个,比如没有找到或者加载类失败

在没有mybatis配置文件的情况下,直接配置在spring或者其他情况下,把类手动初始化,然后配置到SqlSessionFactory

	<bean id="intArrayTypeHandler" class="com.ssm.common.model.utils.IntArrayTypeHandler"/>
    <bean id="stringArrayTypeHandler" class="com.ssm.common.model.utils.StringArrayTypeHandler"/>
    <bean id="stringListTypeHandler" class="com.ssm.common.model.utils.StringListTypeHandler"/>

	<!-- 配置 SqlSessionFactory -->
	<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
		<property name="dataSource" ref="dataSource" />
		<!--typeHandler注入-->
		<!-- 这里是要配置多个的情况下,如果单个的话直接在 property 标签里 ref 即可 -->
        <property name="typeHandlers">
        	<list>
        		<ref bean="intArrayTypeHandler"/>
        		<ref bean="stringArrayTypeHandler"/>
        		<ref bean="stringListTypeHandler"/>
        	</list>
        </property>
	</bean>

如果有mybatis配置文件,那么直接添加一个在 TypeHandleys标签

<configuration>
	<TypeHandleys>
		<!-- 如果类里有注释的话这里就可以省去,如果没有建议是加上,即使不报错,也方便自己或者其他人查看 -->
		<typeHandler handler="com.ssm.common.model.utils.StringListTypeHandler" javaType="java.util.List" jdbcType="VARCHAR" />
	</TypeHandleys>
</configuration>

使用

第一种,在mapper.xml文件里

	<!-- 如果前两出都没有配置 类型的话,这里就要加上对应的类型 -->
	<update id="update">
		update table set cloum=#{cloum,typeHandler=com.ssm.common.model.utils.StringListTypeHandler} where id=#{id}
	</update>
	
	<!-- 也可以配置在查询和结果映射里,另外只有查询参数可以直接写在 sql 语句里,返回结果必须使用映射,同名且没有用到自定义转换类的或许可以不用配置,没有在具体测试 -->
	<parameterMap type="" id="">
		<parameter property="" javaType="" jdbcType="" typeHandler=""/>
	</parameterMap>
	<resultMap type="" id="">
		<result column="" property="" javaType="" jdbcType="" typeHandler=""/>
	</resultMap>

第二种,注解

mapper.java 里用注解的方式实现的查询参数直接按#{cloum,typeHandler=com.ssm.common.model.utils.StringListTypeHandler}这样的形式写上就行,这里要说的都是查询

	@Select("select * from table where cloum=#{cloum,typeHandler=com.ssm.common.model.utils.StringListTypeHandler}")
	@Results({、
		@Result(column="cloum",property="cloum",typeHandler=StringListTypeHandler.class)
	})
	public List<Role> select();

注意事项

  1. 注意:在这3个地方,至少有一处有声明类型,不然可能会报错
  2. 查询没报错,但是返回结果为 null ,先确定是否加载了,然后再看看是否没有声明 javaTypejdbcType 导致的
  3. jdbcType / javaType 不匹配或者类似的,看下查询语句里是否声明了 使用哪个转换类

标签:类型转换,return,自定义,rs,throws,columnIndex,SQLException,Mybatis,public
来源: https://blog.csdn.net/a12331244/article/details/96742532

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有