Quartz - 在使用spring进行hibernate事务时,会发生异常

时间:2013-11-29 12:16:36

标签: java facebook spring hibernate quartz-scheduler

我正在编写一个facebook应用程序。用户授权我的应用@ fb后,其着陆页将成为查看个人资料页面。虽然我提取了大量的数据,比如,喜欢,组等等。它需要很多时间才能将他重定向到登陆页面。所以我想的是,只需获取用户的电子邮件ID,教育和就业详细信息,然后将其重定向到登录页面。平均差距我在重定向之前启动了一个线程,这将从后台的帐户中提取所有数据。所以我创建了一个实现runnable的类,然后我从控制器启动了该线程。它工作正常,直到我从fb获取数据。在调用DAO的save(obj)方法时,我收到以下错误。

org.hibernate.HibernateException: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here

我的一位朋友建议我选择石英调度程序。所以这就是我的尝试。

FBController:

                SchedulerFactory sf = new StdSchedulerFactory();
                Scheduler shed = null;
                try {
                    shed = sf.getScheduler();
                    shed.start();
                } catch (SchedulerException e) {
                    e.printStackTrace();
                }
                JobDetail jobDetail = new JobDetail("FB_Details", null, FacebookControllerHelper.class);

                jobDetail.getJobDataMap().put("Users", user);
                jobDetail.getJobDataMap().put("accessToken", accessToken);
                jobDetail.getJobDataMap().put("fbService", facebookService);
                jobDetail.getJobDataMap().put("OAuth", service);


                Trigger trigger = TriggerUtils.makeImmediateTrigger(0, 1);
                trigger.setName("FB_Details");
                try {
                    shed.scheduleJob(jobDetail, trigger);
                } catch (SchedulerException e) {
                    System.out.println("Ended In Exception");
                    e.printStackTrace();
                }

FBControllerHelper:

public class FacebookControllerHelper implements Job{

    private Users users;
    private Token accessToken;
    private FacebookService facebookService;
    private OAuthService service;
    Gson gson = new Gson();
    private static final String PROTECTED_RESOURCE_URL_LIKE = "https://graph.facebook.com/me?fields=likes.limit(1000).fields(id,name,description,website)";

    public FacebookControllerHelper(){
    }

    public void execute(JobExecutionContext context)
              throws JobExecutionException{

        JobDataMap dataMap = context.getJobDetail().getJobDataMap();

        users = (Users) dataMap.get("Users"); 
        accessToken = (Token) dataMap.get("accessToken");
        facebookService = (FacebookService) dataMap.get("fbService");
        service = (OAuthService) dataMap.get("OAuth");

        this.getUserLikes(accessToken, users);
    } 

    @Transactional
    public void getUserLikes(Token accessToken, Users user){
        System.out.println("Entering getUserLikes Method");

        OAuthRequest request = new OAuthRequest(Verb.GET, PROTECTED_RESOURCE_URL_LIKE);
        service.signRequest(accessToken, request);
        Response response = request.send();

        FBUserLikes fbuserLikes = gson.fromJson(response.getBody(), FBUserLikes.class);
        System.out.println(response.getBody());
        facebookService.saveUserLikes(user, fbuserLikes);
    }
}

response.getBody()正在打印来自facbook的json。但在将其传递给服务时,我正在调用DAO'S save()方法。那时我收到以下错误,

[ERROR] [DefaultQuartzScheduler_Worker-2] org.quartz.core.JobRunShell - Job DEFAULT.FB_Details threw an unhandled Exception: 
org.hibernate.HibernateException: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here

我搜索了我的错误,我得到了一些解决方案,这不适合我的应用程序。我使用的是spring 3.0.5 Version和quartz 1.8.6。许多博客和类似的结果向我展示了如何在特定的时间间隔内运行cron作业。但这对我没用。如果有人帮助我解决这个问题,我将不胜感激。希望我的问题很明确。

提前谢谢。

2 个答案:

答案 0 :(得分:1)

原因是您从同一个控制器调用transational方法。 Spring需要为transation注释创建代理。您可以通过自动装配或从spring上下文中获取bean来实现,但是您必须将此方法移动到单独的类。

另一个(脏)解决方案是直接在方法中创建hibernate会话。

答案 1 :(得分:1)

因为没有正在进行的事务而抛出HibernateException

@Transactional上的FacebookControllerHelper.getUserLikes(Token accessToken, Users user)无效。 Spring使用proxies来实现事务行为。但是为了使其工作,FacebookControllerHelper的生命周期应该由spring管理,而Quartz实例化FacebookControllerHelper作业则不是这样。您可以使用aspectj代理在spring之外管理的对象,但这对您的用例来说可能有点复杂。

真正的问题可能是您的服务或dao都不是事务性的。 Facebook服务和dao可能是由spring管理的,所以你应该至少制作dao或service transactional。无论如何,在服务层上声明交易是一种很好的做法。

如果您确实要进行FacebookControllerHelper事务处理,则应使用aspectj,使用TransactionTemplate或让spring通过配置自定义SchedulerFactory来管理作业的生命周期。