@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
如果 accountsId
是 null
. 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 equalsunsaved-value
(see below), it is considered unsaved and thensave()
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 aunsaved-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/