首先,我从DB获得持久性对象(实例A),然后我将值设置为字段。我再次再次调用来自DB的持久对象(实例B)。出乎意料的是,加载的对象(实例B)具有我设置为实例A的值。即使我没有调用任何save()方法。
意外行为背后的原因是什么?我该如何解决?
以下是测试失败:
@RunWith( SpringJUnit4ClassRunner.class )
@ContextConfiguration( locations = { "/webapp-beans.xml" } )
@Transactional
public class HibernatePersistentTest extends TestCase
{
@Autowired
CompanyDAO companyDAO;
@Test
public void persisting_setAValueAndOnlyCallGet_fieldValueDoesNotChange()
{
// GIVEN
// persist new Company
Company company = new Company();
company.setIsDeleted( YesNoType.NO );
company.setName( "A" );
companyDAO.getHibernateTemplate().saveOrUpdate( company );
// assert "object persisted properly"
Company companyA = (Company) companyDAO.getHibernateTemplate().get( Company.class, company.getId() );
assertEquals( "Field value changed", "A", companyA.getName() );
// WHEN set name B and call get()
company.setName( "B" );
Company companyB = (Company) companyDAO.getHibernateTemplate().get( Company.class, company.getId() );
// THEN name should be still A
assertEquals( "Field value changed", "A", companyB.getName() );
}
}
我的休眠配置:
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass"> <value>oracle.jdbc.driver.OracleDriver</value></property>
<property name="jdbcUrl"><value>${jdbc.url}</value></property>
<property name="user"><value>${jdbc.encusername}</value></property>
<property name="password"><value>${jdbc.encpassword}</value></property>
<property name="initialPoolSize"><value>10</value></property>
<property name="minPoolSize"><value>10</value></property>
<property name="maxPoolSize"><value>100</value></property>
<property name="maxStatements"><value>0</value></property>
<property name="preferredTestQuery"><value>SELECT 1 FROM DUAL</value></property>
<property name="idleConnectionTestPeriod"><value>300</value></property>
<property name="checkoutTimeout"><value>10000</value></property>
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.OracleDialect</prop>
<prop key="hibernate.use_outer_join">true</prop>
<prop key="hibernate.jdbc.batch_size">0</prop>
<prop key="hibernate.jdbc.use_streams_for_binary">true</prop>
<prop key="hibernate.connnection.charSet">UTF8</prop>
<prop key="hibernate.connection.defaultNChar">true</prop>
<prop key="hibernate.bytecode.use_reflection_optimizer">true</prop>
<prop key="hibernate.transaction.flush_before_completion">true</prop>
<prop key="hibernate.default_batch_fetch_size">16</prop>
<prop key="hibernate.cache.provider_class">org.hibernate.connection.C3P0ConnectionProvider</prop>
<prop key="hibernate.cache.use_query_cache">true</prop>
<prop key="hibernate.show_sql">false</prop>
<prop key="hibernate.format_sql">false</prop>
<prop key="hibernate.connection.driver_class">oracle.jdbc.driver.OracleDriver</prop>
<prop key="connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</prop>
<prop key="current_session_context_class">thread</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.default_schema">${schema}</prop>
</props>
</property>
<property name="packagesToScan">
<list merge="true">
<value>com/pegasus/data/entity</value>
</list>
</property>
</bean>
答案 0 :(得分:4)
这是完全预期的行为。
在给定会话中,只存在给定实体的一个实例。它存储在与会话关联的第一级缓存中。您在此会话中执行的任何返回具有相同ID的相同类型实体的查询将返回存储在缓存中的此唯一实体实例。您对此实体所做的任何更改都将自动保持持久性(除非您更改刷新模式)。
我的猜测是你的测试是事务性的,因此测试中的所有内容都在一个会话中执行,因此你看到的行为。
如果您的测试不是事务性的,并且每个DAO调用都是在新事务中进行的,那么您应该会看到您期望的行为。
答案 1 :(得分:0)
这种行为就像hibernate的行为一样:两个get()
- 使用相同id的调用应返回相同的对象 - 实例 - 因此之前的更改仍将反映在该实例中。
JPA规范要求此行为:
其主键的值唯一标识实体实例 在持久化上下文和EntityManager操作中 在第3章“实体操作”中描述。