Grails,Jobs,Static Helper方法和Hibernate Session

时间:2015-02-10 23:47:56

标签: java hibernate session grails quartz-scheduler

我有一个Grails作业类(grails-app/jobs)需要调用静态(辅助)方法(在src/groovy中定义)。此方法分别在2个不同的域对象上调用get-和find-methods。方法调用的结果是返回一个简单的String(为此可以返回任何东西 - 无关紧要)。

我的问题是,当我调用一个包含2个(可能更多)不同域类的fetch的静态方法时,如何在作业类中使用.withTransaction.withSession? / p>

或者,如何在作业类中声明/使用Hibernate会话,以便我不必使用.withBlaBla?

编辑(底部的另一个编辑 - 抱歉): 获取EZTable和EZRow的行正在工作。 EmailReminder我不得不用EmailReminder.with包装......现在调用ServiceUtils.handleSubjectOrMessageString(ezTable, ezRow, emailReminder.subject)的行导致异常(这是“现在”添加 - 整个作业类在早期使用简单的String值工作)。

class EmailReminderJob implements Job {

    EmailReminder emailReminder
    EZTable ezTable
    EZRow ezRow

    static triggers = {}

    def void execute(JobExecutionContext context) {
        List<String> emails = new ArrayList<String>(0)

        ezTable = EZTable.get(new Long(context.mergedJobDataMap.get('ezTableId')))
        ezRow = EZRow.get(new Long(context.mergedJobDataMap.get('ezRowId')))
        EmailReminder.withTransaction { status ->
            emailReminder = EmailReminder.get(new Long(context.mergedJobDataMap.get('emailReminderId')))
            if(emailReminder.sendMessageToOwnerUser && emailReminder.ownerUser.email!=null)
                emails.add(emailReminder.ownerUser.email)
            if(emailReminder.sendMessageToOwnerCompany && emailReminder.ownerCompany.email!=null)
                emails.add(emailReminder.ownerCompany.email)
            if(emailReminder.emails!=null && emails.size()>0)
                emails.addAll(new ArrayList<String>(emailReminder.emails))
            if(emailReminder.messageReceiverUsers!=null && emailReminder.messageReceiverUsers.size()>0) {
                for(user in emailReminder.messageReceiverUsers) {
                    if(user.email!=null)
                        emails.add(user.email)
                }
            }
        }

        if(emails.size()>0) {
            String host = "localhost";
            Properties properties = System.getProperties();
            properties.setProperty("mail.smtp.host", host);
            Session session = Session.getDefaultInstance(properties);
            try{
                // Create a default MimeMessage object.
                MimeMessage message = new MimeMessage(session);
                message.setFrom(new InternetAddress(emailReminder.emailFrom));
                for(email in emails) {
                    message.addRecipient(
                        Message.RecipientType.TO,
                        new InternetAddress(email)
                    );
                }
                message.setSubject(ServiceUtils.handleSubjectOrMessageString(ezTable, ezRow, emailReminder.subject));
                message.setText(ServiceUtils.handleSubjectOrMessageString(ezTable, ezRow, emailReminder.definedMessage));
                Transport.send(message);
            }catch (MessagingException mex) {
                mex.printStackTrace();
            }
        }
    }
}

src/groove下的我的util-class中的静态方法(行EZColumn ezcolumn = EZColumn.get(id)和下一行导致异常):

def static String handleSubjectOrMessageString(EZTable eztable, EZRow ezrow, String subjectOrMessage) {
    String regex = '(?<=\\$\\$)(.*?)(?=\\$\\$)'
    Pattern pattern = Pattern.compile(regex)
    Matcher matcher = pattern.matcher(subjectOrMessage)
    StringBuffer stringBuffer = new StringBuffer();
    while(matcher.find()) {
        if(subjectOrMessage.substring(matcher.start(), matcher.end()).contains('#')) {
            String stringId = subjectOrMessage.substring(matcher.start(), matcher.end()).split('#')[0]
            String name = subjectOrMessage.substring(matcher.start(), matcher.end()).split('#')[1]
            try {
                Long id = new Long(stringId)
                EZColumn ezcolumn = EZColumn.get(id)
                EZCell ezcell = EZCell.findByEzTableAndEzRowAndEzColumn(eztable, ezrow, ezcolumn)
                matcher.appendReplacement(stringBuffer, fetchCellValues(ezcell, ezcolumn))
            } catch(NumberFormatException nfe) {
                if(stringId.equals("id")) {
                    if(name.equals("row"))
                        matcher.appendReplacement(stringBuffer, ezrow.id.toString())
                    else if(name.equals("table"))
                        matcher.appendReplacement(stringBuffer, eztable.id.toString())
                    else
                        matcher.appendReplacement(stringBuffer, "???")
                }
            }
        }
    }
    matcher.appendTail(stringBuffer);
    println stringBuffer.toString().replaceAll('\\$', "")
    return stringBuffer.toString().replaceAll('\\$', "")
}

例外:

| Error 2015-02-11 10:33:33,954 [quartzScheduler_Worker-1] ERROR core.JobRunShell  - Job EmailReminderGroup.ER_3_EZTable_3 threw an unhandled Exception: 
Message: null
   Line | Method
->> 202 | run in org.quartz.core.JobRunShell
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
^   573 | run in org.quartz.simpl.SimpleThreadPool$WorkerThread
| Error 2015-02-11 10:33:33,996 [quartzScheduler_Worker-1] ERROR core.ErrorLogger  - Job (EmailReminderGroup.ER_3_EZTable_3 threw an exception.
Message: Job threw an unhandled exception.
   Line | Method
->> 213 | run in org.quartz.core.JobRunShell
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
^   573 | run in org.quartz.simpl.SimpleThreadPool$WorkerThread
Caused by NullPointerException: null
->> 202 | run in org.quartz.core.JobRunShell
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
^   573 | run in org.quartz.simpl.SimpleThreadPool$WorkerThread
| Error 2015-02-11 10:33:34,005 [quartzScheduler_Worker-1] ERROR listeners.ExceptionPrinterJobListener  - Exception occurred in job: null
Message: org.quartz.SchedulerException: Job threw an unhandled exception. [See nested exception: java.lang.NullPointerException]
   Line | Method
->> 218 | run in org.quartz.core.JobRunShell
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
^   573 | run in org.quartz.simpl.SimpleThreadPool$WorkerThread
Caused by SchedulerException: Job threw an unhandled exception.
->> 213 | run in org.quartz.core.JobRunShell
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
^   573 | run in org.quartz.simpl.SimpleThreadPool$WorkerThread
Caused by NullPointerException: null
->> 202 | run in org.quartz.core.JobRunShell
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
^   573 | run in org.quartz.simpl.SimpleThreadPool$WorkerThread

再次编辑:(: 我在静态方法中有很多嵌套调用(fetchCellValues(ezcell, ezcolumn)中的matcher.appendReplacement(stringBuffer, fetchCellValues(ezcell, ezcolumn)) - 方法调用更深的值来获取值,实际上我在一次调用时得到了“无会话” - 异常调用其他调用尝试获取另一个域对象):

Message: org.quartz.SchedulerException: Job threw an unhandled exception. [See nested exception: org.hibernate.LazyInitializationException: could not initialize proxy - no Session]

1 个答案:

答案 0 :(得分:1)

你可以像在任何地方一样使用它们。两者都独立于他们所要求的阶级; withTransaction只是在事务中运行包装的代码,加入当前活动的事务(如果有的话),withSession使当前的Hibernate Session可用于包装的代码,否则不会任何东西。

您没有说明需要任何理由,因此具体建议并不明确。如果您只是在读取数据,则不需要事务,如果您正在调用域类方法,则不需要访问会话。

我过去提倡的withTransaction的一个用法(几乎是它的唯一用途,因为它通常被滥用)是在没有活动会话时避免延迟加载异常。在withTransaction块中包装代码具有创建会话并在块的持续时间内保持打开的副作用,并且允许您使用延迟加载的实例和集合。控制器具有活动会话,因为有一个开放式会话视图拦截器,它在请求开始时启动会话,将其存储在ThreadLocal中,并在请求结束时刷新并关闭它。作业很相似,因为插件使用Quartz作业开始/结束事件来做同样的事情。

但是,由于延迟加载或者您正在更新,是否要使代码处于事务性状态,您通常应该在事务性服务中进行工作。

服务非常适合事务性工作,因为它们在默认情况下是事务性的(只有没有@Transactional注释且包含static transactional = false的服务是非事务性的),并且很容易配置事务划分。具有@Transactional注释的class和per-method。它们也非常适合封装业务逻辑,而不管它们的调用方式如何;通常不需要服务方法来获得任何HTTP / Job /等。意识,只需将String / number / boolean / object参数中所需的数据传递给它,让它完成它的工作。

我喜欢保持控制器简单,从请求参数进行数据绑定并调用服务来完成实际工作,然后呈现响应或路由到下一页,我在Quartz作业中做同样的事情。使用Quartz作为其调度功能,但在服务中进行实际工作。依赖 - 像任何bean(def fooService)一样注入服务,并将所有业务逻辑和数据库放在那里。它使代码中的内容保持清晰,并使测试更容易,因为您可以测试服务方法,而无需模拟HTTP调用或Quartz。