当前有Person与IdCard两个一对一关联关系的类, 当我设置了二级缓存之后, 出现了异常, 请看源代码:
// Person.java
package bean;
public class Person {
private Integer id;
private String name;
private IdCard idCard;
// set, get省略
}
// IdCard.java
package bean;
import java.util.Date;
public class IdCard {
private Integer id;
private Date useFulLife;
private Person person;
// set, get省略
}
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="bean">
<class name="Person">
<cache usage="read-write" />
<id name="id">
<generator class="native"/>
</id>
<property name="name"/>
<one-to-one name="idCard" property-ref="person"/>
</class>
</hibernate-mapping>// IdCard.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="bean">
<class name="IdCard" table="id_card">
<cache usage="read-write" />
<id name="id">
<generator class="foreign">
<param name="property">person</param>
</generator>
</id>
<property name="useFulLife" column="useful_life"/>
<one-to-one name="person" constrained="true"/>
</class>
</hibernate-mapping>
//One2One.java
package hibernate;
import java.util.Date;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.stat.Statistics;
import bean.IdCard;
import bean.Person;
public class One2One {
public static void main(String[] args) throws InstantiationException, IllegalAccessException, ClassNotFoundException {
add();
testCache();
}
public static void testCache() throws InstantiationException, IllegalAccessException, ClassNotFoundException {
Session session = null;
try {
// 从HibernateUtil中获取session
session = HibernateUtil.getSession();
Person p1 = (Person) session.get(Person.class, 1);
Person p2 = (Person) session.get(Person.class, 1);
Statistics s = HibernateUtil.getSessionFactory().getStatistics();
System.out.println(s);
} finally {
if (null != session)
session.close();
}
try {
session = HibernateUtil.getSession();
Person p3 = (Person) session.get(Person.class, 1);
} finally {
if (null != session)
session.close();
}
}
public static void testQuery() {
Session session = null;
try {
session = HibernateUtil.getSession();
Person person = (Person) session.get(Person.class, 1);
// IdCard idCard = (IdCard)session.load(IdCard.class, 1);
System.out.println("person.class: " + person.getClass());
Person person1 = (Person) session.get(Person.class, 1);
System.out.println("person1.class: " + person1.getClass());
} finally {
if (null != session)
session.close();
}
}
public static void add() {
Session session = null;
Transaction tx = null;
try {
session = HibernateUtil.getSession();
IdCard idCard = new IdCard();
idCard.setUseFulLife(new Date());
Person person = new Person();
person.setName("pserson1 name");
person.setIdCard(idCard);
idCard.setPerson(person);
tx = session.beginTransaction();
session.save(person);
session.save(idCard);
tx.commit();
} finally {
if (null != session) {
session.close();
}
}
}
}
当运行此程序时, 出现以下异常信息:
Hibernate: insert into Person (name) values (?)
Hibernate: insert into id_card (useful_life, id) values (?, ?)
Hibernate: select person0_.id as id5_1_, person0_.name as name5_1_, idcard1_.id as id6_0_, idcard1_.useful_life as useful2_6_0_ from Person person0_ left outer join id_card idcard1_ on person0_.id=idcard1_.id where person0_.id=?
Hibernate: select idcard0_.id as id6_0_, idcard0_.useful_life as useful2_6_0_ from id_card idcard0_
Exception in thread "main" org.hibernate.exception.GenericJDBCException: could not load an entity: [bean.IdCard#1]
at org.hibernate.exception.SQLStateConverter.handledNonSpecificException(SQLStateConverter.java:103)
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:91)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43)
at org.hibernate.loader.Loader.loadEntity(Loader.java:1874)
at org.hibernate.loader.entity.AbstractEntityLoader.load(AbstractEntityLoader.java:48)
at org.hibernate.loader.entity.EntityLoader.loadByUniqueKey(EntityLoader.java:85)
at org.hibernate.persister.entity.AbstractEntityPersister.loadByUniqueKey(AbstractEntityPersister.java:1649)
at org.hibernate.type.EntityType.loadByUniqueKey(EntityType.java:608)
at org.hibernate.type.EntityType.resolve(EntityType.java:382)
at org.hibernate.type.OneToOneType.assemble(OneToOneType.java:141)
at org.hibernate.type.TypeFactory.assemble(TypeFactory.java:420)
at org.hibernate.cache.entry.CacheEntry.assemble(CacheEntry.java:96)
at org.hibernate.cache.entry.CacheEntry.assemble(CacheEntry.java:82)
at org.hibernate.event.def.DefaultLoadEventListener.assembleCacheEntry(DefaultLoadEventListener.java:557)
at org.hibernate.event.def.DefaultLoadEventListener.loadFromSecondLevelCache(DefaultLoadEventListener.java:512)
at org.hibernate.event.def.DefaultLoadEventListener.doLoad(DefaultLoadEventListener.java:357)
at org.hibernate.event.def.DefaultLoadEventListener.load(DefaultLoadEventListener.java:139)
at org.hibernate.event.def.DefaultLoadEventListener.proxyOrLoad(DefaultLoadEventListener.java:195)
at org.hibernate.event.def.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:103)
at org.hibernate.impl.SessionImpl.fireLoad(SessionImpl.java:878)
at org.hibernate.impl.SessionImpl.get(SessionImpl.java:815)
at org.hibernate.impl.SessionImpl.get(SessionImpl.java:808)
at hibernate.One2One.testCache(One2One.java:36)
at hibernate.One2One.main(One2One.java:15)
Caused by: java.sql.SQLException: Parameter index out of range (1 > number of parameters, which is 0).
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1055)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:956)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:926)
at com.mysql.jdbc.PreparedStatement.checkBounds(PreparedStatement.java:3288)
at com.mysql.jdbc.PreparedStatement.setInternal(PreparedStatement.java:3272)
at com.mysql.jdbc.PreparedStatement.setInternal(PreparedStatement.java:3314)
at com.mysql.jdbc.PreparedStatement.setInt(PreparedStatement.java:3258)
at org.hibernate.type.IntegerType.set(IntegerType.java:41)
at org.hibernate.type.NullableType.nullSafeSet(NullableType.java:136)
at org.hibernate.type.NullableType.nullSafeSet(NullableType.java:116)
at org.hibernate.loader.Loader.bindPositionalParameters(Loader.java:1707)
at org.hibernate.loader.Loader.bindParameterValues(Loader.java:1678)
at org.hibernate.loader.Loader.prepareQueryStatement(Loader.java:1563)
at org.hibernate.loader.Loader.doQuery(Loader.java:673)
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:236)
at org.hibernate.loader.Loader.loadEntity(Loader.java:1860)
... 20 more
以上程序我运行在"没有关联关系的类"时不会出错, 曾做过User单个类的测试, 能够正确运行!
但运行在此"一对一关联关系的用例"时却报异常了, 不知道是什么原因.
首先说明, 我的ehcache的配置是正确的, HibernateUtil的类也是没有问题的.
感谢各位的帮助, 谢谢!
基于外键 双向一对一:
<class name="Person">
<id name="id" column="personId">
<generator class="native"/>
</id>
<many-to-one name="address"
column="addressId"
unique="true"
not-null="true"/>
</class><class name="Address">
<id name="id" column="addressId">
<generator class="native"/>
</id>
<one-to-one name="person"
property-ref="address"/>
</class>改了试试
public static void testCache() {
Session session = null;
try {
session = HibernateUtil.getSession();
Person p1 = (Person) session.get(Person.class, 1);
Person p2 = (Person) session.get(Person.class, 1);
Statistics s = HibernateUtil.getSessionFactory().getStatistics();
System.out.println(s);
} finally {
if (null != session)
session.close();
}
try {
session = HibernateUtil.getSession();
Person p3 = (Person) session.get(Person.class, 1);
} finally {
if (null != session)
session.close();
}
}
按照以上的代码来讲, 我已经配置了二级缓存ehcache, 所以只会输出一条select语句, 讲解如下:
(1). p1从数据库里拿出Person之后, 便放入一级缓存和二级缓存.
(2). p2从一级缓存取出Person
(3). p3从一级缓存里找Person, 但找不到, 因为session已经关闭. 然后p3从二级缓存里取出Person.但是结果却产生了两条select语句, 第一句是在(1)里产生的, 这个正常, 因为get方法要从数据库里取数据.
问题是第(3)也产生了一条select语句, 按道理来讲不应该会产生的, 请问这是为什么呢?
本人曾经做过[没有任何关联关系的单个Person类]测试, 结果运行正常, 同样的代码情况下只产生一条select语句
但后来给Person加上IdCard作为one-to-one的关联关系时却产生了两条select语句!感谢大家的帮忙! 谢谢!
关于ehcache,如果不设置“查询缓存”,那么hibernate只会缓存使用load()方法获得的单个持久化对象,如果想缓存使用findall()、list()、Iterator()、createCriteria()、createQuery()等方法获得的数据结果集的话,就需要设置hibernate.cache.use_query_cache true才行.而你获取Persion对象使用的不是load方法,如果没有配置查询缓存是不能够缓存的,检查下你有没有配置查询缓存!