oracle的JDBC使用preparedStatement处理char类型字段的问题

探讨了在使用Hibernate查询Oracle数据库时,针对Char类型字段使用HQL参数占位符出现查询不到数据的问题,并给出了解决方案。
整理了一下:[quote="xiaoyuonline"]关于Hibernate的HQL语句的占位符的一个问题
首先我的环境是Hibernate + oracle9i。user表中name类型为char(10),有值为hello的记录。
代码如下:
String hql = "select user.name from User user where user.name='hello'";
Query query = session.createQuery(hql);
List list = query.list();
System.out.println(list.isEmpty());
打印出来是false,说明查到了数据。

但如果改写上面的代码如下:
String hql = "select user.name from User user where user.name=:name";
Query query = session.createQuery(hql);
query.setParameter("name","hello");
List list = query.list();
System.out.println(list.isEmpty());
打印出来就是true,说明没有查到数据
[/quote]

经过我的测试,上面的问题确实存在。
但当数据库采用sql server或者mysql5时,采用char类型,没有任何问题。
所以判断该错误与hibernate本身没有关系。而与oracle的jdbc驱动有关。
试了classes12.jar和ojdbc.jar,也试过了oci驱动,均错误依旧。

我建了一个表:create table test(name char(7));内有N条值为hello的记录
第一种:不用占位符,
java.sql.PreparedStatement ps = connection().prepareStatement("select * from test where name='hello'");
java.sql.ResultSet rs = ps.executeQuery();
记录集rs有数据;

第二种:使用占位符,
java.sql.PreparedStatement ps = connection().prepareStatement("select * from test where name=?");
ps.setString(1,"hello");
java.sql.ResultSet rs = ps.executeQuery();
记录集rs中无任何数据。

将字段类型改为varchar时以上两条jdbc sql均无任何问题。因此,不要再费劲了,至于产生此问题的详细原因及解决办法,我暂时还没想到。oracle的第三方驱动很少,datadirect还是收费的。

笨一点的解决办法,就不要再采用char类型了,想不通为什么非要用此类型不可。直接转换为varchar类型好了,绝对的正常。
处理 MyBatis 与 Oracle 数据库中的 `DATE` 类型映射问题时,常见的问题包括时间精度丢失、映射类型不匹配或结果集无法正确转换为 Java 中的 `Date` 类型。以下是解决方案和建议: ### 1. 明确指定 JDBC 类型 在 MyBatis 的映射文件中,对于 Oracle 的 `DATE` 类型字段,建议显式指定 `jdbcType="DATE"` 或 `jdbcType="TIMESTAMP"`,以避免自动映射导致的类型不一致问题。例如: ```xml <result property="createTime" column="create_time" jdbcType="DATE"/> ``` 如果需要保留时间戳的完整精度(包括毫秒),则应使用 `TIMESTAMP` 类型: ```xml <result property="createTime" column="create_time" jdbcType="TIMESTAMP"/> ``` 此配置确保了 Oracle 的 `DATE` 或 `TIMESTAMP` 类型能够正确映射到 Java 的 `java.util.Date` 或 `java.sql.Timestamp` 对象[^1]。 ### 2. 使用自定义类型处理器(TypeHandler) 当默认的映射方式无法满足需求时,可以通过自定义 `TypeHandler` 来实现更精确的类型转换。例如,定义一个将 `java.util.Date` 转换为 `java.sql.Timestamp` 的处理器: ```java public class DateToTimestampTypeHandler extends BaseTypeHandler<Date, Timestamp> { @Override public void setNonNullParameter(PreparedStatement ps, int i, Date parameter, JdbcType jdbcType) throws SQLException { ps.setTimestamp(i, new Timestamp(parameter.getTime())); } @Override public Date getNullableResult(ResultSet rs, String columnName) throws SQLException { Timestamp timestamp = rs.getTimestamp(columnName); return timestamp != null ? new Date(timestamp.getTime()) : null; } } ``` 在映射文件中使用处理器: ```xml <result property="createTime" column="create_time" typeHandler="com.example.DateToTimestampTypeHandler"/> ``` 这种方式可以灵活处理复杂的映射需求,例如处理不同格式的时间数据或自定义时间转换逻辑[^1]。 ### 3. 数据库字段与 Java 类型匹配 确保数据库中的字段类型与 Java 中使用类型匹配。例如,Oracle 的 `DATE` 类型通常对应 `java.sql.Date` 或 `java.util.Date`,而 `TIMESTAMP` 则更适合映射到 `java.sql.Timestamp`。如果字段包含时间部分,但使用 `DATE` 类型进行映射,则可能会导致时间信息的丢失。 ### 4. 在 SQL 查询中格式化日期 如果需要在查询时对日期进行格式化,可以使用 Oracle 的 `TO_CHAR` 函数将日期转换为字符串: ```xml <result property="createTime" column="create_time" jdbcType="VARCHAR"/> ``` 对应的 SQL 查询如下: ```sql SELECT TO_CHAR(create_time, 'YYYY/MM/DD HH24:MI:SS') AS create_time FROM your_table ``` 这种方式适用于只需要显示日期时间字符串而不需要进一步在 Java 中操作日期对象的场景[^3]。 ### 5. 使用注解配置映射 如果使用注解而非 XML 文件配置映射关系,可以通过 `@Results` 和 `@Result` 注解显式指定 `jdbcType`: ```java @Results({ @Result(property = "createTime", column = "create_time", jdbcType = JdbcType.TIMESTAMP) }) @Select("SELECT * FROM your_table") List<YourEntity> getAll(); ``` 这种方式简化了配置,并且可以与接口绑定使用,提高代码的可读性和可维护性[^2]。 ### 6. 验证数据库与会话的时区设置 Oracle 数据库的日期处理可能受会话时区设置的影响。如果应用程序和数据库的时区不一致,可能会导致时间转换错误。可以通过以下方式检查和设置会话时区: ```sql -- 查看当前会话时区 SELECT SESSIONTIMEZONE FROM DUAL; -- 设置会话时区 ALTER SESSION SET TIME_ZONE = 'UTC'; ``` 在 Java 应用程序中,也可以通过 JDBC 连接字符串指定时区: ```properties jdbc:oracle:thin:@//host:port/service?TNS_ADMIN=/path/to/wallet&oracle.jdbc.timezoneAsRegion=false ``` 确保时区一致可以避免因时区差异导致的时间数据错误[^4]。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值