Hibernate и Spring - операции загрузки делают trich, операции обновления / удаления не делают - PullRequest
0 голосов
/ 12 марта 2011

Я следовал этому уроку: http://www.scribd.com/doc/25244173/Java-Struts-Spring-Hibernate-Tutorial Настройка (описанная выше) работала нормально с файлами учебника, но когда я внес изменения - действия по удалению / обновлению просто не выполняются. Никаких ошибок или причуд, это просто полностью игнорирует меня! Что касается извлечения данных - все работает отлично ..

Почти все файлы из 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();
    }

}

и пружинное 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>

Ответы [ 2 ]

1 голос
/ 12 марта 2011

Ваш код выглядит так, как будто вы не полностью поняли концепцию внедрения зависимостей Spring, потому что ваш BaseController выполняет работу Spring по управлению синглетами и поддержке зависимостей.

Задача

Вы создаете EventController и PersonController экземпляры самостоятельно внутри BaseController вместо того, чтобы полагаться на Spring.Spring не может перехватить ручное создание экземпляров классов и предоставить им требуемое здесь транзакционное поведение, пометив классы аннотацией Spring @Transactional.

Solution

Итак, давайте найдем путь для очистки этого кода.Сначала удалите класс HibernateUtil, поскольку он представляет собой смесь статических вызовов, концепций Java-бинов и неиспользуемого поведения транзакций, в то время как он приносит новый уровень абстракции без каких-либо преимуществ.Не забудьте удалить его из applicationContext.xml также.

Теперь удалите BaseController из вашего applicationContext.xml также и дайте ему основную переписку, потому что он работает как Singleton-Factory для ваших PersonController и EventController, который будет правильно управляться самой Spring в такой среде.

public abstract class BaseController {

    private SessionFactory sessionFactory;

    public void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }

    protected Session getCurrentSession() {
        return sessionFactory.getCurrentSession();
    }

}

Таким образом BaseController становится абстрактным базовым классом для других расширяющих классов, которые могут использовать предоставленный Hibernate Sessionобъект.Теперь давайте создадим красивый интерфейс для вашего EventController.

public interface EventController {

    Event getEventById(long id);

    void deleteEventById(long id);

    Event createEvent(String name);

    List getEvents();

}

Далее нам потребуется реализация вышеуказанного интерфейса для Hibernate, поэтому давайте вызовем новый класс EventControllerHibernate, используя ранее созданный BaseController реализация.

public class EventControllerHibernate extends BaseController implements EventController {

    @Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
    public Event getEventById(long id) {
        return (Event) getCurrentSession().get(Event.class, id);
    }

    @Transactional(propagation = Propagation.REQUIRED)
    public void deleteEventById(long id) {
        getCurrentSession().delete(getEventById(id));
    }

    @Transactional(propagation = Propagation.REQUIRED)
    public Event createEvent(String name) {
         return (Event) getCurrentSession().save(new Event(name));
    }

    @Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
    @SuppressWarnings("unchecked")
    public List getEvents() {
        return getCurrentSession().createQuery("from Event").list();
    }

}

И не забудьте правильно зарегистрировать этот класс в своей Spring applicationContext.xml, чтобы обеспечить требуемый SessionFactory:

<bean id="eventController" class="com.epa.controller.EventControllerHibernate">
    <property name="sessionFactory" ref="sessionFactory" />
</bean> 

Если вы получаетеSpring bean типа EventController от Spring, вы получите прокси-объект с поддержкой транзакций, полностью реализующий ваш интерфейс EventController, делегирующий бизнес-логике, реализованной внутри EventControllerHibernate.

Помните : new EventControllerHibernate() никогда не должно появляться в вашем приложении, так как это не сработает, потому что Spring не может перехватить ручное создание экземпляра класса!Получение экземпляра с поддержкой транзакций программно будет выглядеть так:

ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
EventController eventController = context.getBean("eventController", EventController.class);
0 голосов
/ 13 марта 2011

Коды контроллера не очень элегантные. Вы должны следовать всему, что сказал Codecape здесь. Однако простым решением проблемы может быть следующее: вместо возврата нового PersonController () или нового EventController () вы можете вернуть экземпляр того же компонента, который был введен в BaseController (). Это вернет прокси-объект, для которого @Transactional может быть перехвачен пружиной. Однако, как я уже сказал, определенные контроллеры не являются хорошими кодами.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...