ICode9

精准搜索请尝试: 精确搜索
首页 > 数据库> 文章详细

Java学习实战教程之Hibernate使用Oracle数据库遇到的几个问题

2021-06-15 16:02:26  阅读:150  来源: 互联网

标签:Hibernate Java sequence 创建 用户 序列 hibernate Oracle


前言
Hibernate作为一个成熟的持久层解决方案,通过简单的配置,可以在不修改源码的情况下,无缝的在不同的数据库上运行。尽管如此,使用不同的数据库仍然会出现一些问题,比如本文要讨论的Oracle中的问题。
 
1.   Hibernate无法创建hibernate_sequence的问题
错误提示:
 

问题分析:
从错误提示上看,查询语句没有找到hibernate_sequence这个序列。到Oracle数据库中查看,果然没有。按道理说,hibernate应该在Oracle中自动生成这个序列,那为什么没有生成呢?原因主要有两个:
1.hibernate的核心配置中没有设置自动建对象的属性,导致无法自动建立序列:

<property name="hibernate.hbm2ddl.auto">update</property>

 
2.其他用户存在hibernate_sequence这个序列,导致当前用户不再创建该序列。
原因:
hibernate在启动时即需要去检测所要创建的序列是否存在,如果存在,则不再创建此序列。在某些情况下,hibernate能够探测到其它用户所创建的同名序列,而被认为不再需要创建序列,这时候如果进行保存数据的操作,就会因为在当前用户下找不到该序列从而导致出错。
要解决这个问题的首要方法是需要找到hibernate判断指定序列是否存在的方法,在hibernate的dialet中,取决于getQuerySequencesString这个方法,此方法返回了查询所有序列的方法。
Hibernate中的与Oracle相关dialet一般配置为Oracle10gDialect、Oracle9iDialect、Oracle8iDialect。从源码我们可以看到他们之间是继承关系,如:Oracle10gDialect extend Oracle9iDialect extend Oracle8iDialect extend Dialet。通过源代码我们可以看出,该方法只是在Oracle8iDialect中进行了覆写,其子类都沿用了该实现。实现代码如下:

public String getQuerySequencesString() {
       return    " select sequence_name from all_sequences"
              + "  union"
              + " select synonym_name"
              + "   from all_synonyms us, all_sequences asq"
              + "  where asq.sequence_name = us.table_name"
              + "    and asq.sequence_owner = us.table_owner";
    }

从代码分析看,它是从all_sequence中寻找所能找到的sequence,而当前用户能找到的sequence全在于当前用户能有多大的权限,以及具体的oracle jdbc实现。在这种情况下,如果当前用户拥有dba权限(开发时候,经常给一个用户授dba权限)或者由于其它某种原因,就能够找到其他用户的sequence了。而如果其他用户也创建了一个叫hibernate_sequence的sequence,那hibernate在当前用户就不能再创建sequence了。
 
知道了这个原因后,如何解决呢?
我们可以创建一个新的OracleDialect,直接继承于Oracle10gDialect,并在新的类中覆盖getQuerySequencesString方法,将其中的sql语句改为从user_sequences(即当前用户的sequence空间)中寻找相应的序列,这样就不会寻找到其它用户的序列了。参考代码如下:

public class Oracle10gDialectEx extends Oracle10gDialect {
public String getQuerySequencesString() {
        return "select sequence_name from user_sequences";
    }
}

 
还有个解决办法,就是去掉该Oracle用户的跨用户访问的权限,如select any table的权限或dba角色。
 
 
2.   使用hibernate生成表不能正确创建表的问题
问题:
hbm2ddl.auto配置成update时,发现hibernate并没有按照默认的生成规则生成相应的数据表信息
分析发现,这里需要引用的表p_menu在另一个用户空间里已经存在了,而hibernate在创建表时,在另一个用户空间中找到了这个表,故不再在当前的用户空间中创建这个表了。而在创建关联表时,由于关联的是本用户空间的表,故有此错误。
hibernate使用了jdbc默认的databasemeta来寻找相应表数据信息,当使用默认的配置时,由于某种原因(并不是每次都能发生,取决于数据库本身以及相应的驱动)。当使用当前用户连接到数据库时,使用databasemeta寻找数据库表信息时,会查询出其它用户的数据表信息(即使当前用户没有相应的权限)。
 
两种解决方案:
1.在hibernate核心配置中配置一个属性:

<property name="hibernate.default_schema">当前连接用户</property>

2.在hbm文件配置中的class元素中指定schema=""的属性

<class name="class"  table="table" schema="当前连接用户">

3.去掉该Oracle用户的跨用户访问的权限,如select any table的权限
 
 
3.   SSH启动中的输出日志中有createClob的info信息的问题
 
在使用SSH+Oracle启动的时候,控制台会打印:
INFO: HHH000424: Disabling contextual LOB creation as createClob() method threw error : java.lang.reflect.InvocationTargetException
如果是使用的Oracle10G,实体类使用了Clob字段的时候,会抛出这个信息。
如果使用的是Oracle11G,实体类使用了复杂的数据类型的时候,也会抛出这个信息。
分析:
这个东西只是个 INFO 级别的,也就是说仅仅是提醒,无关紧要的。但总觉的不爽。如何解决呢?
从驱动上寻找解决方案:
使用Oracle10G,将默认的JDBC驱动ojdbc14升级为更高版本,如Oracle11G的ojdbc6.jar的版本。
从hibernate上寻找解决方案:
修改hibernate配置项hibernate.temp.use_jdbc_metadata_defaults=false。
另外:Hibernate4的官方资料里说11g和10g都是Oracle10gDialect,方言通用,这个没啥影响。

标签:Hibernate,Java,sequence,创建,用户,序列,hibernate,Oracle
来源: https://www.cnblogs.com/cqqfboy/p/14885869.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有