JFinal针对ORACLE的timestamp字段解决办法
2013-06-23 20:22
197 查看
JFinal是个比较不错的的框架,但JFinal起源时使用mysql数据库,因此在对数据库支持方面还没有达到完美。
本人使用JFinal有一段时间的,由于项目的数据库普遍采用oracle,在使用oracle过程中遇到了一些不便之处(比如ORACLE中的自动生成主键、oracle中timestamp字段返回oracle.sql.timestamp等),幸好在@JFinal 等人的帮助下已经解决了遇到的问题,本遍就是讲如何解决oracle中timestamp字段返回oracle.sql.timestamp 。
oracle总有些与众不同的地方,比如它的字段默认没有自增支持,更可恶的是它的字段返回类型与其他数据库返回类型不一样,比如说timestamp字段,这货居然给我们返回了oracle.sql.Timestamp,对于oracle本身暂不作评价。
以前JFinal只用在一个小项目中,而且基本就是我个人在维护,因此碰到timestamp,只能手动的进行一些转换。但现在JFinal用到了一个大一点的项目中,而且开发人员也不只我一个,初次大家对JFinal这种简单的、高效的框架很喜欢,但遇到需手动处理timestamp时,对JFinal有些失望,居然只能手动转换。为了提高大家对JFinal的信心,我就认真研究了一下JFINAL对字段的处理过程,得出结论如下:
1、 JFinal在启动时会将注册的Model 与数据库中对应的table进行一一绑定,绑定的过程主要是通过TableInfoBuilder.buildTableInfo()创建一个TableInfo对象,该对象如下:
其实最核心的就是这个columnTypeMap对象,这个MAP记录着table每个字段的名字及其类型。 通过跟踪源代码发现目前JFinal将默认将Oracle中的timestamp转换成java.lang.String类型,具体创建TableInfo的方法如下:
2、 JFinal将数据填充到Model中时,主要执行ModelBuilder. build(ResultSet rs, Class<? extends Model> modelClass)方法,该方法实现如下:其实这个过程JFinal没有进行干预(除了CLOB、NCLOB、BLOB),数据根据JDBC默认的方式进行返回。
解决思路:
对数据库的数据操作有2种,set/get,为了将oracle的timestamp改造成与mysql的timestamp一样,我们就需要在set/get时进行一些干预,以上2点分别对应set/get操作。通过修改源码,然后经过测试是发现思路是可行的。
1、doBuildTableInfoy()方法中在"java.sql.Timestamp".equals(colClassName)增加|| "oracle.sql.TIMESTAMP".equals(colClassName),使其可以识别oracle.sql.timestamp
2、ModelBuilder.build() 中 for (int i = 1; i <= columnCount; i++) {}循环体修改如下:
PS:本人文字功底差,而没有用得顺手的编辑器,大家凑合看看就行了。希望@JFinal 考虑一下是否能将代码更新到版本库中。
本人使用JFinal有一段时间的,由于项目的数据库普遍采用oracle,在使用oracle过程中遇到了一些不便之处(比如ORACLE中的自动生成主键、oracle中timestamp字段返回oracle.sql.timestamp等),幸好在@JFinal 等人的帮助下已经解决了遇到的问题,本遍就是讲如何解决oracle中timestamp字段返回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,为了将oracle的timestamp改造成与mysql的timestamp一样,我们就需要在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 考虑一下是否能将代码更新到版本库中。
相关文章推荐
- oracle 中 create table tb_content_bak as select * from tb_content where 1=2 long字段解决办法
- oracle 11g 数据库中文字段,vs2013 MFC工程 显示乱码解决办法
- PDO取Oracle lob大字段,当数据量太大无法取出的问题的解决办法
- jfinal 关于多字段搜索结合分页的解决办法
- 批量插入Oracle,遇到CLob字段慢的解决办法
- PDO取Oracle lob大字段,当数据量太大无法取出的问题的解决办法
- SSIS ORACLE NUMBER 字段出错解决办法
- oracle 修改某字段小数位精度 需要字段未empty的解决办法
- oracle.sql.TIMESTAMP cannot be cast to java.sql.Timestamp 异常的解决办法
- 针对Mysql 使用EF Code First时 TimeStamp/RowVersion 类型 的解决办法
- PDO取Oracle lob大字段,当数据量太大无法取出的问题的解决办法
- oracle表中多个字段同时和另一个表中关联解决办法
- Oracle导入包含clob字段的dmp文件报错问题解决办法
- 针对Android里没有Arrays.CopyOf的解决办法
- DISTINCT选取多个字段,只DISTINCT一个字段的解决办法
- oracle10 ora-12154错误的解决办法
- Oracle rebuild index 报 ORA-01652 解决办法
- Oracle 实现类似SQL Server中自增字段的一个办法
- Oracle因目标主机或对象不存在 的解决办法
- oracle 11G exp导出,空表导不出表结构的解决办法..