美国上市公司,专注Java培训21年

java中Hibernate使用Oracle数据库遇到的几个问题


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

1. Hibernate无法创建hibernate_sequence的问题

错误提示:

Hibernate无法创建hibernate_sequence的问题
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,方言通用,这个没啥影响。

版权声明:部分文字转载来自公开网络,版权归作者本人所有,推送文章除非无法确认,我们都会注明作者和来源。如果出处有误或侵犯到原作者权益,请与我们联系删除或授权事宜。


【免责声明】本文部分系转载,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责,如涉及作品内容、版权和其它问题,请在30日内与我们联系,我们会予以重改或删除相关文章,以保证您的权益!

Java开发高端课程免费试学

大咖讲师+项目实战全面提升你的职场竞争力

  • 海量实战教程
  • 1V1答疑解惑
  • 行业动态分析
  • 大神学习路径图

相关推荐

更多
  • Java编程工具用哪个最好
    Java编程工具用哪个最好
    Java编程工具用哪个最好?Java编程工具的选择取决于个人的偏好、项目需求和开发环境。以下是一些常用的Java编程工具: 详情>>

    2024-04-03

  • 好用的Java编写软件
    好用的Java编写软件
    Java是一种广泛使用的编程语言,因其跨平台、安全性和稳定性而受到许多开发者的喜爱。Java被用于开发各种类型的软件,从桌面应用程序到企业级服务器端应用程序。以下是一些常见的、用Java编写的软件示例: 详情>>

    2024-04-02

  • Java测试工具有哪些?
    Java测试工具有哪些?
    Java测试工具有哪些?Java测试工具有很多,可以用于不同的测试阶段和目的,包括单元测试、集成测试、性能测试等。以下是一些流行的Java测试工具: 详情>>

    2024-04-02

  • Java有哪些课程?
    Java有哪些课程?
    Java是一种功能丰富且易于学习的编程语言,适用于多种不同的应用领域。目前,许多机构和在线平台都提供了丰富的Java相关课程,课程内容涵盖了Java的基础知识、高级特性以及实际应用等方面。以下是一些Java课程的示例: 详情>>

    2024-03-14

  • Java开班时间

    收起