Question

Some prehistory.. I have a web-based corporate CRM system written with Spring and Hibernate. There are a lot of tasks that should be done systematically such as reminders or email notifications.. Now it is implemented as a separate Controller wich is called from cron. Everything works fine except of the fact that some of tasks are very "heavy" and take a lot of Tomcat's resources. So I decided to split them into different java console apps. In order to use the same objects and services I splited the main project into separate projects (libraries):

  1. Objects
  2. DAO

In the main project I just added these projects to the BuildPath so I can use all the objects and services without any problem.

Now I started implement the first console utility and facing some issue.. Take a look.

public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-service.xml", "spring-hibernate.xml");

        try {
            MessageSourceEx messageSource = new MessageSourceEx((ResourceBundleMessageSource) ctx.getBean("messageSource"));
            ITasksService tasksService = (ITasksService) ctx.getBean("tasksService");
            NotificationsService notificationsService = (NotificationsService) ctx.getBean("notificationsService");

            List<Task> tasks = tasksService.systemGetList();
            for (Task t: tasks) {
                Locale userLocale = t.getCreator().getCommunicationLanguageLocale();
                EmailNotification reminder = new EmailNotification(t.getCreator().getEmail(), 
                        messageSource.getMessage(userLocale, "notifications.internal.emails.task.subject"), 
                        messageSource.getMessage(userLocale, "notifications.internal.emails.task.text", 
                                t.getCreator().getNickname(),
                                t.getName(),
                                t.getDescription(),
                                AppConfig.getInstance().getUrl(),
                                t.getId()), 
                        userLocale, t.getCreator());
                notificationsService.email.send(reminder);
                if (reminder.getState() == EmailNotificationSendState.Sent) {
                    t.setReminderSent(true);
                    tasksService.save(t);
                }
            }
        }
        catch (Exception e) {
            e.printStackTrace();
        }
        finally {
            ((ConfigurableApplicationContext)ctx).close();
        }

        System.exit(0);
    }

spring-service.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:context="http://www.springframework.org/schema/context"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">
    <context:annotation-config />
    <context:component-scan base-package="com.dao,com.service,com.notifications,com.interfaces" />
    <bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
        <property name="basename" value="com.Resources" />
    </bean>
</beans>

spring-hibernate.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:context="http://www.springframework.org/schema/context"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
    http://www.springframework.org/schema/context  http://www.springframework.org/schema/context/spring-context-3.1.xsd">
    <tx:annotation-driven />
    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="location" value="classpath:/hibernate.properties" />
    </bean>
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="${hibernate.connection.driver_class}" />
        <property name="url" value="${hibernate.connection.url}" />
        <property name="username" value="${hibernate.connection.username}" />
        <property name="password" value="${hibernate.connection.password}" />
    </bean>
    <bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="annotatedClasses">
            <list>
                <value>com.data.Task</value>
            </list>
        </property>
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">${hibernate.dialect}</prop>
                <prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
                <prop key="hibernate.format_sql">${hibernate.format_sql}</prop>
                <prop key="hibernate.cache.use_query_cache">${hibernate.cache.use_query_cache}</prop>
                <prop key="hibernate.cache.region.factory_class">${hibernate.cache.region.factory_class}</prop>
           </props>
        </property>
    </bean>
    <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>
</beans>

DAO

@Component
public class TasksDAO {

    /**
     * Retrieves a list of tasks
     * 
     * @return List of tasks
     */
    @SuppressWarnings({ "unchecked" })
    public List<Task> systemGetList() {
        Session session = SessionFactoryUtils.getSession(sessionFactory, false);
        List<Task> result = null;
        Date now = new Date();

        Criteria query = session.createCriteria(Task.class)
                .add(Restrictions.le("remindTime", DateUtilsEx.addMinutes(now, 3)))
                .add(Restrictions.eq("reminderSent", false))
                .addOrder(Order.asc("remindTime"));

        result = query.list();
        if (result == null)
            result = new ArrayList<Task>();

        return result;
    }
}

Service

@Service
public class TasksService implements ITasksService {

    /**
     * 
     */
    @Override
    public List<Task> systemGetList() {
        return tasksDAO.systemGetList();
    }
}

It fails with No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here at org.springframework.orm.hibernate3.SessionFactoryUtils.doGetSession(SessionFactoryUtils.java:356) exception.. What is interesting - if I add @Transactional to systemGetList() - works fine. But I don't want to add transactions for all select statements... And the same code (without transaction) works fine on web-site itself..

Any help? Thank you in advance.

Était-ce utile?

La solution

You have specified your service methods to be Transactional

<tx:annotation-driven />

Add @Transactional(readOnly = true) on select/read only methods

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top