iBatis的扩展组件主要有TypeHandlerCallback、CacheController、DataSourceFactory、TransactionConfig。其中TypeHandlerCallback可以实现自定义的类型处理逻辑,以便处理非标准数据库、驱动程序和(或)数据类型。
场景举例
有如下数据表,请注意字段status的类型及含义:
CREATE DATABASE ibatis;
USE test_ibatis;
CREATE TABLE person
(
id INT NOT NULL AUTO_INCREMENT,
name VARCHAR(20) NOT NULL comment '姓名',
status TINYINT NOT NULL comment '状态(1可用,-1不可用,0默认)',
PRIMARY KEY (id)
)
ENGINE=InnoDB
DEFAULT CHARACTER SET=utf8;
对应的实体模型类里将status定义为枚举型,如:
public class Person {
private int id;
private String name;
private Status status; // 注意这里
// getters and setters...
}
注:如果将status定义为整型,虽然与表中的字段类型一致了,但在赋值时setStatus(int status),只能传数字,不易被理解,没有人会明白应该传什么值,1或-1又代表了什么含义,且易产生脏数据,比如有意无意间会传321。
用枚举型给status赋值,既直观又限定范围。如:
......
Person person = new Person();
person.setName("yumin");
person.setStatus(Status.AVAILABLE);; // 注意这里
boolean result = DAO.insert(person);
.......
代码里出现的枚举型Status,可以这样进行定义:
public enum Status {
// 默认0, 可用1, 不可用-1
DEFAULT(0), AVAILABLE(1), UNAVAILABLE(-1);
}
但按上述做法执行写入操作时,发生了如下异常:
Caused by: java.sql.SQLException:
Incorrect integer value: 'AVAILABLE' for column 'status' at row 1
类型不匹配,AVAILABLE用在了整型字段status。
异常出现的症结在于,数据表里的字段是用整型存储这没问题,但Java代码里应该用枚举型会更友好,两者间在数据类型上就存在一定的矛盾,即"javaType=enum"而"jdbcType=integer"。这时就需用到TypeHandlerCallback,通过实现该接口来处理中间的转换。
题外话:还有一种做法,定义Person类时,定义两个status,第一个status为整型,但取消setStatus方法,只负责在数据表存储时用,另一个叫status2为枚举型,负责与外部交互,赋值时只能用status2,内部将status2转换为status,这样既能保证友好又能通过转换保持类型的一致。但暂时让我们看看若通过iBatis的扩展应该如何实现。
实例演示
TypeHandlerCallback接口,下面是它的源代码:
public abstract interface TypeHandlerCallback {
public abstract void setParameter(ParameterSetter setter, Object object)
throws SQLException;
public abstract Object getResult(ResultGetter getter) throws SQLException;
public abstract Object valueOf(String string);
}
接下来我们一起Step-by-step操作 ——
第一步:基于TypeHandlerCallback实现类
/**
*
*/
package me.yumin.java.ibatis.handler;
import com.ibatis.sqlmap.client.extensions.ParameterSetter;
import com.ibatis.sqlmap.client.extensions.ResultGetter;
import com.ibatis.sqlmap.client.extensions.TypeHandlerCallback;
import java.sql.SQLException;
import java.sql.Types;
import me.yumin.java.ibatis.enumtype.Status;
/**
* @author yumin
*
*/
public class StatusHandler implements TypeHandlerCallback {
@Override
public void setParameter(ParameterSetter setter, Object parameter)
throws SQLException {
/*
* 在sqlMap中配parameterMap的属性typeHandler
* 和sqlMapConfig中配全局typeHandler时才会触发
*/
if (null == parameter) {
setter.setNull(Types.INTEGER); // 若没有传值则null,表字段不允许则异常
} else {
setter.setInt(((Status) parameter).getValue());
}
}
@Override
public Object getResult(ResultGetter getter) throws SQLException {
/*
* 仅在sqlMap中配置resultMap的属性typeHandler
* 和在sqlMapConfig中配全局typeHandler才会触发
*/
Object result = null;
//if (!getter.wasNull() && null != getter.getObject()) {
// 上面有问题,修复如下.wasNull是判断前一个字段是否为null
if (null != getter.getObject()) {
result = getStatus(getter.getInt());
}
return result;
}
@Override
public Object valueOf(String string) {
/*
* 处理属性或参数为null情况
* 入参即为配置项nullValue
*/
Object result = null;
int integer = 0;
if (null != string && 0 < string.length()) {
try {
integer = Integer.parseInt(string);
} catch (NumberFormatException e) {
e.printStackTrace();
}
}
result = getStatus(integer);
return result;
}
/**
*
* @param value
* @return
*/
private Object getStatus(int value) {
Object result = null;
for (Status status : Status.values()) {
if (value == status.getValue()) {
result = status;
break;
}
}
return result;
}
}
第二步:在sqlMap中指定属性typeHandler
所有完整的sqlMap配置文件如下:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE sqlMap PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN" "http://ibatis.apache.org/dtd/sql-map-2.dtd">
<sqlMap namespace="Person">
<typeAlias alias="Person" type="me.yumin.java.ibatis.domain.Person" />
<parameterMap class="Person" id="person">
<parameter property="name" />
<parameter property="status" typeHandler="me.yumin.java.ibatis.handler.StatusHandler" />
<!-- 若没有使用parameterMap且未给属性指定typeHandler
则在给SQL传值时不会调Handler中的setParameter方法 -->
</parameterMap>
<resultMap class="Person" id="person">
<result property="id" column="id" />
<result property="name" column="name" />
<result property="status" column="status" typeHandler="me.yumin.java.ibatis.handler.StatusHandler" nullValue="0" />
<!-- 同上若没用resultMap且未给属性指定typeHandler
则在返回表数据时不会调Handler中的getResult方法 -->
</resultMap>
<insert id="insert" parameterMap="person">
<![CDATA[
INSERT INTO person (name, status) VALUES (?, ?)
]]>
<selectKey keyProperty="id" resultClass="java.lang.Integer">
SELECT LAST_INSERT_ID()
</selectKey>
</insert>
<select id="query" parameterClass="java.lang.Integer" resultMap="person">
<![CDATA[
SELECT id, name, status FROM person WHERE id=#id#
]]>
</select>
</sqlMap>
主要处理过程是,因在sqlMap中给属性配置了typeHandler,所以在写或改数据前,先调用setParameter方法,再生成SQL,这时已将枚举型转换为整型;在读取数据后映射类时,会调用getResult方法,将整型转换为枚举型。
完整的示例请见附件,导入到IDE即可运行,IBatisTest是测试用例。
上述实例满足了一开始的需求,即Java类中将属性定义为枚举型,在存储时仍用整型,既友好直观地让使用者给类赋值又满足了存储需要。应用场景还有很多,如:对所有字符串型数据先压缩再存储,则可在sqlMapConfig中定义全局typeHandler,凡"javaType=java.lang.String"时,都通过该扩展在写之前先压缩,读取后先解压再返回。
若将Handler定义在sqlMapConfig,则该typeHandler是全局可用的。
全局typeHandler定义:
<sqlMapConfig>
......
<typeHandler javaType="package.Type" callback="package.Handler" />
......
</sqlMapConfig>
分享到:
相关推荐
下面我们将详细探讨iBATIS在.NET中的使用方法,以及如何利用提供的文件进行实践。 首先,了解iBATIS的基本概念。iBATIS是一个轻量级框架,它的核心功能是动态SQL映射,允许开发者编写SQL语句并将其封装到XML配置...
要开始使用 Ibatis,首先需要从官方网站下载最新版本的 ibatis jar 包,以及 log4j 日志框架的 jar 包。然后,在Java项目中添加这些库,配置log4j.properties以开启SQL日志输出。接着,新建主配置文件sqlMapConfig....
以下是对iBATIS简易使用的详细解释: 1. **环境准备**: - **jar文件**:iBATIS框架运行需要依赖一些库文件,包括`log4j`用于日志记录,`ibatis`核心库,以及`jdbc`驱动,这些都需要添加到项目的类路径中。 - **...
标题 "ibatis类型" 暗示我们讨论的是关于iBATIS这个持久层框架的一些特定类型或组件。iBATIS是Java开发中的一个流行数据库访问框架,它允许开发者将SQL语句直接集成到XML配置文件中,实现了SQL与Java代码的分离,...
这个压缩包包含了iBATIS的相关使用文档和安装包,是学习和使用iBATIS的重要参考资料。 《iBATIS-SqlMaps-2.pdf》可能是关于iBATIS SQL映射器的详细指南,它会介绍如何编写SQL Map配置文件,这些文件定义了数据库...
Ibatis对枚举类型的原生支持可能不如实体类那样直观,但通过一些策略,我们可以实现枚举与数据库字段之间的映射。以下将详细解释如何在Ibatis中处理枚举类型。 首先,我们需要定义枚举类。枚举类通常包含若干枚举...
以及ibatis的概述、如何开始使用ibatis、构建SqlSessionFactory的方法(包括通过XML和不使用XML的方式)、获取SqlSession的过程、探索映射SQL语句的方法、命名空间的注意事项、作用域与生命周期的解释、mapper配置...
Ibatis提供了多种方式来实现映射,如自动类型匹配、自定义类型处理器、复杂关联映射等。 7. **缓存机制**:Ibatis内置了本地缓存和二级缓存,可以提高数据读取速度。本地缓存作用于单个SqlSession,而二级缓存则...
在这个"iBatis Web用法实例"中,我们将深入探讨如何在Web项目中集成并使用iBatis,以及相关的最佳实践。 1. **iBatis 概述**: iBatis 作为轻量级的ORM(对象关系映射)框架,它的核心思想是将SQL与Java代码分离,...
**使用iBatis进行数据库操作的核心概念** iBatis是一个优秀的持久层框架,它支持定制化SQL、存储过程以及高级映射。iBatis避免了几乎所有的JDBC代码和手动设置参数以及获取结果集。iBatis可以被看作是一个半自动化 ...
《iBatis 使用手册》是一份详尽的开发资源,涵盖了iBatis框架的各个方面,包括iBatis的开发指南、SQL Maps的使用以及入门教程。iBatis是一款优秀的持久层框架,它允许Java开发者将SQL语句与Java代码分离,实现数据...
本案例将聚焦于如何使用Ibatis操作两个有关系的表。 Ibatis的核心思想是将SQL语句写在XML配置文件中,通过映射关系将Java对象与数据库中的记录对应起来。在处理两个有关系的表时,Ibatis提供了多种策略,如一对一、...
5. **类型处理器扩展**:iBATIS3允许开发者自定义类型处理器,用于处理不同类型之间的转换,这为处理非标准数据类型提供了便利。 6. **插件架构**:iBATIS3支持插件架构,开发者可以通过编写插件来扩展框架的功能,...
### ibatis中输入输出各种类型的参数分析及#与$区别 #### iBatis简介与特点 iBatis作为一款轻量级的Java持久层框架,以其简洁、灵活的特点,在众多框架中占据一席之地。相较于知名的Hibernate框架,iBatis在实现上...
12.2 使用自定义类型处理器 217 12.2.1 实现自定义类型处理器 217 12.2.2 创建TypeHandlerCallback 218 12.2.3 注册TypeHandlerCallback以供使用 221 12.3 使用CacheController 222 12.3.1 创建CacheController 223 ...
IBATIS,一个由iBATIS公司开发的开源持久层框架,是Java世界中广泛使用的数据访问接口(DAO)工具。它允许开发者将SQL语句直接写在XML配置文件中,实现了SQL与Java代码的分离,提高了开发效率和数据库移植性。本篇将...
自定义类型处理器需要实现`org.apache.ibatis.type.TypeHandler`接口,并重写`setNonNullParameter`、`getNullableResult`和`getResultFromCursor`方法。 ```java public class CustomTypeHandler implements ...
Ibatis 是一款轻量级的Java持久层框架,它允许开发者将SQL语句与Java代码分离,从而使得数据库访问更加灵活、易于维护。本篇文章将深入探讨Ibatis的核心概念、最佳实践以及与其他框架如Struts和Spring的整合。 1. ...
在实际项目中,你需要将自定义的类型处理器注册到MyBatis的配置中,以便MyBatis在处理相关字段时能够找到并使用这个处理器。注册可以通过XML配置文件或Java配置类来完成。 总结来说,MyBatis的自定义类型处理器Type...