MySQL支持一种" INSERT ... ON DUPLICATE KEY UPDATE ..."语法,允许您"盲目地"插入数据库,并回退到更新现有记录(如果存在).
当您需要快速事务隔离并且要更新的值依赖于数据库中已有的值时,这非常有用.
作为一个人为的例子,假设您想要计算在博客上查看故事的次数.使用此语法执行此操作的一种方法可能是:
INSERT INTO story_count (id, view_count) VALUES (12345, 1)
ON DUPLICATE KEY UPDATE set view_count = view_count + 1
Run Code Online (Sandbox Code Playgroud)
这比开始交易更有效,更有效,并且处理新故事登上头版时发生的不可避免的异常.
我们怎么能用Hibernate做同样的事情,或者实现同样的目标呢?
首先,Hibernate的HQL解析器将抛出异常,因为它不了解特定于数据库的关键字.事实上,HQL不喜欢任何显式插入,除非它是" INSERT ... SELECT ....".
其次,Hibernate将SQL限制为仅选择.如果您尝试呼叫,Hibernate将抛出异常session.createSQLQuery("sql").executeUpdate().
第三,saveOrUpdate在这种情况下,Hibernate 不符合要求.您的测试将通过,但如果您每秒有多个访问者,则会导致生产失败.
我真的要颠覆Hibernate吗?
我需要从每日CSV文件中消耗大量数据.CSV包含大约120K条记录.使用hibernate时,这会慢慢爬行.基本上,当使用saveOrUpdate()时,似乎hibernate在每个INSERT(或UPDATE)之前都在执行SELECT; 对于使用saveOrUpdate()持久化的每个实例,在实际INSERT或UPDATE之前发出SELECT.我可以理解它为什么会这样做,但它对于进行批量处理非常低效,而且我正在寻找替代方案
我确信性能问题在于我使用hibernate的方式,因为我有另一个版本使用本机SQL(以相同的方式解析CSV)以及围绕这个新版本的字面运行圈子)
那么,对于实际问题,是否存在一个hibernate替代mysqls"INSERT ... ON DUPLICATE"语法?
或者,如果我选择为此执行本机SQL,我可以在hibernate事务中执行本机SQL吗?意思是,它会支持提交/回滚吗?
我正在编写一个应用程序,将来自第三方数据源的实体同步到我们自己的架构中,其间有转换/映射步骤.我正在使用Hibernate来表示和持久化我们自己的架构中的实体.我遇到的一个问题是我的一个表上有一个唯一的多列键.我希望看到的行为类似于upsert:当Hibernate持久化实体并检测到唯一约束违规时,它会执行更新.我们正在使用MySQL,它提供了INSERT ... ON DUPLICATE KEY UPDATE语法,但我不确定如何或者是否可以使用Hibernate来使用它?
我想我总是可以尝试插入,如果我捕获异常做更新,但这似乎是hacky和次优.有关干净方式的任何提示吗?
我正在寻找一种方法来保存或更新记录,根据表的唯一键,由几列组成).
我希望实现相同的功能INSERT ... ON DUPLICATE KEY UPDATE- 意味着盲目保存记录,并让DB/Hibernate插入一个新的,或者如果唯一键已经存在则更新现有的.
我知道我可以使用@SQLInsert( sql="INSERT INTO .. ON DUPLICATE KEY UPDATE"),但我希望不要编写自己的SQL并让Hibernate完成这项工作.(我假设它会做得更好 - 否则为什么要使用Hibernate?)
我有一个Keyword和一个KeywordType实体.有很多类型的关键字.
尝试保留类型的第二个关键字时,违反了唯一约束并回滚了事务.
搜索我发现了几个可能性(其中一些来自不同的背景,所以我不确定它们的有效性在这里) - 这篇文章和这篇文章建议捕获对我没有用的例外,因为我最终在我开始的地方并且仍然需要以某种方式持久保存关键字.
同样适用于锁定提出了不同的situaltion 这里
自定义插入在提出陈述这个和这个职位是行不通的正确我想,因为我使用的是Oracle而不是MySQL和woulnd喜欢扎到Hibernate实现.
一种不同的解决方法是尝试在生成关键字的代码中首先检索类型,并在找到关键字时将其设置为关键字,否则创建一个新关键字.
那么,什么是最好的 - 最强大,可移植(适用于不同的数据库和持久性提供商)和理智的方法?
谢谢.
涉及的实体:
public class Keyword {
@Id
@GeneratedValue
private long id;
@Column(name = "VALUE")
private String value;
@ManyToOne
@JoinColumn(name = "TYPE_ID")
private KeywordType type;
...
}
Run Code Online (Sandbox Code Playgroud)
和
@Entity
@Table(uniqueConstraints = {@UniqueConstraint(columnNames = { "TYPE" }) })
public class KeywordType {
@Id
@GeneratedValue
private long id;
@Column(name = "TYPE")
private String type;
...
}
Run Code Online (Sandbox Code Playgroud) @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 …Run Code Online (Sandbox Code Playgroud) https://docs.jboss.org/hibernate/orm/5.2/javadocs/org/hibernate/Interceptor.html 表示 onPrepareStatement(String sql) 已弃用。如果您希望检查和更改 SQL 语句,请改为提供 StatementInspector。
但我不清楚如何在应用程序级别的 Hibernate 中配置 StatementInspector (我不想在每个 Hibernate 会话级别设置它)。