@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();
}
Run Code Online (Sandbox Code Playgroud)
输出:
即使数据库中没有数据,它也会始终运行更新。
Hibernate: update name=?, subaccount=? where accounts_id=?
....
Run Code Online (Sandbox Code Playgroud)
如果我在第 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;
}
Run Code Online (Sandbox Code Playgroud)
查询:Oracle数据库:
create table test (accounts_id NUMBER(10) NOT NULL PRIMARY KEY,
name VARCHAR(100),
subaccount VARCHAR(100)
)
Run Code Online (Sandbox Code Playgroud)
我的要求是如果数据库中没有数据则插入,否则更新。
编辑
我在我的 dto 中创建了一个新字段:
@Version
@Column(name = "version")
private long version;
Run Code Online (Sandbox Code Playgroud)
并在数据库中创建一列作为版本号(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)
Run Code Online (Sandbox Code Playgroud)
在你的情况下,saveOrUpdate()将生成:
INSERT如果accountsId是null。UPDATE。这就是为什么当你有第 20 行 ( accountDetails.setAccountsId(...);) 时,它是UPDATEing。
最简单的方法可能是自己检查它,save()如果accountsId尚不存在或update()其他情况则调用。
请参阅自动状态检测-斜体是我写的:
saveOrUpdate()执行以下操作:
- 如果该对象已在此会话中持久化,则不执行任何操作;
- 如果与会话关联的另一个对象具有相同的标识符,则抛出异常;
- 如果对象没有标识符属性,
save()则;
- 没有标识符属性意味着没有
@Id或 XML 等效项。- 如果对象的标识符具有分配给新实例化的对象的值
save();
- 请注意,新实例化的对象是由属性定义的
unsaved-value。- 换句话说,这个项目符号说:如果
@Id属性值等于unsaved-value(见下文),则认为未保存,然后就save()可以了。- 这是你的场景。请注意,您正在使用它,
unsaved-value=null因为它是默认值。- 如果该对象由
<version>或进行版本控制<timestamp>,并且版本属性值与分配给新实例化的对象的值相同save();
- 这与之前的项目相同,但使用
<version>和<timestamp>属性而不是@Id属性。- 还要注意,
<version>和<timestamp>都有一个unsaved-value=null属性来定义什么是未保存的或新实例化的对象。- 否则
update()该对象
unsaved-value有关该属性的更多详细信息(下面的引用来自unsaved-value/ @Ididentifier 属性):
unsaved-value(可选 - 默认为“合理”值):指示实例新实例化(未保存)的标识符属性值,将其与先前会话中保存或加载的分离实例区分开来。
对于Long标识符,“合理”的默认值最有可能是null。
如果只是想分配标识符,我们可以使用<generator class="assigned"/>它就可以了。但你不想要两个世界:有时分配并生成其他世界。
1 - 如上所述,一种选择是检查对象是否已存在,并相应地调用save()或update()。
2 - 另一种选择是使用重写的方法来实现Interceptor。在该方法中,您必须再次检查该实体是否已存在。优点:您只需实现一次(在 上)。缺点:嗯,它是一个,你必须连接它以及它需要的其他一切。isTransient()InterceptorInterceptor
3 - 最后,文档暗示有可能(我们必须确认)您可以通过使用生成器和设置属性来执行您想要的操作unsaved-value="undefined"。但是您必须求助于 XML 映射,因为您无法设置unsaved-valuethrough 注释:
unsaved-valueHibernate 中几乎从不需要该属性,并且注释中确实没有相应的元素。
通过 XML设置unsaved-value类似于:
<id name="accountsId" column="accounts_id" type="long" unsaved-value="undefined">
<generator class="auto" />
</id>
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
17768 次 |
| 最近记录: |