众所周知 hive是字段类型不敏感的,比如date 2022-01-01 和string 2022-01-01 在大多数情况下都是可以呼唤的。我们这边为了方便经常将oracle的date字段 在hive中直接用string字段去替代,最近发现了一个问题。
表中字段如下 字段类型是date。 注意这个date 不是datetime。
date类型只保留年月日 不保留时分秒
所以我们一般来说看到这个date 数值就是年月日,但是因为工具看到的也不同 我用dbeaver看到的如上,同事用的哪个工具忘了如下
当然 我猜测底层存储的肯定是1469635200000 这种,时分秒的单位都归0了
这时候我们要明确一个问题,前端需要看到的到底是什么? 如果你想看到年月日时分秒,那么datax就是这么做的。
但是如果你想看到的只是年月日,那么就需要自己去改了。当然你在hive用date类型接受也没有问题。
学习一下源码。
CommonRdbmsReader.java
// for mysql bug, see http://bugs.mysql.com/bug.php?id=35115 --你看这里还有bug。。 这里才是 年月日 没有时分秒 case Types.DATE: if (metaData.getColumnTypeName(i).equalsIgnoreCase("year")) { record.addColumn(new LongColumn(rs.getInt(i))); } else { record.addColumn(new DateColumn(rs.getDate(i))); } break; case Types.TIMESTAMP: record.addColumn(new DateColumn(rs.getTimestamp(i))); break;注意 oracle的date类型属于这里的 Types.TIMESTAMP
DateColumn.java
/** * 构建值为ts(java.sql.Timestamp)的DateColumn,使用Date子类型为DATETIME * */ public DateColumn(final java.sql.Timestamp ts) { this(ts == null ? null : ts.getTime()); this.setSubType(DateType.DATETIME); }设置datecolumn的类型为datetime, 并且把值ts 传进去了。
然后我们看取出来是怎么取的
@Override public String asString() { try { return ColumnCast.date2String(this); } catch (Exception e) { throw DataXException.asDataXException( CommonErrorCode.CONVERT_NOT_SUPPORT, String.format("Date[%s]类型不能转为String .", this.toString())); } } @Override public Date asDate() { if (null == this.getRawData()) { return null; } return new Date((Long)this.getRawData()); }---这里就是as string的后续方法 static String asString(final DateColumn column) { if (null == column.asDate()) { return null; } switch (column.getSubType()) { case DATE: return DateFormatUtils.format(column.asDate(), DateCast.dateFormat, DateCast.timeZoner); --yyyy-MM-dd case TIME: return DateFormatUtils.format(column.asDate(), DateCast.timeFormat, DateCast.timeZoner); case DATETIME: return DateFormatUtils.format(column.asDate(), DateCast.datetimeFormat, DateCast.timeZoner);--yyyy-MM-dd HH:mm:ss default: throw DataXException .asDataXException(CommonErrorCode.CONVERT_NOT_SUPPORT, "时间类型出现不支持类型,目前仅支持DATE/TIME/DATETIME。该类型属于编程错误,请反馈给DataX开发团队 ."); } }
所以问题很清楚了,
就是oracle对于date类型数据 在java的types里对应的是timestamp
对于mysql的date类型来说对应的就是date 只保留年月日。
这里有点不是特别理解,oracle的date和mysql的date哪里不一样?
CREATE TABLE test.cc_test_time( t1 DATE, t2 timestamp )String querySql = "SELECT * from test.cc_test_time "; rs = demo.execQuery(querySql); ResultSetMetaData metaData = rs.getMetaData(); for (int i = 1; i <= metaData.getColumnCount(); i++) { System.out.println("columntype="+metaData.getColumnType(i)); }
INSERT INTO test.cc_test_time VALUES (sysdate,sysdate)
columntype=93
columntype=93
而且经过我的测试 oracle的date 和timestamp类型 对应的都是 93也就是timestamp,所以datax在对oracle取数的时候,这两个类型是区分不了的。。
具体我就不尝试了。比如timestamp精确到毫秒 ,我猜测datax也忽略了毫秒,反正统一都是年于日时分秒。
---------------------------
又遇到一个问题。datax读取oracle的number字段 不是number(22,8)这种会出现问题。
jdbc查询
datax
datax这里读取的时候直接就rs.getString 最后结果就是科学计数法。。。。 唉 大坑,解决办法也很简单 getBigdecimal或者getObject