我的DAO实现存在一些问题。我的场景:我在我的数据库中插入一个实体,从数据库中获取此实体两次。我理解AssertSame和AssertEquals之间的区别。我猜两个案例都应该传递相同的实体。在我的情况下,AssertEquals传递,但AssertSame失败。
我长期以来一直在努力,任何帮助都将不胜感激。
我的问题是:为了确保这两个实体是相同的,必须满足哪些条件?我应该在代码中更改什么?
我只粘贴了部分类和配置文件,我认为这些文件是必不可少的。
StudentEntity类使用@Entity进行注释。
我准备了以下jUnit测试:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "/dao-context.xml", "/hibernate-context.xml", "/core-context.xml" })
public class BidirectionalTest {
@Autowired
private UserService userService;
@Test
public void testBidirectionalRelation() {
try {
StudentEntity s = new StudentEntity();
s.setLogin("Login");
userService.registerUser(s);
StudentEntity foundStudent1 = (StudentEntity) userService.findUserByLogin("Login");
StudentEntity foundStudent2 = (StudentEntity) userService.findUserByLogin("Login");
assertEquals(foundStudent1, foundStudent2);
assertSame(foundStudent1, foundStudent2); // fail!
} catch (ServiceException e) {
e.printStackTrace();
}
}
}
我的服务实施的一部分:
@Transactional(propagation=Propagation.REQUIRED)
public class UserServiceImpl implements UserService{
private UserDao userDao;
public AbstractUserEntity findUserByLogin(String login) throws ServiceException {
Long userId = getUserDao().findUserByLogin(login);
if(userId == null) {
return null;
}
return getUserDao().findUser(userId);
}
public Long registerUser(AbstractUserEntity user) throws ServiceException {
Long duplicateUserId = getUserDao().findUserByLogin(user.getLogin());
if (duplicateUserId!=null) {
throw new ServiceException("Użytkownik już istnieje");
}
return getUserDao().insertUser(user);
}
}
我的dao实现的一部分:
@Repository
public class HibernateUserDao implements UserDao {
private EntityManagerFactory emf;
public EntityManagerFactory getEmf() {
return emf;
}
@PersistenceUnit
public void setEmf(EntityManagerFactory emf) {
this.emf = emf;
}
@Override
public Long insertUser(AbstractUserEntity user) {
EntityManager em = emf.createEntityManager();
try {
em.getTransaction().begin();
em.persist(user);
em.getTransaction().commit();
} finally {
if (em != null) em.close();
}
return user.getId();
}
@Override
public Long findUserByLogin(String login) {
EntityManager em = emf.createEntityManager();
Long result;
try{
result = (Long) em.createNamedQuery("findUserByLogin").setParameter("login", login).getSingleResult();
} catch(NoResultException nre) {
return null;
}
return result;
}
}
我的persistence.xml的一部分
<persistence-unit name="JpaPersistenceUnit" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<properties>
<property name="hibernate.ejb.naming_strategy" value="org.hibernate.cfg.DefaultNamingStrategy" />
<property name="hibernate.dialect" value="org.hibernate.dialect.DerbyDialect" />
<property name="hibernate.hbm2ddl.auto" value="create-drop" />
<property name="show_sql" value="true" />
</properties>
</persistence-unit>
我的core-context.xml的一部分
<!-- enable the configuration of transactional behavior based on annotations -->
<tx:annotation-driven transaction-manager="transactionManager" />
<!-- a PlatformTransactionManager is still required -->
<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="transactionManager">
<ref local="atomikosTM" />
</property>
<property name="userTransaction">
<ref local="atomikosUTX" />
</property>
</bean>
<bean id="atomikosTM" class="com.atomikos.icatch.jta.UserTransactionManager" />
<bean id="atomikosUTX" class="com.atomikos.icatch.jta.UserTransactionImp" />
编辑:
谢谢你的回答。现在我知道我需要一个缓存。我找到了一个很好的解释:“在JPA中,不会在EntityManagers中维护对象标识。每个EntityManager都维护自己的持久化上下文,以及它自己的对象事务状态。”我更改了我的persistence.xml,但我的测试仍然失败。
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
version="2.0">
<persistence-unit name="JpaPersistenceUnit" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<class>amg.training.spring.model.StudentEntity</class>
<class>amg.training.spring.model.SubjectEntity</class>
<class>amg.training.spring.model.TeacherEntity</class>
<class>amg.training.spring.model.AbstractUserEntity</class>
<class>amg.training.spring.model.TeacherDegree</class>
<class>amg.training.spring.dao.AbstractEntity</class>
<shared-cache-mode>ALL</shared-cache-mode>
<properties>
<property name="hibernate.ejb.naming_strategy" value="org.hibernate.cfg.DefaultNamingStrategy" />
<property name="hibernate.dialect" value="org.hibernate.dialect.DerbyDialect" />
<property name="hibernate.hbm2ddl.auto" value="create-drop" />
<property name="show_sql" value="true" />
<property name="hibernate.cache.provider_class" value="org.hibernate.cache.EhCacheProvider"/>
<property name="hibernate.cache.use_second_level_cache" value="true"/>
<property name="hibernate.cache.use_query_cache" value="true"/>
</properties>
</persistence-unit>
答案 0 :(得分:1)
要检索相同的对象,您必须使用hibernate查询缓存。任何进入数据库的查询都将创建不同的对象。
请参阅以下有关启用查询缓存的信息:http://docs.jboss.org/hibernate/orm/3.3/reference/en/html/performance.html#performance-querycache
答案 1 :(得分:0)
assertSame
之所以根据文档比较对象而不是它们的值,是因为:
assertSame(java.lang.Object expected,java.lang.Object actual) - 断言两个对象引用同一个对象。
每次检索学生都会创建一个新的StudentEntity
对象,尽管它们引用相同的数据库条目。尝试缓存结果。
答案 2 :(得分:0)
最后设法让它发挥作用。我认为缺少缓存不是问题。有必要将资源(在我们的示例中为EntityManagerFactory)绑定到同一个线程。 link to doc of .bindResource() method
@PersistenceUnit
private EntityManagerFactory emf;
private EntityManager em;
@Before
public void setUp() {
em = emf.createEntityManager();
TransactionSynchronizationManager.bindResource(emf, new EntityManagerHolder(em));
}
@After
public void tearDown() {
TransactionSynchronizationManager.unbindResource(emf);
EntityManagerFactoryUtils.closeEntityManager(em);
}