Oracle数据库中字段定义为Char类型,Hibernate用该字段进行动态绑定参数查询,获取不到结果的问题
一、问题背景
create table STORE_INFORMATION ( id CHAR(32) not null, name VARCHAR2(254) default '', content CLOB default '', create_time VARCHAR2(26) default '', cindex NUMBER default 0, status VARCHAR2(4) default '0' not null, nav_text VARCHAR2(254) default '', nav_image VARCHAR2(254) default '', note VARCHAR2(1000) default '', type VARCHAR2(60) default '', url VARCHAR2(254) default '', filename VARCHAR2(254) default '', update_time VARCHAR2(26) default '', filesize VARCHAR2(60) default '', flat VARCHAR2(60) default '', categoryid VARCHAR2(40) default '0', viewnumber NUMBER default 0, tag VARCHAR2(254) default '', sid VARCHAR2(60) default '1', creator VARCHAR2(120) default '', author VARCHAR2(120) default '', news_editor VARCHAR2(120) default '', news_from VARCHAR2(120) default '', pop_type CHAR(32) default '', app_usercount NUMBER default 0, orgid VARCHAR2(32), isnew NUMBER, flag NUMBER, isupdate NUMBER, check_status VARCHAR2(40), check_time VARCHAR2(26), check_man VARCHAR2(60), checked_note VARCHAR2(500), store_id CHAR(32), store_name VARCHAR2(254) )
其中store_id定义为CHAR(32)
/** * 新增 需要持续化的临时对象 * * @param po * @throws HibernateException */ public void addBean(Object po) throws Exception { covertSpace(po); try { session = sessionFactory.openSession(); transaction = session.beginTransaction(); session.save(po); // session.flush(); transaction.commit(); } catch (Exception e) { transaction.rollback(); PubLogs.dbLogError(new StringBuffer("新增操作失败!") .append("PubHibernate.addBean()"), e); throw e; } finally { if (session != null && session.isOpen()) { session.close(); } } }
/** * 根据查询条件得到查询结果 * * @param querySQL * @param map * 查询条件 * @return 查询结果 * @throws HibernateException */ public List list(String querySQL, Map<String, Object> map, Pager page) throws Exception { List list = null; try { session = sessionFactory.openSession(); String sql = rebuildOrgSql(querySQL, orgId, listAllOrgs); Query query = session.createQuery(sql); if (map != null) { for (String key : map.keySet()) { if (sql.indexOf(":" + key) != -1) { query.setParameter(key, map.get(key)); System.out.println("param[" + key + "]===" + map.get(key)); } } } if (page != null) { query.setFirstResult(page.getFromRow()); query.setMaxResults(page.getRowsPerPage()); } else { query.setFirstResult(0); query.setMaxResults(20); } list = query.list(); if (page != null) { Query countQuery = session.createQuery(countSql(sql)); if (map != null) { for (String key : map.keySet()) { if (sql.indexOf(":" + key) != -1) { countQuery.setParameter(key, map.get(key)); System.out.println("param[" + key + "]===" + map.get(key)); } } } if (countQuery != null) { List countlist = countQuery.list(); if (countlist != null && countlist.size() > 0) { page .setTotalRow(((Number) countlist.get(0)) .intValue()); } } } } catch (Exception e) { e.printStackTrace(); PubLogs.dbLogError(new StringBuffer("获取查询列表失败!").append( "PubHibernate.list(querySQL)").append( "querySql=" + querySQL), e); throw e; } finally { if (session != null && session.isOpen()) { session.close(); } } if (list != null) { covertNullToSpace(list); } return list; }
sql.append(" from StoreInformation as si where 1=1"); //按商户搜索 sql.append(" and si.storeId= :storeId"); paramMap.put("storeId", store.getId()); sql.append(" order by si.updateTime desc");
二、问题分析
sql.append(" and si.storeId='").append(store.getId()).append(","); // paramMap.put("storeId", store.getId());
3)用其他Varchar2类型的字段动态绑定参数查询是可以的
sql.append(" and si.checkStatus=:checkStatus"); paramMap.put("checkStatus", checkStatus);
分析:该问题可能和字段类型和hibernate的动态绑定有关系
Bug in PreparedStatement with CHAR fields 396190 Newbie 396190 2003-6-5 上午10:57 Select * From table Where column = ? setObject(1, "compValue") will never return anything if the type of column would be e.g. CHAR(20) This behaviour is inconsistent to executing the same select as statement in the following form Statement.executeQuery(Select * From table Where column = "compValue") which will return all rows, where the value matches. The difference in the behaviour lies in the fact, that for a PreparedStatment the number of characters must match.
use setFixedCHAR(....)., quote from Oracle9i JDBC API Docs public void setFixedCHAR(int paramIndex, java.lang.String x) throws java.sql.SQLException Sets the disignated parameter to a String and executes a non-padded comparison with a SQL CHAR. CHAR data in the database is padded to the column width. This leads to a limitation in using the setCHAR() method to bind character data into the WHERE clause of a SELECT statement--the character data in the WHERE clause must also be padded to the column width to produce a match in the SELECT statement. This is especially troublesome if you do not know the column width. setFixedCHAR() remedies this. This method executes a non-padded comparison. Notes: * Remember to cast your prepared statement object to OraclePreparedStatement to use the setFixedCHAR() method. * There is no need to use setFixedCHAR() for an INSERT statement. The database always automatically pads the data to the column width as it inserts it. The following example demonstrates the difference between the setString(), setCHAR() and setFixedCHAR() methods. // Schema is : create table my_table (col1 char(10)); // insert into my_table values ('JDBC'); PreparedStatement pstmt = conn.prepareStatement ("select count() from my_table where col1 = ?"); ResultSet rs; pstmt.setString (1, "JDBC"); // Set the Bind Value rs = pstmt.executeQuery(); // This does not match any row // ... do something with rs CHAR ch = new CHAR("JDB ", null); ((OraclePreparedStatement)pstmt).setCHAR(1, ch); // Pad it to 10 bytes rs = pstmt.executeQuery(); // This matches one row // ... do something with rs ((OraclePreparedStatement)pstmt).setFixedCHAR(1, "JDBC"); rs = pstmt.executeQuery(); // This matches one row // ... do something with rs Parameters: paramIndex - index of the bind variable (first is 1)x - the literal/variable to be bound. hope this helps Elango.
大体意思就是说采用CHAR类型,是固定类型,如果长度不够会用空格补齐,因此采用PreparedStatement动态参数绑定查询时,要采用OraclePreparedStatement 的setFixedCHAR() 设置char类型的字段。
三、问题解决
query.setParameter(key, map.get(key));
因此使用setFixedCHAR()的方式行不太通。说下我的解决方式
sql.append(" and trim(si.storeId)= :storeId"); paramMap.put("storeId", store.getId());
2)将字段类型改为varchar2类型 (项目中使用,推荐使用),另外建议优先使用varchar2类型
四、关于Oracle数据库中是使用char还是varchar2可参考如下
A CHAR datatype and VARCHAR2 datatype are stored identically (eg: the word 'WORD' stored in a CHAR(4) and a varchar2(4) consume exactly the same amount of space on disk, both have leading byte counts). The difference between a CHAR and a VARCHAR is that a CHAR(n) will ALWAYS be N bytes long, it will be blank padded upon insert to ensure this. A varchar2(n) on the other hand will be 1 to N bytes long, it will NOT be blank padded. Using a CHAR on a varying width field can be a pain due to the search semantics of CHAR. Consider the following examples: ops$tkyte@8i> create table t ( x char(10) ); Table created. ops$tkyte@8i> insert into t values ( 'Hello' ); 1 row created. ops$tkyte@8i> select * from t where x = 'Hello'; X ---------- Hello ops$tkyte@8i> variable y varchar2(25) ops$tkyte@8i> exec :y := 'Hello' PL/SQL procedure successfully completed. ops$tkyte@8i> select * from t where x = :y; no rows selected ops$tkyte@8i> select * from t where x = rpad(:y,10); X ---------- Hello Notice how when doing the search with a varchar2 variable (almost every tool in the world uses this type), we have to rpad() it to get a hit. If the field is in fact ALWAYS 10 bytes long, using a CHAR will not hurt -- HOWEVER, it will not help either. The only time I personally use a CHAR type is for CHAR(1). And that is only because its faster to type char(1) then varchar2(1) -- it offers no advantages.
<quote> The fact that a CHAR/NCHAR is really nothing more than a VARCHAR2/NVARCHAR2 in disguise makes me of the opinion that there are really only two character string types to ever consider, namely VARCHAR2 and NVARCHAR2. I have never found a use for the CHAR type in any application. Since a CHAR type always blank pads the resulting string out to a fixed width, we discover rapidly that it consumes maximum storage both in the table segment and any index segments. That would be bad enough, but there is another important reason to avoid CHAR/NCHAR types: they create confusion in applications that need to retrieve this information (many cannot find their data after storing it). The reason for this relates to the rules of character string comparison and the strictness with which they are performed. ...... </quote>
事实上,一个char/nchar实际上只是一个伪装的VARCHAR2/NVARCHAR2,这使我认为只有两个字符串类型是可以考虑的,即VARCHAR2和NVARCHAR2。我从来没有在任何应用程序中找到过CHAR类型的用法。由于CHAR类型始终是空白的,因此产生的字符串是固定宽度的,因此我们很快就会发现,它在表段和任何索引段中都消耗了最大的存储空间。这已经够糟糕了,但是还有另外一个重要的原因要避免使用char/nchar类型:它们在需要检索此信息的应用程序中造成混乱(许多在存储后无法找到它们的数据)。其原因与字符串比较的规则和它们执行的严格性有关。
Oracle数据库中字段定义为Char类型,Hibernate用该字段进行动态绑定参数查询,获取不到结果的问题的更多相关文章
- Oracle数据库中NARCHAR转换成NUMBER类型
1.修改后的代码: public void addDirectorActorKeyword(long idStart, long idEnd) { SeriesMgr seriesMgr = new ...
- sybase数据库和oracle数据库中字段中含有换行符的解决办法
最近在做数据库从sybase到oracle的迁移工作,sybase数据库表bcp导出后,通过sqlldr导入到oracle数据库,然后oracle数据库通过spool按照sybase数据库bcp的格式 ...
- Oracle数据库教程-数据定义语言(表操作)
创建表 建表语法: CREATE TABLE 表名 ( 列1 数据类型 [primary key], 列2 数据类型 default 默认值 [not null], …, constraint 约束名 ...
- oracle数据库中提供的5种约束
约束作用:用来保持数据的完整性,防止无效数据进入到数据库中.oracle数据库中提供的5种约束,都是限定某个列或者列的组合的.1.主键约束(PRIMARY KEY):在一个表中能唯一的标识一行.主键可 ...
- Oracle 数据库中日期时间的插入操作
Oracle 中如何插入日期时间类型的数据,首先为了演示, 新建数据表如下 create table t( mydate date); 插入日期时间 SQL> insert into t val ...
- Oracle数据库中的变量
Oracle数据库中的变量 来源:https://blog.csdn.net/wahaa591/article/details/46772769 1.define(即host变量) define va ...
- --关于null在oracle数据库中是否参与计算,进行验证,
--关于null在oracle数据库中是否参与计算,进行验证,with td as (select null id,1 name from dual ),td1 as ( select null id ...
- 配置NHibernate将枚举保存为Oracle数据库中的字符串
假设有这样一个枚举: /// <summary> /// 字典项类型 /// </summary> public enum DicItemType { [EnumDescrip ...
- 查找Oracle数据库中的重复记录
本文介绍了几种快速查找ORACLE数据库中的重复记录的方法. 下面以表table_name为例,介绍三种不同的方法来确定库表中重复的记录 方法1:利用分组函数查找表中的重复行:按照某个字段分组,找出行 ...
随机推荐
- 2017阿里C++研发工程师-校招-笔试模拟
题目描述: 猎人把一对兔子婴儿(一公一母称为一对)放到一个荒岛上,两年之后,它们生00下一对小兔,之后开始每年都会生下一对小兔.生下的小兔又会以同样的方式继续繁殖. 兔子的寿命都是x(x>=3) ...
- C++之STL迭代器(iterator)
[摘要]本文是对STL--迭代器(iterator)的讲解,对学习C++编程技术有所帮助,与大家分享. 原文:http://www.cnblogs.com/qunews/p/3761405.html ...
- Graph_Master(连通分量_Poj_1904)
Poj_1904 背景:本来是在做Voj的连通分量,做到了E( hdu_4685 ),想到了二分图,但是笔者只会最大匹配,但题目要求要输出所有的最大匹配情况,想了好久都没想出来怎么做,因为如果我已知一 ...
- 转载 URL短地址压缩算法
文章转载http://www.nowamagic.net/webdesign/webdesign_ShortUrlInTwitter.php /// <summary> /// 生成sal ...
- install opencv
OpenCV是一个基于开源发行的跨平台计算机视觉库,它轻量级而且高效——由一系列 C 函数和少量 C++ 类构成,同时提供了Python.Ruby.MATLAB等语言的接口,实现了图像处理和计算机视觉 ...
- Memcached stats items 命令
Memcached stats items 命令用于显示各个 slab 中 item 的数目和存储时长(最后一次访问距离现在的秒数). 语法: stats items 命令的基本语法格式如下: sta ...
- cygwin 获取root高级权限
cygwin安装完成后没有passwd文件解决方法
- dropout 为何会有正则化作用
在神经网络中经常会用到dropout,大多对于其解释就是dropout可以起到正则化的作用. 一下是我总结的对于dropout的理解.花书上的解释主要还是从模型融合的角度来解释,末尾那一段从生物学角度 ...
- authentication vs authorization 验证与授权的区别
认证和授权的区别 Authentication vs. Authorization简单来说,认证(Authentication )是用来回答以下问题: 用户是谁 当前用户是否真的是他所代表的角色 通常 ...
- JSP 标准标签库(JSTL)
JSP 标准标签库(JSTL) JSP标准标签库(JSTL)是一个JSP标签集合,它封装了JSP应用的通用核心功能. JSTL支持通用的.结构化的任务,比如迭代,条件判断,XML文档操作,国际化标签, ...