我在我的应用中发现了一个奇怪的错误。我简化了它,这就是它的再现方式:
(我使用DbUnit创建表和HSQLDB作为数据库,但这实际上并不重要)
package test;
import java.io.IOException;
import java.io.Serializable;
import java.io.StringReader;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Set;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.Table;
import org.dbunit.DatabaseUnitException;
import org.dbunit.database.DatabaseConnection;
import org.dbunit.database.IDatabaseConnection;
import org.dbunit.dataset.IDataSet;
import org.dbunit.dataset.xml.FlatXmlDataSetBuilder;
import org.dbunit.operation.DatabaseOperation;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.springframework.orm.hibernate3.HibernateTemplate;
public class DatabaseBugReproduction {
@Entity(name = "A")
@Table(name = "a")
public static class A {
private int id;
private Set <B> bs;
@Id
public int getId() {
return id;
}
@ManyToMany
@JoinTable(
name = "ab",
joinColumns = @JoinColumn(name = "a_id"),
inverseJoinColumns = @JoinColumn(name = "b_id")
)
public Set <B> getBs() {
return bs;
}
void setId(int id) {
this.id = id;
}
void setBs(Set <B> engines) {
this.bs = engines;
}
}
@Entity(name = "B")
@Table(name = "b")
public static class B {
private int id;
@Id
public int getId() {
return id;
}
void setId(int id) {
this.id = id;
}
}
private static SessionFactory getSessionFactory() throws SQLException, IOException, DatabaseUnitException {
String driverClass = "org.hsqldb.jdbc.JDBCDriver";
String jdbcUrl = "jdbc:hsqldb:mem:seoservertooltest";
String dbUsername = "test";
String dbPassword = "test";
String dbDialect = "org.hibernate.dialect.HSQLDialect";
Configuration config = new Configuration()//
.setProperty("hibernate.connection.driver_class", driverClass)//
.setProperty("hibernate.connection.url", jdbcUrl)//
.setProperty("hibernate.connection.username", dbUsername)//
.setProperty("hibernate.connection.password", dbPassword)//
.setProperty("hibernate.dialect", dbDialect)//
.setProperty("hibernate.hbm2ddl.auto", "create-drop")//
.setProperty("hibernate.current_session_context_class", "thread")//
.setProperty("hibernate.cache.use_query_cache", "true")//
.setProperty("hibernate.cache.use_second_level_cache", "true")//
.setProperty("hibernate.cache.region.factory_class", "net.sf.ehcache.hibernate.EhCacheRegionFactory")//
.setProperty("hibernate.cache.region_prefix", "")//
// .setProperty("hibernate.show_sql", "true")//
// .setProperty("hibernate.format_sql", "true")//
.addAnnotatedClass(A.class) //
.addAnnotatedClass(B.class) //
;
SessionFactory result = config.buildSessionFactory();
try (Connection con = DriverManager.getConnection(jdbcUrl, dbUsername, dbPassword)) {
con.createStatement().executeUpdate("SET DATABASE REFERENTIAL INTEGRITY FALSE;");
String xml = "<?xml version='1.0' encoding='UTF-8'?>"//
+ "<dataset>"//
+ "<a id='1'/>"//
+ "<b id='1'/>"//
+ "<ab a_id='1' b_id='1' />"//
+ "</dataset>";
final IDatabaseConnection dbCon = new DatabaseConnection(con);
try {
final FlatXmlDataSetBuilder builder = new FlatXmlDataSetBuilder();
final IDataSet dataSet = builder.build(new StringReader(xml));
DatabaseOperation.CLEAN_INSERT.execute(dbCon, dataSet);
} finally {
dbCon.close();
}
}
return result;
}
public static void main(String[] args) throws Exception {
HibernateTemplate hibTemplate = new HibernateTemplate(getSessionFactory());
hibTemplate.setCacheQueries(true);
System.out.println(hibTemplate.find("select a.bs from A a"));
System.out.println(hibTemplate.find("select a.bs from A a"));
}
}
输出是:
[test.DatabaseBugReproduction$B@2942ce]
[null]
看起来缓存在某种程度上是错误配置的。错误在哪里,我该如何解决?
用于:
答案 0 :(得分:2)
经过一些调试后,我发现查询缓存和集合查询似乎存在问题。将存储在缓存中的集合进行分解的方法始终返回null
。
事实上,在谷歌搜索之后,事实证明这个问题是由于Hibernate中的bug引起的。有关详细信息,请参阅问题说明。
虽然这个问题没有解决(似乎不会),但您可以重新编写查询,这样就不需要收集查询了:
public static void main(String[] args) throws Exception {
HibernateTemplate hibTemplate = new HibernateTemplate(getSessionFactory());
hibTemplate.setCacheQueries(true);
//System.out.println(hibTemplate.find("select a.bs from A a"));
//System.out.println(hibTemplate.find("select a.bs from A a"));
System.out.println(hibTemplate.find("select bs from A a inner join a.bs as bs"));
System.out.println(hibTemplate.find("select bs from A a inner join a.bs as bs"));
}
我已经测试过它并且工作正常。