Spring + Hibernate控制台应用程序

3

一些前置信息...

我有一个基于Spring和Hibernate编写的Web企业CRM系统。有很多任务需要系统化完成,比如提醒或电子邮件通知...现在它被实现为一个独立的控制器,从cron中调用。除了某些任务非常“沉重”并占用了大量Tomcat资源之外,一切都运行良好。因此,我决定将它们拆分成不同的Java控制台应用程序。为了使用相同的对象和服务,我将主项目分成了以下几个库:

  1. 对象
  2. DAO

在主项目中,我只需将这些项目添加到BuildPath中,就可以毫无问题地使用所有对象和服务。

现在,我开始实现第一个控制台工具,并遇到了一些问题...请看下面。

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
public class TasksService implements ITasksService {

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

它会出现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)异常。有趣的是,如果我在systemGetList()中添加@Transactional,它就可以正常工作。但我不想为所有选择语句添加事务...而且同样的代码(没有事务)在网站本身上运行良好。
需要帮助吗?谢谢。
1个回答

1
您已将服务方法指定为事务性。
<tx:annotation-driven />

在只读的方法上添加@Transactional(readOnly = true)

是的,我明白。但为什么它在Web项目(我之前编写的CRM)中运行良好,在这里却失败了呢?对象和服务都是相同的。 - nKognito
配置文件是一样的吗?那肯定有些不同。可能在Spring上下文中没有创建CRM上的事务管理器,或者使用<tx:advice>应用了事务语义... - isah
嗯..你说得对,我没有在Spring上下文中指定这个注释,而是在Hibernate中...但是事务仍然正常工作,我刚刚再次检查了一下..如果一个方法失败,第二个方法会回滚..所以我想我会使用“advice”功能。 - nKognito
最终我决定使用另一个包含@Transactional的库来重写DAO服务。 - nKognito

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接