1

我正在开发一个基于 Web 的应用程序来替换基于桌面的应用程序。我需要让它们都在同一个数据库上工作。对于基于 Web 的应用程序,我使用 GWT 和 Hiberate(与 Gilead),在 Tomcat 7.0 上运行。SQL 服务器是 MSSQL 2000。

我得到了例外:

com.microsoft.sqlserver.jdbc.SQLServerException:违反主键约束“PK_CallLog”。无法在对象“CallLog”中插入重复键。

要获得异常,我执行以下步骤:

  1. 使用旧应用程序添加通话记录
  2. 使用新应用程序添加通话记录(使用休眠)。

似乎hibernate正在使用自己的缓存,而不是查看数据库来确定下一个主键应该是什么。
有没有办法通过查看数据库来强制休眠获取下一个密钥?

这是通话记录的映射:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hib.....dtd">

<hibernate-mapping>
    <class name="com.asi.shared.Call" table="CallLog">
        <id name="id" column="callid">
            <generator class="increment"/>
        </id>        
        <property name="caller"/>
        <property name="callDate" column="calldate"/>
        .... other props ....
        <property name="checkOut" column="checkout"/>
        <many-to-one name="customer" class="com.asi.shared.Customer"
                     column="customerid" not-found="ignore"/>
    </class>
</hibernate-mapping>

这是我用来添加新调用的方法:

public Integer saveCall(Call call){
    DebugLog.print("HelpDeskServiceImpl.saveCall(call)");
    Session session = gileadHibernateUtil.getSessionFactory().getCurrentSession();
    session.beginTransaction();
    check(session);
    session.saveOrUpdate(call);
    session.getTransaction().commit();
    return call.getId();
}

通话记录的架构:

if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[CallLog]') and OBJECTPROPERTY(id, N'IsUserTable') = 1)
drop table [dbo].[CallLog]
GO

CREATE TABLE [dbo].[CallLog] (
    [callid] [int] NOT NULL ,
    [caller] [varchar] (50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
    [calldate] [datetime] NULL ,
    .... other columns ....
    [checkout] [varchar] (5) COLLATE SQL_Latin1_General_CP1_CI_AS NULL 
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO

我想尽可能避免更改数据库,我不想破坏旧的应用程序。

4

2 回答 2

0

您将需要更改数据库的定义以自动增加该 id,然后告诉 hibernate 不要自己分配 id 并将其留给数据库。

[callid] [int] NOT NULL IDENTITY(1, 1), % or (10000, 1) or use the highest id.

休眠类:

@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private int callid;

或者使用类似于此处记录的内容供生成器查看数据库:

    <id name="id" column="callid">
        <generator class="hilo">
          <param name="table">CallLog</param>
          <param name="column">callid</param>
        </generator>
    </id>        
于 2011-11-17T17:34:04.117 回答
0

是的,increment生成器使用内部缓存,并且不打算在多个进程可以同时访问数据库时使用。

假设您无法更改数据库和遗留应用程序,并且遗留应用程序也使用increment-like id 生成策略,唯一可能的解决方案是使用改进increment的 -like 策略。

有两种可能的选择:

  • Call在保存每个和手动分配标识符之前发出查询以手动确定最大 id 值

  • 看看IncrementGenerator并实现类似的,而不缓存值

请注意,如果多个事务同时保存,这些策略仍然容易受到可能的 id 冲突Call的影响。

如果您可以更改数据库和遗留应用程序,请查看 dlamblin 的建议。

于 2011-11-17T17:42:52.807 回答