MyBatis数据类型转换,默认情况下MyBatis已经帮我们完成了很多的数据类型的转换,一般情况下我们直接使用即可,下面大概介绍一下
一 Java日期类型和Jdbc字符串类型转换
在做开发时,我们经常会遇到这样一些问题,比如我有一个Java中的Date数据类型,我想将之存到数据库的时候存成一个1970年至今的毫秒数,怎么实现?
就是我直接向数据库写数据,要写的是一个Date对象,但是写到数据库之后这个Date对象就变成了Date对象所描述的时间到1970年的秒数了,然后当我从数据库读取这个秒数之后,系统又会自动帮我将这个秒数转为Date对象,就是这样两个需求.
1.新增数据库字段
2.持久化类中代码
public class User implements java.io.Serializable{
private static final long serialVersionUID = 1L;
private Integer user_id;
private String account;
private String password;
private String user_name;
private Integer status;
private Date login_time;
private String ip;
private Integer fk_role_id;
//注意这里是java.util.Date类型
private Date create_time;
}
3.自定义typeHandler继承自BaseTypeHandler
自定义typeHandler我们有两种方式:
- 实现TypeHandler接口
- 简化的写法就是继承自BaseTypeHandler类
package com.shxt.type;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Date;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
public class MyDateTypeHandler extends BaseTypeHandler {
@Override
public Date getNullableResult( ResultSet rs , String columnName ) throws SQLException {
return this.getDate(rs.getLong(columnName));
}
@Override
public Date getNullableResult( ResultSet rs , int columnIndex ) throws SQLException {
return this.getDate(rs.getLong(columnIndex));
}
@Override
public Date getNullableResult( CallableStatement cs , int columnIndex ) throws SQLException {
return this.getDate(cs.getLong(columnIndex));
}
@Override
public void setNonNullParameter( PreparedStatement ps , int index , Date parameter , JdbcType jdbcType )
throws SQLException {
ps.setString(index, String.valueOf(parameter.getTime()));
}
private Date getDate(Long columnValue){
if(columnValue==null){
return null;
}
return new Date(columnValue);
}
}
4.在Mapper中进行配置
自定义好了typeHandler之后,接下来我们需要在UserMapper.xml中进行简单的配置,首先我们可以像上文说的,配置resultMap,如下:
user_id,account,password,user_name,status,login_time,ip,fk_role_id,create_time
5.查询数据
6.测试代码
@Test
public void 数据类型转换(){
SqlSession sqlSession = null;
try {
sqlSession = MyBatisUtils.getSqlSession();
User u1 = sqlSession.selectOne(UserDao.class.getName()+".load",-888);
System.out.println("第一次查询:"+u1);
} finally {
MyBatisUtils.closeSqlSession(sqlSession);
}
}
7.控制台运行结果
DEBUG [main] - ==> Preparing: SELECT user_id,account,password,user_name,status,login_time,ip,fk_role_id,create_time FROM sys_user WHERE user_id=?
DEBUG [main] - ==> Parameters: -888(Integer)
TRACE [main] - <== Columns: user_id, account, password, user_name, status, login_time, ip, fk_role_id, create_time
TRACE [main] - <== Row: -888, admin, admin, 悟空, 1, 2017-07-30 09:50:47.0, , -100, 1504618580
DEBUG [main] - <== Total: 1
第一次查询:User [user_id=-888, account=admin, password=admin, user_name=悟空, status=1, login_time=Sun Jul 30 09:50:47 CST 2017, ip=, fk_role_id=-100, create_time=Sun Jan 18 17:56:58 CST 1970]
create_time=Sun Jan 18 17:56:58 CST 1970 将字符串转换为了日期类型
8.添加数据映射文件
这种方式有一个缺点那就是只适用于查询操作,即在查询的过程中系统会启用我们自定义的typeHandler,会将秒数转为Date对象,但是在插入的时候却不会启用我们自定义的typeHandler,想要在插入的时候启用自定义的typeHandler,需要我们在insert节点中简单配置一下
INSERT INTO
sys_user
(account,password,user_name,create_time)
VALUES
(#{account},#{password},#{user_name},
#{create_time,javaType=Date,jdbcType=VARCHAR,typeHandler=com.shxt.type.MyDateTypeHandler})
或者配置如下
INSERT INTO
sys_user
(account,password,user_name,create_time)
VALUES
(#{account},#{password},#{user_name},
#{create_time,typeHandler=com.shxt.type.MyDateTypeHandler})
9.测试代码
@Test
public void 添加方式1(){
SqlSession sqlSession = null;
try {
sqlSession = MyBatisUtils.getSqlSession();
User user = new User();
user.setAccount("tangseng");
user.setPassword("123");
user.setUser_name("唐僧");
user.setCreate_time(new Date());
sqlSession.insert(UserDao.class.getName()+".add02", user);
sqlSession.commit();
}catch (Exception ex) {
ex.printStackTrace();
} finally {
MyBatisUtils.closeSqlSession(sqlSession);
}
}
二 List< String >类型和Jdbc字符串的转换
1.准备的SQL语句
CREATE TABLE `person` (
`id` int(11) NOT NULL AUTO_INCREMENT ,
`hobby` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL ,
PRIMARY KEY (`id`)
)
ENGINE=InnoDB
DEFAULT CHARACTER SET=utf8 COLLATE=utf8_general_ci
AUTO_INCREMENT=1
ROW_FORMAT=DYNAMIC
;
2.新建持久化类
public class Person {
private Integer id;
private List hobbyList;
public Integer getId() {
return this.id;
}
public void setId( Integer id ) {
this.id = id;
}
public List getHobbyList() {
return this.hobbyList;
}
public void setHobbyList( List hobbyList ) {
this.hobbyList = hobbyList;
}
@Override
public String toString() {
return "Person [id=" + this.id + ", hobbyList=" + this.hobbyList + "]";
}
}
3.自定义处理类型
package com.shxt.type;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.List;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
public class MyListTypeHandler extends BaseTypeHandler> {
@Override
public List getNullableResult( ResultSet rs , String columnName ) throws SQLException {
return this.getList(rs.getString(columnName));
}
@Override
public List getNullableResult( ResultSet rs , int columnIndex ) throws SQLException {
return this.getList(rs.getString(columnIndex));
}
@Override
public List getNullableResult( CallableStatement cs , int columnIndex ) throws SQLException {
return this.getList(cs.getString(columnIndex));
}
@Override
public void setNonNullParameter( PreparedStatement ps , int index , List parameter , JdbcType jdbcType )
throws SQLException {
//1.List集合转字符串
StringBuffer sb = new StringBuffer();
for (String value : parameter) {
sb.append(value).append(",");
}
//2.设置给ps
ps.setString(index, sb.toString().substring(0, sb.toString().length() - 1));
}
private List getList(String columnValue){
if (columnValue == null) {
return null;
}
return Arrays.asList(columnValue.split(","));
}
}
4.新建映射文件
5.测试代码
@Test
public void 查询02(){
SqlSession sqlSession = null;
try {
sqlSession = MyBatisUtils.getSqlSession();
Person p = sqlSession.selectOne(Person.class.getName()+".load",1);
System.out.println(p);
} finally {
MyBatisUtils.closeSqlSession(sqlSession);
}
}
6.控制台运行结果
DEBUG [main] - ==> Preparing: SELECT id,hobby FROM person WHERE id=?
DEBUG [main] - ==> Parameters: 1(Integer)
TRACE [main] - <== Columns: id, hobby
TRACE [main] - <== Row: 1, basketball,football,music
DEBUG [main] - <== Total: 1
Person [id=1, hobbyList=[basketball, football, music]]
7.添加数据映射文件
INSERT INTO
person
(hobby)
VALUES
(
#{hobbyList,javaType=java.util.List,jdbcType=VARCHAR,typeHandler=com.shxt.type.MyListTypeHandler}
)
8.测试代码
@Test
public void 添加方式02(){
SqlSession sqlSession = null;
try {
sqlSession = MyBatisUtils.getSqlSession();
List hobbyList = new ArrayList();
hobbyList.add("music");
hobbyList.add("book");
Person p = new Person();
p.setHobbyList(hobbyList);
sqlSession.insert(Person.class.getName()+".add", p);
sqlSession.commit();
}catch (Exception ex) {
ex.printStackTrace();
} finally {
MyBatisUtils.closeSqlSession(sqlSession);
}
}
9.控制台运行结果
DEBUG [main] - ==> Preparing: INSERT INTO person (hobby) VALUES ( ? )
DEBUG [main] - ==> Parameters: music,book(String)
DEBUG [main] - <== Updates: 1
三 Java 数组和Jdbc字符串的转换
该着上面的
List
1.自定义类型
package com.shxt.type;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
public class MyArrayTypeHander extends BaseTypeHandler {
/**
* 获取数据结果集时把数据库类型转换为对应的Java类型
* @param rs 当前的结果集
* @param columnName 当前的字段名称
* @return 转换后的Java对象
* @throws SQLException
*/
@Override
public String[] getNullableResult( ResultSet rs , String columnName ) throws SQLException {
return this.getStringArray(rs.getString(columnName));
}
/**
* 通过字段位置获取字段数据时把数据库类型转换为对应的Java类型
* @param rs 当前的结果集
* @param columnIndex 当前字段的位置
* @return 转换后的Java对象
* @throws SQLException
*/
@Override
public String[] getNullableResult( ResultSet rs , int columnIndex ) throws SQLException {
return this.getStringArray(rs.getString(columnIndex));
}
/**
* 调用存储过程后把数据库类型的数据转换为对应的Java类型
* @param cs 当前的CallableStatement执行后的CallableStatement
* @param columnIndex 当前输出参数的位置
* @return
* @throws SQLException
*/
@Override
public String[] getNullableResult( CallableStatement cs , int columnIndex ) throws SQLException {
return this.getStringArray(cs.getString(columnIndex));
}
/**
* 把Java类型参数转换为对应的数据库类型
* @param ps 当前的PreparedStatement对象
* @param index 当前参数位置
* @param parameter 当前参数的Java对象
* @param jdbcType 当前参数的数据库类型
* @throws SQLException
*/
@Override
public void setNonNullParameter( PreparedStatement ps , int index , String[] parameter , JdbcType jdbcType )
throws SQLException {
// 由于BaseTypeHandler中已经把parameter为null的情况做了处理,所以这里我们就不用在判断parameter是否为空,直接用就可以了
StringBuffer result = new StringBuffer();
for (String value : parameter) {
result.append(value).append(",");
}
result.deleteCharAt(result.length() - 1);
ps.setString(index, result.toString());
}
/**
* 讲"book,music"转化为数组对象
* @param columnValue
* @return
*/
private String[] getStringArray(String columnValue) {
if (columnValue == null) {
return null;
}
return columnValue.split(",");
}
}
2.映射文件代码
3.测试代码
@Test
public void 查询02(){
SqlSession sqlSession = null;
try {
sqlSession = MyBatisUtils.getSqlSession();
Person p = sqlSession.selectOne(Person.class.getName()+".load",1);
System.out.println(p);
} finally {
MyBatisUtils.closeSqlSession(sqlSession);
}
}
4.控制台运行结果
DEBUG [main] - ==> Preparing: SELECT id,hobby,flag,hobby hobbyArray FROM person WHERE id=?
DEBUG [main] - ==> Parameters: 1(Integer)
TRACE [main] - <== Columns: id, hobby, flag, hobbyArray
TRACE [main] - <== Row: 1, basketball,football,music, N, basketball,football,music
DEBUG [main] - <== Total: 1
Person [id=1, hobbyList=[basketball, football, music], flag=false, hobbyArray=[basketball, football, music]]
5.添加操作映射文件
INSERT INTO
person
(hobby,flag)
VALUES
(
#{hobbyArray,typeHandler=com.shxt.type.MyArrayTypeHander}
,
#{flag,typeHandler=com.shxt.type.MyBooleanTypeHandler}
)
6.测试代码
@Test
public void 添加方式02(){
SqlSession sqlSession = null;
try {
sqlSession = MyBatisUtils.getSqlSession();
Person p = new Person();
p.setHobbyArray(new String[]{"book","music"});
p.setFlag(true);
sqlSession.insert(Person.class.getName()+".add", p);
sqlSession.commit();
}catch (Exception ex) {
ex.printStackTrace();
} finally {
MyBatisUtils.closeSqlSession(sqlSession);
}
}
7.控制台运行结果
DEBUG [main] - ==> Preparing: INSERT INTO person (hobby,flag) VALUES ( ? , ? )
DEBUG [main] - ==> Parameters: book,music(String), Y(String)
DEBUG [main] - <== Updates: 1
Java 布尔类型和Jdbc字符串的转换
需求场景:当数据库中保存'Y'/'N',而对应bean字段的值的类型为boolean,这是就需要我们自定义类型转换器,在Mybatis执行SQL得到结果时,通过自定义类型转换器将CHAR或者VARCHAR2类型转换为boolean类型,Java代码如下:
1.自定义类型
package com.shxt.type;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
public class MyBooleanTypeHandler extends BaseTypeHandler {
private Boolean getBoolean(String flag){
Boolean bool = Boolean.FALSE;
if (flag.equalsIgnoreCase("Y")){
bool = Boolean.TRUE;
}
return bool;
}
@Override
public Boolean getNullableResult( ResultSet rs , String columnName ) throws SQLException {
return this.getBoolean(rs.getString(columnName));
}
@Override
public Boolean getNullableResult( ResultSet rs , int columnIndex ) throws SQLException {
return this.getBoolean(rs.getString(columnIndex));
}
@Override
public Boolean getNullableResult( CallableStatement cs , int columnIndex ) throws SQLException {
return this.getBoolean(cs.getString(columnIndex));
}
@Override
public void setNonNullParameter( PreparedStatement ps , int index , Boolean parameter , JdbcType jdbcType )
throws SQLException {
String flag = parameter?"Y":"N";
ps.setString(index, flag);
}
}
2.映射文件
3.测试代码
@Test
public void 查询02(){
SqlSession sqlSession = null;
try {
sqlSession = MyBatisUtils.getSqlSession();
Person p = sqlSession.selectOne(Person.class.getName()+".load",1);
System.out.println(p);
} finally {
MyBatisUtils.closeSqlSession(sqlSession);
}
}
4.控制台运行结果
DEBUG [main] - ==> Preparing: SELECT id,hobby,flag FROM person WHERE id=?
DEBUG [main] - ==> Parameters: 1(Integer)
TRACE [main] - <== Columns: id, hobby, flag
TRACE [main] - <== Row: 1, basketball,football,music, N
DEBUG [main] - <== Total: 1
Person [id=1, hobbyList=[basketball, football, music], flag=false]
5.添加操作映射文件
INSERT INTO
person
(hobby,flag)
VALUES
(
#{hobbyList,javaType=java.util.List,jdbcType=VARCHAR,typeHandler=com.shxt.type.MyListTypeHandler}
,
#{flag,typeHandler=com.shxt.type.MyBooleanTypeHandler}
)
6.控制台运行结果
DEBUG [main] - ==> Preparing: INSERT INTO person (hobby,flag) VALUES ( ? , ? )
DEBUG [main] - ==> Parameters: music,book(String), Y(String)
DEBUG [main] - <== Updates: 1
附录A : 常用java类型和jdbc类型对应表
类型处理器 | Java 类型 | JDBC 类型 |
---|---|---|
BooleanTypeHandler |
java.lang.Boolean , boolean |
数据库兼容的 BOOLEAN |
ByteTypeHandler |
java.lang.Byte , byte |
数据库兼容的 NUMERIC 或 BYTE |
ShortTypeHandler |
java.lang.Short , short |
数据库兼容的 NUMERIC 或 SHORT INTEGER |
IntegerTypeHandler |
java.lang.Integer , int |
数据库兼容的 NUMERIC 或 INTEGER |
LongTypeHandler |
java.lang.Long , long |
数据库兼容的 NUMERIC 或 LONG INTEGER |
FloatTypeHandler |
java.lang.Float , float |
数据库兼容的 NUMERIC 或 FLOAT |
DoubleTypeHandler |
java.lang.Double , double |
数据库兼容的 NUMERIC 或 DOUBLE |
BigDecimalTypeHandler |
java.math.BigDecimal |
数据库兼容的 NUMERIC 或 DECIMAL |
StringTypeHandler |
java.lang.String |
CHAR , VARCHAR |
ClobReaderTypeHandler |
java.io.Reader |
- |
ClobTypeHandler |
java.lang.String |
CLOB , LONGVARCHAR |
NStringTypeHandler |
java.lang.String |
NVARCHAR , NCHAR |
NClobTypeHandler |
java.lang.String |
NCLOB |
BlobInputStreamTypeHandler |
java.io.InputStream |
- |
ByteArrayTypeHandler |
byte[] |
数据库兼容的字节流类型 |
BlobTypeHandler |
byte[] |
BLOB , LONGVARBINARY |
DateTypeHandler |
java.util.Date |
TIMESTAMP |
DateOnlyTypeHandler |
java.util.Date |
DATE |
TimeOnlyTypeHandler |
java.util.Date |
TIME |
SqlTimestampTypeHandler |
java.sql.Timestamp |
TIMESTAMP |
SqlDateTypeHandler |
java.sql.Date |
DATE |
SqlTimeTypeHandler |
java.sql.Time |
TIME |
ObjectTypeHandler |
Any | OTHER 或未指定类型 |
EnumTypeHandler |
Enumeration Type | VARCHAR-任何兼容的字符串类型,存储枚举的名称(而不是索引) |
EnumOrdinalTypeHandler |
Enumeration Type | 任何兼容的 NUMERIC 或 DOUBLE 类型,存储枚举的索引(而不是名称)。 |
InstantTypeHandler |
java.time.Instant |
TIMESTAMP |
LocalDateTimeTypeHandler |
java.time.LocalDateTime |
TIMESTAMP |
LocalDateTypeHandler |
java.time.LocalDate |
DATE |
LocalTimeTypeHandler |
java.time.LocalTime |
TIME |
OffsetDateTimeTypeHandler |
java.time.OffsetDateTime |
TIMESTAMP |
OffsetTimeTypeHandler |
java.time.OffsetTime |
TIME |
ZonedDateTimeTypeHandler |
java.time.ZonedDateTime |
TIMESTAMP |
YearTypeHandler |
java.time.Year |
INTEGER |
MonthTypeHandler |
java.time.Month |
INTEGER |
YearMonthTypeHandler |
java.time.YearMonth |
VARCHAR or LONGVARCHAR |
JapaneseDateTypeHandler |
java.time.chrono.JapaneseDate |
DATE |
一个简单的结果集映射示例
如果自己不知道写说明,那么就可以省略javaType和jdbcType也是可以的
附录B : Oracle数据类型和对应的java类型
用mybatis generator生成代码后,执行查询语句时,oracle里的Date类型字段只精确到年月日,后面时分秒都为零。
jdbcType="DATE"时候,存入到数据库中的字段只有年月日!
后来发现是jdbcType问题,改成 jdbcType="TIMESTAMP" 就可以。(原先默认生成时是jdbcType="DATE")
SQL数据类型 | JDBC类型代码 | 标准的Java类型 | Oracle扩展的Java类型 |
---|---|---|---|
1.0标准的JDBC类型: | |||
CHAR |
java.sql.Types.CHAR |
java.lang.String |
oracle.sql.CHAR |
VARCHAR2 |
java.sql.Types.VARCHAR |
java.lang.String |
oracle.sql.CHAR |
LONG |
java.sql.Types.LONGVARCHAR |
java.lang.String |
oracle.sql.CHAR |
NUMBER |
java.sql.Types.NUMERIC |
java.math.BigDecimal |
oracle.sql.NUMBER |
NUMBER |
java.sql.Types.DECIMAL |
java.math.BigDecimal |
oracle.sql.NUMBER |
NUMBER |
java.sql.Types.BIT |
boolean |
oracle.sql.NUMBER |
NUMBER |
java.sql.Types.TINYINT |
byte |
oracle.sql.NUMBER |
NUMBER |
java.sql.Types.SMALLINT |
short |
oracle.sql.NUMBER |
NUMBER |
java.sql.Types.INTEGER |
int |
oracle.sql.NUMBER |
NUMBER |
java.sql.Types.BIGINT |
long |
oracle.sql.NUMBER |
NUMBER |
java.sql.Types.REAL |
float |
oracle.sql.NUMBER |
NUMBER |
java.sql.Types.FLOAT |
double |
oracle.sql.NUMBER |
NUMBER |
java.sql.Types.DOUBLE |
double |
oracle.sql.NUMBER |
RAW |
java.sql.Types.BINARY |
byte[] |
oracle.sql.RAW |
RAW |
java.sql.Types.VARBINARY |
byte[] |
oracle.sql.RAW |
LONGRAW |
java.sql.Types.LONGVARBINARY |
byte[] |
oracle.sql.RAW |
DATE |
java.sql.Types.DATE |
java.sql.Date |
oracle.sql.DATE |
DATE |
java.sql.Types.TIME |
java.sql.Time |
oracle.sql.DATE |
TIMESTAMP |
java.sql.Types.TIMESTAMP |
javal.sql.Timestamp |
oracle.sql.TIMESTAMP |
2.0标准的JDBC类型: | |||
BLOB |
java.sql.Types.BLOB |
java.sql.Blob |
oracle.sql.BLOB |
CLOB |
java.sql.Types.CLOB |
java.sql.Clob |
oracle.sql.CLOB |
用户定义的对象 | java.sql.Types.STRUCT |
java.sql.Struct |
oracle.sql.STRUCT |
用户定义的参考 | java.sql.Types.REF |
java.sql.Ref |
oracle.sql.REF |
用户定义的集合 | java.sql.Types.ARRAY |
java.sql.Array |
oracle.sql.ARRAY |
Oracle扩展: | |||
BFILE |
oracle.jdbc.OracleTypes.BFILE |
N/A | oracle.sql.BFILE |
ROWID |
oracle.jdbc.OracleTypes.ROWID |
N/A | oracle.sql.ROWID |
REF CURSOR |
oracle.jdbc.OracleTypes.CURSOR |
java.sql.ResultSet |
oracle.jdbc.OracleResultSet |
TIMESTAMP |
oracle.jdbc.OracleTypes.TIMESTAMP |
java.sql.Timestamp |
oracle.sql.TIMESTAMP |
TIMESTAMP WITH TIME ZONE |
oracle.jdbc.OracleTypes.TIMESTAMPTZ |
java.sql.Timestamp |
oracle.sql.TIMESTAMPTZ |
TIMESTAMP WITH LOCAL TIME ZONE |
oracle.jdbc.OracleTypes.TIMESTAMPLTZ |
java.sql.Timestamp |
oracle.sql.TIMESTAMPLTZ |