通过主键检索多条记录时,我会大量使用以下Hibernate查询
Criteria c = session
.createCriteria(Song.class)
.setLockMode(LockMode.NONE)
.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY)
.add(Restrictions.in("recNo", ids));
List<Song> songs = c.list();
问题是ID的数量可以在1到50之间变化,并且每个ID的不同数量都需要不同的PreparedStatement。加上任何特定的预处理语句都与特定的数据库池连接相关联的事实,意味着重用PreparedStatement的机会非常低。
有没有办法我可以重写它,以便同一条语句可以与不同数量的in值一起使用,我想我读到某处可以通过使用ANY来完成,但找不到引用。
答案 0 :(得分:1)
这称为“ in子句参数填充”,可以通过休眠属性激活:
<property
name="hibernate.query.in_clause_parameter_padding"
value="true"
</property>
在此处了解有关此主题的更多信息:https://vladmihalcea.com/improve-statement-caching-efficiency-in-clause-parameter-padding/
答案 1 :(得分:0)
在一些帮助下,我最终从Hibernate获得了一个普通的SQL连接,然后将标准SQL与ANY而不是IN一起使用。据我所知,使用ANY意味着每个连接只需要一个准备好的语句,因此比使用填充的IN更好。但是因为只使用SQL并没有太大用,如果您需要修改返回的数据
public static List<SongDiff> getReadOnlySongDiffs(List<Integer> ids)
{
Connection connection = null;
try
{
connection = HibernateUtil.getSqlSession();
String SONGDIFFSELECT = "select * from SongDiff where recNo = ANY(?)";
PreparedStatement ps = connection.prepareStatement(SONGDIFFSELECT);
ps.setObject(1, ids.toArray(new Integer[ids.size()]));
ResultSet rs = ps.executeQuery();
List<SongDiff> songDiffs = new ArrayList<>(ids.size());
while(rs.next())
{
SongDiff sd = new SongDiff();
sd.setRecNo(rs.getInt("recNo"));
sd.setDiff(rs.getBytes("diff"));
songDiffs.add(sd);
}
return songDiffs;
}
catch (Exception e)
{
MainWindow.logger.log(Level.SEVERE, "Failed to get SongDiffsFromDb:" + e.getMessage(), e);
throw new RuntimeException(e);
}
finally
{
SessionUtil.close(connection);
}
}
public static Connection getSqlSession() throws SQLException {
if (factory == null || factory.isClosed()) {
createFactory();
}
return ((C3P0ConnectionProvider)factory.getSessionFactoryOptions().getServiceRegistry().getService(C3P0ConnectionProvider.class)).getConnection();
}
答案 2 :(得分:0)
如果您仍然使用旧版本的 Hibernate,如对 Simon's answer here 的评论中所建议,作为一种解决方法,您可以使用 jOOQ's ParsingConnection
通过应用 IN
list padding feature在幕后透明。您可以像这样包装您的 DataSource
:
// Input DataSource ds1:
DSLContext ctx = DSL.using(ds1, dialect);
ctx.settings().setInListPadding(true);
// Use this DataSource for your code, instead:
DataSource ds2 = ctx.parsingDataSource();
I've written up a blog post to explain this more in detail here。
(免责声明:我为 jOOQ 背后的公司工作)