Hibernate savOrUpdate 仅插入或更新

标签 hibernate

@Autowired
private SessionFactory sessionFactory;
public String getAccountsDetails(List<Account> accountList) {
    Session session = sessionFactory.openSession();
    for (Account account : accountList) {
        int i = 0;
        AccountDetails accountDetails = new AccountDetails();
        accountDetails.setAccountsId(Long.parseLong(account.getId()));//LINE no -20
        accountDetails.setName(account.getName());
        accountDetails.setSubAccount(account.getAccountSubType());
        session.saveOrUpdate(accountDetails);
        if (++i % 20 == 0) {
            session.flush();  
            session.clear();  
        } 
    }
        session.getTransaction().commit();
        session.close();
}

输出:

即使数据库中没有数据,这也总是运行更新。
   Hibernate: update name=?, subaccount=? where accounts_id=?
    ....

如果我在 LINE no-20 中评论帐户 ID,它总是运行插入。

hibernate :插入表测试...
……

dto类:
@Entity
@Table(name="test")
public class AccountDetails{
    @Id
    @GeneratedValue
    @Column(name = "accounts_id")
    private Long accountsId;

    @Column(name = "name")
    private String name;

    @Column(name = "subaccount")
    private String subAccount;

}

询问:
甲骨文数据库:
 create table test (accounts_id NUMBER(10) NOT NULL PRIMARY KEY, 
    name VARCHAR(100),
    subaccount VARCHAR(100) 
    )

我的要求是如果数据库中没有数据,则插入否则更新。

编辑

我在我的 dto 中创建了一个新字段:
@Version
@Column(name = "version")
private long version;

并在 db 中创建了一个列作为版本号(100)。每当我运行应用程序时,它总是首先运行一个 updte 语句,然后它抛出 StaleObjectStateException 为:
Hibernate: update test set accountsubtype=?, accounttype=?, acctnum=?, active=?, currentbalance=?, currentbalancewithsubaccounts=?, description=?, fullyqualifiedname=?, name=?, subaccount=?, version=? where accounts_id=? and version=?
ERROR 2014-09-22 11:57:25,832 [[qbprojects].connector.http.mule.default.receiver.04] org.hibernate.event.def.AbstractFlushingEventListener: Could not synchronize database state with session
org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [com.trinet.mulesoft.quickbooks.dto.AccountDetails#63]
    at org.hibernate.persister.entity.AbstractEntityPersister.check(AbstractEntityPersister.java:1932)
    at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:2576)

最佳答案

TL;博士

在您的情况下,saveOrUpdate()将产生:

  • 一个 INSERT如果 accountsIdnull .
  • 一个 UPDATE除此以外。

  • 这就是为什么当你有第 20 行( accountDetails.setAccountsId(...); )时,它是 UPDATE ing。

    最简单的方法可能是自己检查并调用 save()如果 accountsId尚不存在或update()除此以外。

    细节:

    Automatic State Detection - 斜体是我写的:

    saveOrUpdate() does the following:

    • if the object is already persistent in this session, do nothing;
    • if another object associated with the session has the same identifier, throw an exception;
    • if the object has no identifier property, save() it;
      • No identifier property means no @Id or XML equivalent.
    • if the object's identifier has the value assigned to a newly instantiated object, save() it;
      • Notice that newly instantiated object is defined by the unsaved-value attribute.
      • In other words, this bullet says: if the @Id property value equals unsaved-value (see below), it is considered unsaved and then save() it.
      • This is your scenario. Notice that you are using unsaved-value=null because it is the default.
    • if the object is versioned by a <version> or <timestamp>, and the version property value is the same value assigned to a newly instantiated object, save() it;
      • This is the same as the item before, but with the <version> and <timestamp> properties instead of the @Id property.
      • Notice also both <version> and <timestamp> also have a unsaved-value=null attribute to define what is an unsaved or newly instantiated object.
    • otherwise update() the object


    有关 unsaved-value attribute 的更多详细信息(下面的引用来自 unsaved-value@Id/identifier 属性):

    unsaved-value (optional - defaults to a "sensible" value): an identifier property value that indicates an instance is newly instantiated (unsaved), distinguishing it from detached instances that were saved or loaded in a previous session.



    对于 Long标识符,“明智的”默认值很可能是 null .

    解决方法:

    如果只是想分配标识符,我们可以使用 <generator class="assigned"/>没关系。但你不想两个 of worlds:有时分配并生成其他的。

    1 - 如上所述,一种选择是自己检查对象是否已经存在并调用save()update()因此。

    2 - 另一个选项是 implement an Interceptor isTransient() method被覆盖。在这种方法中,您必须再次检查实体是否已经存在。优点:您只需执行一次(在 Interceptor 上)。缺点:嗯,它是一个Interceptor你必须把它和它需要的一切连接起来。

    3 - 最后,docs hint有可能(我们必须确认)你可以通过使用生成器和设置属性 unsaved-value="undefined" 来做你想做的事。 .但是你必须求助于 XML 映射,因为你 can't set the unsaved-value through annotations :

    The unsaved-value attribute is almost never needed in Hibernate and indeed has no corresponding element in annotations.



    设置unsaved-value通过 XML 将类似于:
    <id name="accountsId" column="accounts_id" type="long" unsaved-value="undefined">
        <generator class="auto" />
    </id> 
    

    关于Hibernate savOrUpdate 仅插入或更新,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25952569/

    相关文章:

    java - 如何通过很多id找到一些数据?

    Spring Hibernate 事务管理

    Hibernate 通过将值与 2 个串联字段匹配来获取记录

    java - Hibernate 和 FlexJSON 的惰性初始化错误

    java - 将 Hibernate 与动态 Eclipse 插件一起使用

    java - REST API 中线程 "main"java.lang.IllegalArgumentException 中出现异常

    java - hibernate中的一对多关联

    java - 有没有办法使用 Spring Boot 和 Hibernate 使用 postgres 批量插入具有 UUID 主键的实体?

    java - 在 Hibernate 视角下生成代码时忽略表前缀

    java - Hibernate 可审计的多对多关系