为什么 getHibernateTemplate().delete(entity) 失败?

发布于 2024-11-16 06:09:16 字数 4208 浏览 1 评论 0原文

下面是代码:

// Hibernate 模型

@Entity
@Table(name="contact")
public class Contact {
@Id
@GeneratedValue(strategy= GenerationType.AUTO)
@Column(name = "contact_id")
private Long id;

@Column(name="contact_ref_id")
private String contactRefId;

@Column(name="first_name")
private String firstName;

@Column(name="last_name")
private String lastName;

@ManyToOne
@JoinColumn(name="app_user_id")
/** user whose contact list owns this contact */
private AppUser appUser;

public Long getId() {
    return id;
}

public void setId(Long id) {
    this.id = id;
}

public String getFirstName() {
    return firstName;
}

public void setFirstName(String firstName) {
    this.firstName = firstName;
}

public String getLastName() {
    return lastName;
}

public void setLastName(String lastName) {
    this.lastName = lastName;
}


/**
 * @return AppUser who owns contact list this contact belongs to
 */
public AppUser getAppUser() {
    return appUser;
}

public void setAppUser(AppUser appUser) {
    this.appUser=appUser;
}

public String getContactRefId() {
    return contactRefId;
}

public void setContactRefId(String contactRefId) {
    this.contactRefId=contactRefId;
}

}

// DAO 层

private Criteria createCriteria() {
    return getHibernateTemplate().getSessionFactory().getCurrentSession().createCriteria(Contact.class);
}

public void deleteContact(String contactRefId) {
    Criteria criteria = createCriteria();
    criteria.add(Restrictions.eq("contactRefId", contactRefId));
    Contact contact = (Contact)criteria.uniqueResult();
    try {
        contact = getHibernateTemplate().merge(contact);
        getHibernateTemplate().delete(contact);
    } catch (DataAccessException e) {
        log.error(e.getMessage());
        throw e;
    }
}

// 服务层

public void deleteContact(String contactRefId) {
    contactDao.delete(contactRefId);
}

// 单元测试

@Test
public void testDeleteContact() {
    contactService.deleteContact("fe43b43a-d77f-45ce-b024-bb6e93264a69");
}

// Spring 配置

<beans>
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
    <property name="dataSource" ref="dataSource"/>
    <property name="packagesToScan" value="model.hibernate"/>
    <property name="hibernateProperties">
        <value>
            hibernate.dialect=org.hibernate.dialect.MySQLInnoDBDialect
            hibernate.query.substitutions=true 'Y', false 'N'
            hibernate.cache.use_second_level_cache=true
            hibernate.cache.provider_class=org.hibernate.cache.EhCacheProvider
        </value>
    </property>
</bean>

<!-- Transaction manager for a single Hibernate SessionFactory (alternative to JTA) -->
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory" />
</bean>

<bean id="contactsDao" class="ContactDaoHibernate">
    <property name="sessionFactory" ref="sessionFactory" />
</bean>

<aop:config>
  <aop:advisor advice-ref="txAdvice" pointcut="execution(* service..*.*(..))" order="0"/>
</aop:config>

<!-- Enable @Transactional support -->
<tx:annotation-driven/>

<!-- Enable @AspectJ support -->
  <aop:aspectj-autoproxy proxy-target-class="true" />

  <tx:advice id="txAdvice" transaction-manager="transactionManager">
    <tx:attributes>
       <tx:method name="*"/>
    </tx:attributes>
  </tx:advice>
</beans>

当我触发测试方法时,不会引发异常,但数据库中的行不会被删除。通过 criteria.uniqueResult() 从数据库获取联系人对象后,在调试器中检查该对象会发现已获取完整且正确的对象。尽管合并调用可能看起来是不必要的,但我这样做是为了看看是否存在用于删除的错误会话的问题。

因此,尽管 Spring 配置很简单并且我没有看到任何潜在问题,但事务中并未调用删除。最令人困惑的是这个 DAO 代码是否有效:

public void addContact(Contact contact) {
    try {
        getHibernateTemplate().save(contact);
    } catch (DataAccessException e) {
        log.error(e.getMessage());
        throw e;
    }
}

我没有主意了。

Here is the code:

// Hibernate model

@Entity
@Table(name="contact")
public class Contact {
@Id
@GeneratedValue(strategy= GenerationType.AUTO)
@Column(name = "contact_id")
private Long id;

@Column(name="contact_ref_id")
private String contactRefId;

@Column(name="first_name")
private String firstName;

@Column(name="last_name")
private String lastName;

@ManyToOne
@JoinColumn(name="app_user_id")
/** user whose contact list owns this contact */
private AppUser appUser;

public Long getId() {
    return id;
}

public void setId(Long id) {
    this.id = id;
}

public String getFirstName() {
    return firstName;
}

public void setFirstName(String firstName) {
    this.firstName = firstName;
}

public String getLastName() {
    return lastName;
}

public void setLastName(String lastName) {
    this.lastName = lastName;
}


/**
 * @return AppUser who owns contact list this contact belongs to
 */
public AppUser getAppUser() {
    return appUser;
}

public void setAppUser(AppUser appUser) {
    this.appUser=appUser;
}

public String getContactRefId() {
    return contactRefId;
}

public void setContactRefId(String contactRefId) {
    this.contactRefId=contactRefId;
}

}

// DAO layer

private Criteria createCriteria() {
    return getHibernateTemplate().getSessionFactory().getCurrentSession().createCriteria(Contact.class);
}

public void deleteContact(String contactRefId) {
    Criteria criteria = createCriteria();
    criteria.add(Restrictions.eq("contactRefId", contactRefId));
    Contact contact = (Contact)criteria.uniqueResult();
    try {
        contact = getHibernateTemplate().merge(contact);
        getHibernateTemplate().delete(contact);
    } catch (DataAccessException e) {
        log.error(e.getMessage());
        throw e;
    }
}

// Service layer

public void deleteContact(String contactRefId) {
    contactDao.delete(contactRefId);
}

// Unit test

@Test
public void testDeleteContact() {
    contactService.deleteContact("fe43b43a-d77f-45ce-b024-bb6e93264a69");
}

// Spring config

<beans>
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
    <property name="dataSource" ref="dataSource"/>
    <property name="packagesToScan" value="model.hibernate"/>
    <property name="hibernateProperties">
        <value>
            hibernate.dialect=org.hibernate.dialect.MySQLInnoDBDialect
            hibernate.query.substitutions=true 'Y', false 'N'
            hibernate.cache.use_second_level_cache=true
            hibernate.cache.provider_class=org.hibernate.cache.EhCacheProvider
        </value>
    </property>
</bean>

<!-- Transaction manager for a single Hibernate SessionFactory (alternative to JTA) -->
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory" />
</bean>

<bean id="contactsDao" class="ContactDaoHibernate">
    <property name="sessionFactory" ref="sessionFactory" />
</bean>

<aop:config>
  <aop:advisor advice-ref="txAdvice" pointcut="execution(* service..*.*(..))" order="0"/>
</aop:config>

<!-- Enable @Transactional support -->
<tx:annotation-driven/>

<!-- Enable @AspectJ support -->
  <aop:aspectj-autoproxy proxy-target-class="true" />

  <tx:advice id="txAdvice" transaction-manager="transactionManager">
    <tx:attributes>
       <tx:method name="*"/>
    </tx:attributes>
  </tx:advice>
</beans>

When I fire the test method, no exceptions are thrown, but the row in the db is not deleted. Examination of the Contact object in the debugger after it's fetched from the db by criteria.uniqueResult() reveals the complete and correct object was fetched. Although the merge call may appear unneccesary, I did that to see if there was an issue w/ the wrong Session being used for the delete.

It appears therefore that the the delete is not being called in a transaction, although the Spring config is simple and I don't see any potential issues. What is most perplexing is that this DAO code works:

public void addContact(Contact contact) {
    try {
        getHibernateTemplate().save(contact);
    } catch (DataAccessException e) {
        log.error(e.getMessage());
        throw e;
    }
}

I'm out of ideas.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

聽兲甴掵 2024-11-23 06:09:16

强烈建议为您的对象实现 equals()hashCode(),因为您似乎对每个操作使用单独的会话。

请参阅 http:// docs.jboss.org/hibernate/core/3.3/reference/en/html/persistent-classes.html#persistent-classes-equalshashcode


更新

看来您的基于 Spring 的单元测试不提交事务。默认情况下,Spring 测试框架将回滚它启动的事务。

It's highly recommended to implement equals() and hashCode() for your object since you seem to use separate sessions for each operation.

See http://docs.jboss.org/hibernate/core/3.3/reference/en/html/persistent-classes.html#persistent-classes-equalshashcode


Update

It appears that your Spring based unit test does not commit transaction. By default Spring test framework will rollback transaction that it started.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文