我正在使用 Hibernate 5.2.9.Final (核心和Envers的版本)。将审计添加到表时,使用:
创建CREATE TABLE Transaction (
id BIGINT PRIMARY KEY
,name VARCHAR(120) NOT NULL
,currency CHAR(3) REFERENCES Currency(code)
,country VARCHAR(3)
,status INTEGER
,description VARCHAR(1000)
,amount NUMERIC(30,5)
,closingDate TIMESTAMP WITH TIME ZONE
,rangeStart TIMESTAMP WITH TIME ZONE
,rangeEnd TIMESTAMP WITH TIME ZONE
,isin VARCHAR(12)
,version INTEGER NOT NULL DEFAULT 0
);
Hibernate Envers创建了_AUD
表,它吐出了以下内容:
CREATE TABLE transaction_aud (
id bigint NOT NULL,
rev integer NOT NULL,
revtype smallint,
closingdate timestamp without time zone,
closingdate_mod boolean,
country character varying(255),
country_mod boolean,
currency character varying(255),
currency_mod boolean,
description character varying(255),
description_mod boolean,
amount numeric(19,2),
isin character varying(255),
isin_mod boolean,
name character varying(255),
name_mod boolean,
rangeend timestamp without time zone,
rangeend_mod boolean,
rangestart timestamp without time zone,
rangestart_mod boolean,
status integer,
status_mod boolean
);
实体映射文件是:
<entity name="Transaction" class="com.project.datamodel.TransactionTO" access="FIELD">
<attributes>
<id name="id" access="PROPERTY">
<generated-value strategy="SEQUENCE" generator="TransactionIdSeq" />
<sequence-generator name="TransactionIdSeq" sequence-name="TransactionIdSeq" allocation-size="1" />
</id>
<basic name="name" optional="false"> <column length="120" /> </basic>
<basic name="currency"> <column columnDefinition="CHAR(3)" /> </basic>
<basic name="country"> <column length="3" /> </basic>
<basic name="status" />
<basic name="description"> <column length="1000" /> </basic>
<basic name="amount"> <column columnDefinition="NUMERIC(30,5)" /> </basic>
<basic name="closingDate"> <column columnDefinition="TIMESTAMP WITH TIME ZONE" /> </basic>
<basic name="rangeStart"> <column columnDefinition="TIMESTAMP WITH TIME ZONE" /> </basic>
<basic name="rangeEnd"> <column columnDefinition="TIMESTAMP WITH TIME ZONE" /> </basic>
<basic name="isin"> <column length="12" /> </basic>
<transient name="favorite" />
<version name="version" />
</attributes>
</entity>
注意:我已从实体中移除了所有已加入的many-to-one
关系,因为它们只是添加批量而不会影响我的主要问题。
问题是:
VARCHAR
/ CHAR
字段类型&amp;长度忽略所有CHAR
和VARCHAR
字段,无论其长度如何,都会转换为VARCHAR(255)
/ character varying(255)
字段。
在description
字段中保存通常应包含1000个字符的数据时,这会导致问题。超过255限制大小后,数据库引擎会因异常而导致异常,因为数据对于列大小来说太宽了。
此外,将CHAR(3)
投射到VARCHAR(255)
会有什么意义?这对我来说似乎非常浪费,但我希望还有其他一些我不知道的原因。
TIMESTAMP
时区属性被忽略 TIMESTAMP
- 类型字段从显式定义 WITH 更改为定义为未定义时区的时区(我知道PostgreSQL中的TIMESTAMP
类型 - 这是我的后备数据库引擎 - 默认情况下没有时区定义它们。)
定义为NUMERIC (30,5)
的金额字段在审计表中定义为NUMERIC(19,2)
。
为什么Hibernate Envers在生成_AUD
表时不尊重原始表的列类型?
我还发现它尊重一个表格的大小:LocalizedMessage
<entity name="LocalizedMessage" class="com.project.datamodel.to.LocalizedMessageTO" access="FIELD">
<attributes>
<id name="id" access="PROPERTY">
<generated-value strategy="SEQUENCE" generator="LocalizedMessageIdSeq" />
<sequence-generator name="LocalizedMessageIdSeq" sequence-name="LocalizedMessageIdSeq" allocation-size="1" />
</id>
<many-to-one name="adminMessage"> <join-column name="adminMessageId" /> </many-to-one>
<basic name="localeCode"> <column length="7" /> </basic>
<basic name="message"> <column length="500" /> </basic>
<version name="version" />
</attributes>
</entity>
原始表定义是:
CREATE TABLE LocalizedMessage (
id BIGINT PRIMARY KEY
,adminMessageId BIGINT REFERENCES AdminMessage(id)
,localeCode VARCHAR(7)
,message VARCHAR(500)
,version INTEGER NOT NULL DEFAULT 0
);
生成的_AUD
表是:
CREATE TABLE localizedmessage_aud (
id bigint NOT NULL,
rev integer NOT NULL,
revtype smallint,
localecode character varying(7),
localecode_mod boolean,
message character varying(500),
message_mod boolean,
adminmessageid bigint,
adminmessage_mod boolean
);
注意:这是在将长度指令添加到映射文件后完成的。现在唯一有问题的字段是TIMESTAMP WITH TIME ZONE
和NUMERIC
字段(其中精度已更改)以及CHAR()
字段。
实质上,不尊重JPA XML映射文件的columnDefinition
属性。
为org.hibernate.envers.boot.internal.AdditionalJaxbMappingProducerImpl
生成的日志条目启用跟踪日志记录,如下所示:
2017-06-10 15:52:19,981 TRACE org.hibernate.envers.boot.internal.AdditionalJaxbMappingProducerImpl ~ ------------------------------------------------------------
2017-06-10 15:52:19,984 TRACE org.hibernate.envers.boot.internal.AdditionalJaxbMappingProducerImpl ~ Envers-generate entity mapping -----------------------------
<hibernate-mapping auto-import="false">
<class entity-name="com.project.datamodel.to.TransactionTO_AUD" discriminator-value="Transaction" table="Transaction_AUD" schema="app" abstract="false">
<composite-id name="originalId">
<key-property name="id" type="long">
<column name="id" length="255" scale="2" precision="19"/>
</key-property>
<key-many-to-one type="integer" class="com.project.datamodel.to.CustomRevisionEntity" name="REV">
<column name="REV"/>
</key-many-to-one>
</composite-id>
<property insert="true" update="false" name="REVTYPE" type="org.hibernate.envers.internal.entities.RevisionTypeType"/>
<property insert="true" update="false" name="closingDate" type="timestamp">
<column name="closingDate" length="255" scale="2" precision="19"/>
</property>
<property insert="true" update="false" name="closingDate_MOD" type="boolean"/>
<property insert="true" update="false" name="country" type="string">
<column name="country" length="3" scale="2" precision="19"/>
</property>
<property insert="true" update="false" name="country_MOD" type="boolean"/>
<property insert="true" update="false" name="currency" type="string">
<column name="currency" length="255" scale="2" precision="19"/>
</property>
<property insert="true" update="false" name="currency_MOD" type="boolean"/>
<property insert="true" update="false" name="description" type="string">
<column name="description" length="1000" scale="2" precision="19"/>
</property>
<property insert="true" update="false" name="description_MOD" type="boolean"/>
<property insert="true" update="false" name="amount" type="big_decimal">
<column name="amount" length="255" scale="2" precision="19"/>
</property>
<property insert="true" update="false" name="amount_MOD" type="boolean"/>
<property insert="true" update="false" name="isin" type="string">
<column name="isin" length="12" scale="2" precision="19"/>
</property>
<property insert="true" update="false" name="isin_MOD" type="boolean"/>
<property insert="true" update="false" name="name" type="string">
<column name="name" length="120" scale="2" precision="19"/>
</property>
<property insert="true" update="false" name="name_MOD" type="boolean"/>
<property insert="true" update="false" name="rangeEnd" type="timestamp">
<column name="rangeEnd" length="255" scale="2" precision="19"/>
</property>
<property insert="true" update="false" name="rangeEnd_MOD" type="boolean"/>
<property insert="true" update="false" name="rangeStart" type="timestamp">
<column name="rangeStart" length="255" scale="2" precision="19"/>
</property>
<property insert="true" update="false" name="rangeStart_MOD" type="boolean"/>
<property insert="true" update="false" name="status" type="converted::com.project.datamodel.converter.StatusConverter">
<column name="status" length="255" scale="2" precision="19"/>
</property>
<property insert="true" update="false" name="status_MOD" type="boolean"/>
</class>
</hibernate-mapping>
对于LocalizedMessage表:
2017-06-10 15:52:19,947 TRACE org.hibernate.envers.boot.internal.AdditionalJaxbMappingProducerImpl ~ ------------------------------------------------------------
2017-06-10 15:52:19,949 TRACE org.hibernate.envers.boot.internal.AdditionalJaxbMappingProducerImpl ~ Envers-generate entity mapping -----------------------------
<?xml version="1.0" encoding="UTF-8"?>
<hibernate-mapping auto-import="false">
<class entity-name="com.project.datamodel.to.LocalizedMessageTO_AUD" discriminator-value="LocalizedMessage" table="LocalizedMessage_AUD" schema="app" abstract="false">
<composite-id name="originalId">
<key-property name="id" type="long">
<column name="id" length="255" scale="2" precision="19"/>
</key-property>
<key-many-to-one type="integer" class="com.project.datamodel.to.CustomRevisionEntity" name="REV">
<column name="REV"/>
</key-many-to-one>
</composite-id>
<property insert="true" update="false" name="REVTYPE" type="org.hibernate.envers.internal.entities.RevisionTypeType"/>
<property insert="true" update="false" name="localeCode" type="string">
<column name="localeCode" length="7" scale="2" precision="19"/>
</property>
<property insert="true" update="false" name="localeCode_MOD" type="boolean"/>
<property insert="true" update="false" name="message" type="string">
<column name="message" length="500" scale="2" precision="19"/>
</property>
<property insert="true" update="false" name="message_MOD" type="boolean"/>
<property insert="true" update="false" name="adminMessage_id" type="long">
<column name="adminMessageId" length="255" scale="2" precision="19"/>
</property>
<property insert="true" update="false" name="adminMessage_MOD" type="boolean"/>
</class>
</hibernate-mapping>
为什么它适用于一种情况而不适用于另一种情况?
答案 0 :(得分:1)
如我的评论中所述,Envers不会以任何方式从现有数据库架构解释其架构。实际上,它的整个映射模型生成过程都是基于检查Hibernate ORM的启动时映射模型,您可以在org.hibernate.mapping
中找到它。
这意味着对于诸如列长度之类的内容,它们应该通过注释或XML映射文件作为映射模型的一部分提供,以便Envers生成使用相同长度的属性,或者在某些情况下自定义列定义
如果在XML映射文件中指定长度并重新生成Envers架构,它应该与您的Hibernate实体架构非常接近。
更新的
您没有看到在Envers映射中呈现的列定义的原因是因为您的JPA ORM.XML文件无效,它不遵循模式定义,因此Envers不会看到您的列Hibernate也不会定义。
你的映射应该是:
<column column-definition="TIMESTAMP WITH TIME ZONE"/>
您会注意到该属性的名称为column-definition
,而不是columnDefinition
。