我真的很喜欢Hibernate,但我也不知道同时具备强大功能和欺骗性的工具。 我可以写一本书,讲述仅与Hibernate相关的生产和货物崇拜编程中的意外情况。 与用户相比,与工具相比,这更多的是问题,但请不要让它过于保修。
所以,这是一个最近的例子。
问题
我们需要一个后台作业,该作业列出目录中的所有文件,并将每个文件的条目插入表中。
天真的解决方案
该作业以前是用Bash编写的,并且可以从表中直接读取SQL。 所以,盲人,让我们写一些直接的SQL!
for (String fileName : folder.list()) {SQLQuery sql = session.getDelegate().createSQLQuery("insert into dir_contents values (?)");sql.setString(0, fileName);sql.executeUpdate();
}
它行得通吗? 当然可以。
现在,如果文件夹中有10,000个文件怎么办? 如果您还有一个不太优雅的域模型 ,在一个上下文中有太多的实体类,数千个实例和两级缓存,该怎么办?
突然,这项琐碎的工作需要10分钟才能执行,所有时间使2或3个CPU保持100%繁忙。
什么,只要一堆插入物?
简易修复
问题在于它是休眠状态。 它不仅是一个愚蠢的JDBC包装器,而且还有很多事情要做。 它试图使缓存和会话状态保持最新。 如果运行裸露的SQL更新,则不知道要更新的表,它所依赖的表以及它如何影响一切,以防万一它几乎刷新了所有内容 。
如果您在如此拥挤的环境中执行此操作10,000次,则总和会增加。
这是修复它的一种方法-而不是使用刷新运行10,000个更新,而是在一个块中执行所有操作并刷新一次。
session.doWork(new Work() {public void execute(Connection connection) throws SQLException {PreparedStatement ps = connection.prepareStatement("insert into dir_contents values (?)");for (String fileName : folder.list()) {ps.setString(1, fileName);ps.executeUpdate();}}
});
其他解决方案
惊喜,惊喜:
- 一定要使用休眠模式。 创建一个代表
DirContents
的真实实体,并像其他所有东西一样使用它。 然后,Hibernate知道何时刷新哪些缓存,如何批处理更新等等。 - 不要使用休眠模式。 使用普通的旧JDBC, MyBatis或其他适合您的堆栈或已经存在的堆栈。
带走
即使此示例不是最佳用例,本机SQL也应有的地位。 无论如何,关键是:如果将本地SQL与Hibernate一起使用,请注意会话状态和缓存。
翻译自: https://www.javacodegeeks.com/2014/03/careful-with-native-sql-in-hibernate.html