Hibernate 和 Spring - 加载操作执行此操作,更新/删除操作则不然
我一直在关注这个教程: http://www.scribd.com/doc/25244173/Java -Struts-Spring-Hibernate-教程 设置(前面描述的)在教程文件中运行良好,但是当我进行更改时 - 删除/更新操作不会发生。没有错误或怪癖,它只是完全忽略我!至于检索数据 - 一切都很完美。
几乎所有来自 tut 的文件都是相同的,但有这些差异;本教程使用服务文件:
Services.java
package services;
import org.springframework.transaction.annotation.Transactional;
import org.hibernate.SessionFactory;
import org.hibernate.Session;
import data.*;
import java.util.List;
// This class is the business services tier in the application.
// @Transactional is needed so that a Hibernate transaction is set up,
// otherwise updates won't have an affect
@Transactional
public class Services {
// So Spring can inject the session factory
SessionFactory sessionFactory;
public void setSessionFactory(SessionFactory value) {
sessionFactory = value;
}
// Shortcut for sessionFactory.getCurrentSession()
public Session sess() {
return sessionFactory.getCurrentSession();
}
public Event getEventById(long id) {
return (Event) sess().load(Event.class, id);
}
public Person getPersonById(long id) {
return (Person) sess().load(Person.class, id);
}
public void deleteEventById(long id) {
sess().delete(getEventById(id));
}
public void deletePersonById(long id) {
sess().delete(getPersonById(id));
}
public void createEvent(String name) {
Event theEvent = new Event();
theEvent.setName(name);
sess().save(theEvent);
}
public void createPerson(String name) {
Person p = new Person();
p.setName(name);
sess().save(p);
}
@SuppressWarnings("unchecked")
public List getEvents() {
return sess().createQuery("from Event").list();
}
@SuppressWarnings("unchecked")
public List getPeople() {
return sess().createQuery("from Person").list();
}
public void removePersonFromEvent(int personId, int eventId) {
getEventById(eventId).getPeople().remove(getPersonById(personId));
}
public void addPersonToEvent(int personId, int eventId) {
getEventById(eventId).getPeople().add(getPersonById(personId));
}
}
,我尝试使用父控制器和对 HibernateUtil 的静态调用来分离文件: HibernateUtil.java
package com.epa.util;
import org.hibernate.SessionFactory;
import org.springframework.transaction.annotation.Transactional;
@Transactional
public class HibernateUtil {
// So Spring can inject the session factory
static SessionFactory sessionFactory;
public void setSessionFactory(SessionFactory value) {
sessionFactory = value;
}
// Shortcut for sessionFactory.getCurrentSession()
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
}
BaseController.java
package com.epa.controller.base;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.transaction.annotation.Transactional;
import com.epa.controller.EventController;
import com.epa.controller.PersonController;
import com.epa.util.HibernateUtil;
@Transactional
public class BaseController {
protected SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
// Shortcut for sessionFactory.getCurrentSession()
public Session sess() {
return sessionFactory.getCurrentSession();
}
private PersonController personController = null;
private EventController eventController = null;
public PersonController getPersonController() {
if (this.personController == null) {
this.personController = new PersonController();
}
return personController;
}
public EventController getEventController() {
if (this.eventController == null) {
this.eventController = new EventController();
}
return eventController;
}
}
EventController.java
package com.epa.controller;
import java.util.List;
import org.springframework.transaction.annotation.Transactional;
import com.epa.controller.base.BaseController;
import com.epa.model.Event;
@Transactional
public class EventController extends BaseController {
public Event getEventById(long id) {
return (Event) sess().load(Event.class, id);
}
public void deleteEventById(long id) {
sess().delete(getEventById(id));
}
public void createEvent(String name) {
Event theEvent = new Event();
theEvent.setName(name);
sess().save(theEvent);
}
@SuppressWarnings("unchecked")
public List getEvents() {
return sess().createQuery("from Event").list();
}
}
和 spring 的 applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<!-- The singleton hibernate session factory -->
<bean id="sessionFactory" scope="singleton"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="configLocation" value="classpath:hibernate.cfg.xml" />
</bean>
<!-- Spring's hibernate transaction manager, in charge of making hibernate sessions/txns -->
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<!-- So classes/functions with @Transactional get a hibernate txn -->
<tx:annotation-driven />
<!-- Inject my business services class to the actions
<bean id="services" class="com.epa.services.Services" scope="singleton">
<property name="sessionFactory" ref="sessionFactory" />
</bean>-->
<!-- Inject my business services class to the actions -->
<bean id="hibernateUtil" class="com.epa.util.HibernateUtil" scope="singleton">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<bean id="baseController" class="com.epa.controller.base.BaseController" scope="singleton" />
</beans>
I've been following this tutorial:
http://www.scribd.com/doc/25244173/Java-Struts-Spring-Hibernate-Tutorial
The setup (described ahead) was working fine with the tutorial files, but when I have made the changes - delete / update actions just don't happen. No errors or quirks, it just completely ignores me! As for retrieving data - everything works perfectly..
Almost all the files from the tut are the same, with these differences; The tutorial uses a services file:
Services.java
package services;
import org.springframework.transaction.annotation.Transactional;
import org.hibernate.SessionFactory;
import org.hibernate.Session;
import data.*;
import java.util.List;
// This class is the business services tier in the application.
// @Transactional is needed so that a Hibernate transaction is set up,
// otherwise updates won't have an affect
@Transactional
public class Services {
// So Spring can inject the session factory
SessionFactory sessionFactory;
public void setSessionFactory(SessionFactory value) {
sessionFactory = value;
}
// Shortcut for sessionFactory.getCurrentSession()
public Session sess() {
return sessionFactory.getCurrentSession();
}
public Event getEventById(long id) {
return (Event) sess().load(Event.class, id);
}
public Person getPersonById(long id) {
return (Person) sess().load(Person.class, id);
}
public void deleteEventById(long id) {
sess().delete(getEventById(id));
}
public void deletePersonById(long id) {
sess().delete(getPersonById(id));
}
public void createEvent(String name) {
Event theEvent = new Event();
theEvent.setName(name);
sess().save(theEvent);
}
public void createPerson(String name) {
Person p = new Person();
p.setName(name);
sess().save(p);
}
@SuppressWarnings("unchecked")
public List getEvents() {
return sess().createQuery("from Event").list();
}
@SuppressWarnings("unchecked")
public List getPeople() {
return sess().createQuery("from Person").list();
}
public void removePersonFromEvent(int personId, int eventId) {
getEventById(eventId).getPeople().remove(getPersonById(personId));
}
public void addPersonToEvent(int personId, int eventId) {
getEventById(eventId).getPeople().add(getPersonById(personId));
}
}
and I have tried to separate the files by using a parent controller and static calls to HibernateUtil:
HibernateUtil.java
package com.epa.util;
import org.hibernate.SessionFactory;
import org.springframework.transaction.annotation.Transactional;
@Transactional
public class HibernateUtil {
// So Spring can inject the session factory
static SessionFactory sessionFactory;
public void setSessionFactory(SessionFactory value) {
sessionFactory = value;
}
// Shortcut for sessionFactory.getCurrentSession()
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
}
BaseController.java
package com.epa.controller.base;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.transaction.annotation.Transactional;
import com.epa.controller.EventController;
import com.epa.controller.PersonController;
import com.epa.util.HibernateUtil;
@Transactional
public class BaseController {
protected SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
// Shortcut for sessionFactory.getCurrentSession()
public Session sess() {
return sessionFactory.getCurrentSession();
}
private PersonController personController = null;
private EventController eventController = null;
public PersonController getPersonController() {
if (this.personController == null) {
this.personController = new PersonController();
}
return personController;
}
public EventController getEventController() {
if (this.eventController == null) {
this.eventController = new EventController();
}
return eventController;
}
}
EventController.java
package com.epa.controller;
import java.util.List;
import org.springframework.transaction.annotation.Transactional;
import com.epa.controller.base.BaseController;
import com.epa.model.Event;
@Transactional
public class EventController extends BaseController {
public Event getEventById(long id) {
return (Event) sess().load(Event.class, id);
}
public void deleteEventById(long id) {
sess().delete(getEventById(id));
}
public void createEvent(String name) {
Event theEvent = new Event();
theEvent.setName(name);
sess().save(theEvent);
}
@SuppressWarnings("unchecked")
public List getEvents() {
return sess().createQuery("from Event").list();
}
}
and spring's applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<!-- The singleton hibernate session factory -->
<bean id="sessionFactory" scope="singleton"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="configLocation" value="classpath:hibernate.cfg.xml" />
</bean>
<!-- Spring's hibernate transaction manager, in charge of making hibernate sessions/txns -->
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<!-- So classes/functions with @Transactional get a hibernate txn -->
<tx:annotation-driven />
<!-- Inject my business services class to the actions
<bean id="services" class="com.epa.services.Services" scope="singleton">
<property name="sessionFactory" ref="sessionFactory" />
</bean>-->
<!-- Inject my business services class to the actions -->
<bean id="hibernateUtil" class="com.epa.util.HibernateUtil" scope="singleton">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<bean id="baseController" class="com.epa.controller.base.BaseController" scope="singleton" />
</beans>
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您的代码看起来好像您没有完全理解 Spring 依赖注入的概念,因为您的
BaseController
负责 Spring 管理单例和提供依赖项的工作。问题
您正在
BaseController
中自己创建EventController
和PersonController
实例,而不是依赖 Spring。 Spring 无法拦截类实例的手动创建,也无法通过使用 Spring 注释@Transactional
注释类来为它们提供此处所需的事务行为。解决方案
那么,让我们找到一条清理这段代码的路径。首先删除类
HibernateUtil
,因为它是静态调用、java bean 概念和未使用的事务行为的混合体,同时它带来了一个新的抽象层,但没有任何好处。请记住也将其从applicationContext.xml
中删除。现在,从您的
applicationContext.xml
中删除BaseController
并对其进行重大重写,因为它作为您的PersonController
和PersonController
的单例工厂工作。 code>EventController 在这样的环境中,Spring 本身可以正确管理它。这样,
BaseController
就成为其他扩展类的抽象基类,可以利用提供的 HibernateSession
对象。现在让我们为您的EventController
创建一个漂亮的界面。接下来,我们需要 Hibernate 的上述接口的实现,因此让我们利用之前创建的
BaseController
实现来调用新类EventControllerHibernate
。请记住在 Spring
applicationContext.xml
中正确注册此类,以便也提供所需的SessionFactory
:如果您检索
EventController< 类型的 Spring bean /code> 从 Spring 中,您将获得一个事务感知代理对象,该对象完全实现您的
EventController
接口,委托给EventControllerHibernate
内实现的业务逻辑。记住:
new EventControllerHibernate()
永远不应该出现在您的应用程序中,因为这不会起到作用,因为 Spring 无法拦截类实例的手动创建!以编程方式获取事务感知实例如下所示:Your code looks as if you did not fully understand the concept of Spring dependency injection because your
BaseController
does Spring's job of managing singletons and suppling dependencies.Problem
You are creating
EventController
andPersonController
instances by yourself inside theBaseController
instead of relying on Spring. Spring cannot intercept the manual creation of class instances and providing them with the transactional behavior which you require here by annotating the classes with the Spring annotation@Transactional
.Solution
So, lets find a path to clean this code up. First remove the class
HibernateUtil
because it is a mixture of static calls, java bean concepts and unused transactional behavior while it brings a new abstraction layer without any benefits. Remember to remove it from theapplicationContext.xml
also.Now remove the
BaseController
from yourapplicationContext.xml
also and give it a major rewrite because it works as a Singleton-Factory for yourPersonController
andEventController
which would correctly managed by Spring itself in a environment like this.This way
BaseController
becomes an abstract base class for other extending classes, which can make use of the provided HibernateSession
object. Now lets create a nice interface for yourEventController
.Next we need the implementation of the above interface for Hibernate so let us call the new class
EventControllerHibernate
making use of the earlier createdBaseController
implementation.And remember to register this class in your Spring
applicationContext.xml
correctly so that the requiredSessionFactory
is provided, too:If you retrieve a Spring bean of type
EventController
from Spring you will get a transaction-aware proxy object fully implementing yourEventController
interface delegating to the business logic implemented insideEventControllerHibernate
.Remember: A
new EventControllerHibernate()
should never occur in your application since this will not do the trick because Spring can not intercept the manual creation of a class instance! Getting a transaction-aware instance programmatically would look like this:控制器代码不是很优雅。你应该遵循 codescape 在这里所说的一切。然而,问题的简单修复如下:您可以返回已注入 BaseController() 的相同 bean 实例,而不是返回 new PersonController() 或 new EventController()。这将返回一个代理对象,spring可以在该代理对象上拦截@Transactional。然而,正如我所说, 定义的控制器不是好的代码。
The controller codes are not very elegant. You should be following everything codescape has said here. However a simple fix to problem would be the following: Instead of returning a new PersonController() or new EventController(), you can return a bean instance of the same which have been injected into the BaseController(). This will return a proxy object on which the @Transactional can be intercepted by spring. However, as I said the controllers defined by are not good codes.