在某些情况下,您的JEE应用程序需要支持Postgres和Oracle作为数据库。
Hibernate应该在这里完成工作,但是有些细节值得一提。
在为已经运行Oracle的应用程序启用Postgres时,我遇到了以下棘手的部分:
-
BLOBs
支持, -
CLOBs
支持, - Oracle不知道
Boolean
类型(使用Integer
),并且 -
DUAL
表。
这些是我必须使用的技巧,以使@Entity
类在这两种方法上运行。
请注意,我已经将Postgres 9.3和Hibernate 4.2.1.SP1一起使用了。
BLOB支持
Postgres的问题在于它提供两种类型的BLOB存储:
-
bytea
–表中存储的数据 -
oid
–表仅保存存储在其他位置的数据的标识符
我猜在大多数情况下,您都可以像我一样使用bytea
。 据我所读,另一个用于一些大数据(千兆字节),因为它支持IO操作流。
好吧,听起来很高兴有这样的支持,但是在这种情况下使用Hibernate可能会带来很多问题(由于需要使用特定的批注),尤其是在您尝试与Oracle兼容的情况下。
要在此处查看问题,请参见StackOverflow:byte []的正确休眠注释
所有组合均在此处描述:
annotation postgres oracle works on
-------------------------------------------------------------
byte[] + @Lob oid blob oracle
byte[] bytea raw(255) postgresql
byte[] + @Type(PBA) oid blob oracle
byte[] + @Type(BT) bytea blob postgresql
其中@Type(PBA)
代表@Type(type="org.hibernate.type.PrimitiveByteArrayBlobType")
和@Type(BT)
代表: @Type(type="org.hibernate.type.BinaryType")
。
这些会导致各种Postgres错误,例如:
错误:列“ foo”的类型为oid,但表达式的类型为bytea
要么
错误:列“ foo”的类型为bytea,但表达式的类型为oid
好吧,似乎有一个解决方案,它仍然包括对Hibernate库的修补(我在使用3.rd party库时看到的最后一个选择)。
Hibernate的专家们还引用了官方博客文章,主题是PostgreSQL和BLOB 。 仍然在博客文章中描述的解决方案似乎对我不起作用,并且基于这些评论,似乎对更多人无效。
BLOB已解决
好,现在是乐观的部分。
经过大量调试后,我最终得到了Entity定义,如下所示:
@Lob
private byte[] foo;
Oracle对此没有任何麻烦,而且我不得不以一种方式自定义Postgres方言:
public class PostgreSQLDialectCustom extends PostgreSQL82Dialect {@Overridepublic SqlTypeDescriptor remapSqlTypeDescriptor(SqlTypeDescriptor sqlTypeDescriptor) {if (sqlTypeDescriptor.getSqlType() == java.sql.Types.BLOB) {return BinaryTypeDescriptor.INSTANCE;}return super.remapSqlTypeDescriptor(sqlTypeDescriptor);}
}
而已! 很简单吧? 这适用于在Postgres中持久保存bytea
类型的列(因为这适合我的用例)。
CLOB支持
错误配置中的错误如下所示:
org.postgresql.util.PSQLException: Bad value for type long : ...
因此,首先我找到了以下解决方案(在带有Hibernate 3.6的PostgreSQL上的String LOB上 ):
@Lob
@Type(type = "org.hibernate.type.TextType")
private String foo;
嗯,那行得通,但仅适用于Postgres。
然后有一个建议(关于StackOverflow:Postgres具有JDBC的Postgres UTF-8克隆 )可用于:
@Lob
@Type(type="org.hibernate.type.StringClobType")
private String foo;
那为我指明了正确的方向(有趣的是,这只是对一些答案的评论)。 它非常接近,但是在所有情况下都不适用于我,仍然导致测试出错。
CLOB已解决
重要的是org.hibernate.type.StringClobType
中的@deprecation
javadocs,这使我开始工作:
@Lob
@Type(type="org.hibernate.type.MaterializedClobType")
private String foo;
这适用于Postgres和Oracle,而无需任何进一步的黑客(在Hibernate方面)。
布尔型
Oracle不知道Boolean
类型,而麻烦是Postgres知道。 由于也存在一些简单的SQL,我最终在Postgres中遇到错误:
错误:“ foo”列的类型为布尔值,但表达式的类型为整数
我决定在Postgres中启用从Integer
到Boolean
,而不是固定所有普通的SQL位置(以论坛:自动从Integer到Boolean的转换 ):
update pg_cast set castcontext = 'i' where oid in ( select c.oid from pg_cast c inner join pg_type src on src.oid = c.castsource inner join pg_type tgt on tgt.oid = c.casttarget where src.typname like 'int%' and tgt.typname like 'bool%');
请注意,您应该按用户权限运行SQL
更新,以更新目录(可能不是您的postgres用户用于从应用程序进行数据库连接),正如我在Stackoverflow上了解到的:Postgres –拒绝更新pg_catalog.pg_cast的权限 。
双表
我遇到的Oracle中还有一个更具体的内容。 如果您使用普通的SQL,则在Oracle中提供了DUAL
表(请参阅Wikipedia上的更多信息),这可能会对Postgres造成伤害。
解决方案仍然很简单。 在Postgres中创建一个视图,该视图将达到类似的目的。 可以这样创建:
create or replace view dual as select 1;
结论
好吧,应该是这样。 享受与跨数据库兼容的JEE应用程序。
翻译自: https://www.javacodegeeks.com/2014/03/postgres-and-oracle-compatibility-with-hibernate.html