我正在尝试审核用户执行的操作导致对相应表的更改。例如,如果用户要在两个帐户之间转移资金,则会生成以下事件序列:
所有表的父审核消息将是:“用户生成的金额转移金额”
这是通过以下架构实现的: schema
alt text http://img48.imageshack.us/img48/7460/auditloggingiv6.png
问题是如何在休眠中表示这一点?
我创建了以下内容:
在Balance和Transfer的映射文件中
<set name="auditRecords" table="TransferAuditRecord" inverse="false" cascade="save-update">
<key>
<column name="AuditRecordID" not-null="true" />
</key>
<one-to-many class="audit.AuditRecord"/>
</set>
转移和平衡类然后实现具有方法的IAuditable
public void setAuditRecords(Set<AuditRecord> auditRecord);
public Set<AuditRecord> getAuditRecords();
在AuditRecord的映射文件中,我有:
<many-to-one name="parentAuditRecord" lazy="false"
column="parent_id"
class="audit.AuditRecord"
cascade="all" />
然后在使用AOP和Hibernate Interceptor的Logging类中我有:
AuditRecord auditRecord = new AuditRecord();
auditRecord.setUser(userDAO.findById(
org.springframework.security.context.SecurityContextHolder.getContext()
.getAuthentication().getName()));
auditRecord.setParentAuditRecord(getCurrentActiveServiceRecord());
auditable.getAuditRecords().add(auditRecord);
然后在服务类中,我调用以下方法,包含在事务中:
save(balance1);
save(balance2);
transfer.setPassed(true);
update(transfer);
使用带有线程安全堆栈的AOP创建parentAuditRecord,并使用方法上的注释设置AuditRecordType_id。
我遗漏了转移表上的“通过”列。以前我调用save(transfer)将传输量插入Transfer表,并将传递设置为false。 (此操作也经过审核)。
我的要求比上面的例子稍微复杂一点:P
因此上述事件的顺序应为:
但是,上面定义的级联选项在update语句中失败。 Hibernate拒绝将记录插入到多对多表中(即使AuditRecord Mapping上的unsaved-value =“any”)。我总是希望在多对多表中插入行,因此可能有一个Transfer有许多审核记录标记以前的事件。但是,最新事件确定用户想要查看的消息。 Hibernate要么尝试更新多对多表和以前的AuditRecord条目,要么只是拒绝插入AuditRecord和TransferAuditRecord,抛出一个TransientObjectException。
审核消息的检索方式如下:
msg=... + ((AuditRecord) balance.getAuditRecords().toArray()[getAuditRecords().size()-1])
.getParentAuditRecord().getAuditRecordType().getDescription() + ...;
该消息应该是这样的: “用户名设置转移到2008年10月11日中午12点”
编辑我决定使用显式映射多对多表(带有关联的接口),然后在afterTransactionCompletion中,在父审计记录上调用save(将保存级联到子审计记录)然后在所有子映射表上显式保存接口。这不是真正的审计历史记录,而是记录用户操作的非侵入性方法。如果我以后需要更完整的审核历史,我会研究Envers。
答案 0 :(得分:1)
似乎parentAuditRecord和transferauditrecord之间的关系和余额auditrecord不应该是一对多。当我读到您输入的内容时,我将其视为每个子类使用该审计层次结构的表,这是一对一的关系。
http://www.hibernate.org/hib_docs/reference/en/html/inheritance.html
您可能还想查看JBoss的Envers项目。
答案 1 :(得分:0)
在设计层面,似乎只有插入式数据库设计才能在这里实现奇迹。
如果你想保持现在的状态(我确信你这样做),你可以查看Hibernate监听器/拦截器/事件(在doc:http://www.hibernate.org/hib_docs/v3/reference/en-US/html_single/中明确定义)
另外,我只是研究了JBoss Envers,它看起来也很有用。