文档章节

JFinal针对ORACLE的timestamp字段解决办法

真的农夫三拳
 真的农夫三拳
发布于 2013/06/23 20:22
字数 1156
阅读 1695
收藏 5

JFinal是个比较不错的的框架,但JFinal起源时使用mysql数据库,因此在对数据库支持方面还没有达到完美。

本人使用JFinal有一段时间的,由于项目的数据库普遍采用oracle,在使用oracle过程中遇到了一些不便之处(比如ORACLE中的自动生成主键、oracletimestamp字段返回oracle.sql.timestamp等),幸好在@JFinal 等人的帮助下已经解决了遇到的问题,本遍就是讲如何解决oracletimestamp字段返回oracle.sql.timestamp

  oracle总有些与众不同的地方,比如它的字段默认没有自增支持,更可恶的是它的字段返回类型与其他数据库返回类型不一样,比如说timestamp字段,这货居然给我们返回了oracle.sql.Timestamp,对于oracle本身暂不作评价。

    以前JFinal只用在一个小项目中,而且基本就是我个人在维护,因此碰到timestamp,只能手动的进行一些转换。但现在JFinal用到了一个大一点的项目中,而且开发人员也不只我一个,初次大家对JFinal这种简单的、高效的框架很喜欢,但遇到需手动处理timestamp时,对JFinal有些失望,居然只能手动转换。为了提高大家对JFinal的信心,我就认真研究了一下JFINAL对字段的处理过程,得出结论如下:

1、      JFinal在启动时会将注册的Model 与数据库中对应的table进行一一绑定,绑定的过程主要是通过TableInfoBuilder.buildTableInfo()创建一个TableInfo对象,该对象如下:

private String tableName;
	private String primaryKey;
	private String secondaryKey = null;
	
	@SuppressWarnings("unchecked")
	private Map<String, Class<?>> columnTypeMap = DbKit.containerFactory.getAttrsMap();	//	new HashMap<String, Class<?>>();

其实最核心的就是这个columnTypeMap对象,这个MAP记录着table每个字段的名字及其类型。 通过跟踪源代码发现目前JFinal将默认将Oracle中的timestamp转换成java.lang.String类型,具体创建TableInfo的方法如下:

private static TableInfo doBuildTableInfo(TableInfo tableInfo,
	    Connection conn) throws SQLException {
	TableInfo result = tableInfo;

	String sql = DbKit.getDialect().forTableInfoBuilderDoBuildTableInfo(
		tableInfo.getTableName());
	Statement stm = conn.createStatement();
	ResultSet rs = stm.executeQuery(sql);
	ResultSetMetaData rsmd = rs.getMetaData();

	for (int i = 1; i <= rsmd.getColumnCount(); i++) {
	    String colName = rsmd.getColumnName(i);
	    String colClassName = rsmd.getColumnClassName(i);
	    if ("java.lang.String".equals(colClassName)) {
		// varchar, char, enum, set, text, tinytext, mediumtext,
		// longtext
		result.addInfo(colName, java.lang.String.class);
	    } else if ("java.lang.Integer".equals(colClassName)) {
		// int, integer, tinyint, smallint, mediumint
		result.addInfo(colName, java.lang.Integer.class);
	    } else if ("java.lang.Long".equals(colClassName)) {
		// bigint
		result.addInfo(colName, java.lang.Long.class);
	    } else if ("java.sql.Date".equals(colClassName)) {
		// date, year
		result.addInfo(colName, java.sql.Date.class);
	    } else if ("java.lang.Double".equals(colClassName)) {
		// real, double
		result.addInfo(colName, java.lang.Double.class);
	    } else if ("java.lang.Float".equals(colClassName)) {
		// float
		result.addInfo(colName, java.lang.Float.class);
	    } else if ("java.lang.Boolean".equals(colClassName)) {
		// bit
		result.addInfo(colName, java.lang.Boolean.class);
	    } else if ("java.sql.Time".equals(colClassName)) {
		// time
		result.addInfo(colName, java.sql.Time.class);
	    } else if ("java.sql.Timestamp".equals(colClassName)
		    || "oracle.sql.TIMESTAMP".equals(colClassName)) {
		// timestamp, datetime
		result.addInfo(colName, java.sql.Timestamp.class);
	    } else if ("java.math.BigDecimal".equals(colClassName)) {
		// decimal, numeric
		result.addInfo(colName, java.math.BigDecimal.class);
	    } else if ("[B".equals(colClassName)) {
		// binary, varbinary, tinyblob, blob, mediumblob, longblob
		// qjd project: print_info.content varbinary(61800);
		result.addInfo(colName, byte[].class);
	    } else {
		int type = rsmd.getColumnType(i);
		if (type == Types.BLOB) {
		    result.addInfo(colName, byte[].class);
		} else if (type == Types.CLOB || type == Types.NCLOB) {
		    result.addInfo(colName, String.class);
		} else {
		    result.addInfo(colName, String.class);
		}
		// core.TypeConverter
		// throw new RuntimeException("You've got new type to mapping.
		// Please add code in " + TableInfoBuilder.class.getName() + ".
		// The ColumnClassName can't be mapped: " + colClassName);
	    }
	}

	rs.close();
	stm.close();
	return result;
    }


2、      JFinal将数据填充到Model中时,主要执行ModelBuilder. build(ResultSet rs, Class<? extends Model> modelClass)方法,该方法实现如下:其实这个过程JFinal没有进行干预(除了CLOB、NCLOB、BLOB),数据根据JDBC默认的方式进行返回。

@SuppressWarnings({"rawtypes", "unchecked"})
	public static final <T> List<T> build(ResultSet rs, Class<? extends Model> modelClass) throws SQLException, InstantiationException, IllegalAccessException {
		List<T> result = new ArrayList<T>();
		ResultSetMetaData rsmd = rs.getMetaData();
		int columnCount = rsmd.getColumnCount();
		String[] labelNames = new String[columnCount + 1];
		int[] types = new int[columnCount + 1];
		buildLabelNamesAndTypes(rsmd, labelNames, types);
		while (rs.next()) {
			Model<?> ar = modelClass.newInstance();
			Map<String, Object> attrs = ar.getAttrs();
			for (int i=1; i<=columnCount; i++) {
				Object value;
				if (types[i] < Types.BLOB)
					value = rs.getObject(i);
				else if (types[i] == Types.CLOB)
					value = handleClob(rs.getClob(i));
				else if (types[i] == Types.NCLOB)
					value = handleClob(rs.getNClob(i));
				else if (types[i] == Types.BLOB)
					value = handleBlob(rs.getBlob(i));
				else
					value = rs.getObject(i);
				
				attrs.put(labelNames[i], value);
			}
			result.add((T)ar);
		}
		return result;
	}


解决思路:

         对数据库的数据操作有2种,set/get,为了将oracletimestamp改造成与mysqltimestamp一样,我们就需要在set/get时进行一些干预,以上2点分别对应set/get操作。通过修改源码,然后经过测试是发现思路是可行的。

 1、doBuildTableInfoy()方法中在"java.sql.Timestamp".equals(colClassName)增加|| "oracle.sql.TIMESTAMP".equals(colClassName),使其可以识别oracle.sql.timestamp

} else if ("java.sql.Timestamp".equals(colClassName)
		    || "oracle.sql.TIMESTAMP".equals(colClassName)) {
		// timestamp, datetime
		result.addInfo(colName, java.sql.Timestamp.class);

            2、ModelBuilder.build() 中 for (int i = 1; i <= columnCount; i++) {}循环体修改如下:

for (int i = 1; i <= columnCount; i++) {
		Object value;
		if (types[i] == Types.CLOB)
		    value = handleClob(rs.getClob(i));
		else if (types[i] == Types.NCLOB)
		    value = handleClob(rs.getNClob(i));
		else if (types[i] == Types.BLOB)
		    value = handleBlob(rs.getBlob(i));
		else if (types[i] == Types.TIMESTAMP
			&& DbKit.dialect.isOracle()) {
		    // oracle.sql.timestamp --->java.sql.Timestamp
		    value = rs.getTimestamp(i);
		} else {
		    value = rs.getObject(i);
		}

		attrs.put(labelNames[i], value);
	    }

PS:本人文字功底差,而没有用得顺手的编辑器,大家凑合看看就行了。希望@JFinal 考虑一下是否能将代码更新到版本库中。

 



© 著作权归作者所有

共有 人打赏支持
真的农夫三拳

真的农夫三拳

粉丝 14
博文 11
码字总数 2807
作品 0
武汉
高级程序员
加载中

评论(6)

微信小程序社区俱乐部
微信小程序社区俱乐部
感谢分享啊
真的农夫三拳
真的农夫三拳

引用来自“wlg910525”的评论

请问 现在这个问题解决吗?更新到源码里面去了吗

没有!自已改造

w
wlg910525
请问 现在这个问题解决吗?更新到源码里面去了吗
FuYung
FuYung

引用来自“kudc”的评论

引用来自“FuYung”的评论

请教一个问题,46行代码[B是什么类型呀。

byte[] byte数组

哦。明白了,谢谢。
真的农夫三拳
真的农夫三拳

引用来自“FuYung”的评论

请教一个问题,46行代码[B是什么类型呀。

byte[] byte数组
FuYung
FuYung
请教一个问题,46行代码[B是什么类型呀。
JFinal 3.4 发布,将极速贯彻到 UI 层

jfinal 的终极目标是全面实现软件开发整个过程的极速开发,极大提升开发效率,极大降低学习成本,极大提升开发体验 jfinal 诞生头五年,已实现 WEB + ORM + AOP 层面的极速开发,赢得了大量开...

JFinal
04/28
0
129
jfinal兼容oracle integer字段

为什么oracle integer字段用了number(3,0),jfinal生成的字段还是BigDecimal @jfinal

tianxia007
05/02
0
0
OSC上关于Jfinal的提问整理(一)

看见Jfinal很火,就手痒痒了,想学一下,无奈入门较慢,没有找到比较全的文档。于是就经常看讨论区大家的提问与解答。后来就忽然萌生了整理下来的想法。其中的问题如果是@Jfinal 回答的,那我...

木川瓦兹
2013/04/23
0
21
在jfinal实现oracle”自增主键“保存入库,并获取自生成的主键

oracle数据库其实是没有自增主键的,但为了达到这一效果 ,可以采取以下方式间接实现: 1、利用sequence自动力产生一个主键 ,然后将该值设置到主键上,并保存入库具体代码如下: insert int...

真的农夫三拳
2012/08/19
0
6
SpringMVC 集成 JFinal Dao

<dependency> </dependency><dependency> </dependency> <bean id="autoTableBindPlugin" class="com.jfinal.ext.plugin.tablebind.AutoTableBindPlugin" init-method="start"> </bean> exte......

大树被注册了
2015/11/03
0
6

没有更多内容

加载失败,请刷新页面

加载更多

【大福利】极客时间专栏返现二维码大汇总

我已经购买了如下专栏,大家通过我的二维码你可以获得一定额度的返现! 然后,再给大家来个福利,只要你通过我的二维码购买,并且关注了【飞鱼说编程】公众号,可以加我微信或者私聊我,我再...

飞鱼说编程
今天
1
0
Spring5对比Spring3.2源码之容器的基本实现

最近看了《Spring源码深度解析》,该书是基于Spring3.2版本的,其中关于第二章容器的基本实现部分,目前spring5的实现方式已有较大改变。 Spring3.2的实现: public void testSimpleLoad(){...

Ilike_Java
今天
1
0
【王阳明心学语录】-001

1.“破山中贼易,破心中贼难。” 2.“夫万事万物之理不外于吾心。” 3.“心即理也。”“心外无理,心外无物,心外无事。” 4.“人心之得其正者即道心;道心之失其正者即人心。” 5.“无...

卯金刀GG
今天
2
0
OSChina 周三乱弹 —— 我们无法成为野兽

Osc乱弹歌单(2018)请戳(这里) 【今日歌曲】 @ _刚刚好: 霸王洗发水这波很骚 手机党少年们想听歌,请使劲儿戳(这里) hahahahahahh @嘻酱:居然忘了喝水。 让你喝可乐的话, 你准忘不了...

小小编辑
今天
10
0
vm GC 日志 配置及查看

-XX:+PrintGCDetails 打印 gc 日志 -XX:+PrintTenuringDistribution 监控晋升分布 -XX:+PrintGCTimeStamps 包含时间戳 -XX:+printGCDateStamps 包含时间 -Xloggc:<filename> 可以将数据保存为......

Canaan_
昨天
0
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部