2015-02-10 38 views
0

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

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

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

编辑(在底部的另一编辑 - 对不起): EZTable和EZRow被提取的行正在工作。 EmailReminder我不得不用EmailReminder.with包裹...现在调用ServiceUtils.handleSubjectOrMessageString(ezTable, ezRow, emailReminder.subject)的行会引发一个异常(这是“现在”添加的 - 整个job-class使用简单的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(); 
      } 
     } 
    } 
} 

的静态方法在我的util类下src/groove(行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 

编辑再次:(: 我有我的静态方法很多嵌套调用(在matcher.appendReplacement(stringBuffer, fetchCellValues(ezcell, ezcolumn)) - 方法0呼吁更深层次的获取价值观和我实际上是在一个呼叫得到一个“无会话” -exception(定期调用所有其他调用试图获取另一个域对象):

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

注意:我也试过声明作业'@Transactional',虽然文档说:“作业默认情况下配置为Hibernate会话有约束,每次执行作业时都会使用线程”https://grails.org/Job+Scheduling+% 28夸脱%29 – 2015-02-11 00:10:17

回答

1

你可以像任何地方一样使用它们。两者都独立于他们所要求的班级; withTransaction只是在事务中运行包装代码,如果有事务加入当前活动事务,并且withSession使得当前Hibernate Session对包装代码可用,否则不执行任何操作。

你没有指出任何需要的理由,所以不明白特别提供什么建议。如果您只是读取数据,则不需要事务处理;如果您调用的是域类方法,则不需要访问会话。

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

但是,无论您是因为延迟加载还是因为您正在更新而使您的代码事务处理,您通常应该在事务性服务中完成这项工作。

服务是伟大的事务性工作,因为他们是通过默认的事务(仅适用于那些没有@Transactional注释和包括static transactional = false都是非交易服务),并且可以很容易地配置事务划分每个类和每个方法与@Transactional注释。它们也非常适合封装业务逻辑,与它们的调用无关。通常不需要任何HTTP/Job /等服务方法。只需将它在String/number/boolean/object参数中所需的数据传递给它,并让它执行它的工作。我喜欢保持控制器简单,从请求参数中进行数据绑定并调用服务来完成实际工作,然后呈现响应或路由到下一页,并且我在Quartz作业中也做同样的事情。使用Quartz调度功能,但在服务中做真正的工作。像任何bean(def fooService)一样依赖注入服务,并将所有业务逻辑和数据库工作放在那里。它将事情在代码中进行了简洁的描述,并且使得测试更加容易,因为您可以测试服务方法而无需模拟HTTP调用或Quartz。

+0

嗨伯特 - 首先,非常感谢您的时间。尽管过去多年来我在许多不同的框架中创建了许多“小型”网络应用程序,但我最喜欢Grails。当你阅读有用的答案/文章时,你的名字似乎是我最后碰到的最后一个。你的时间非常感谢。谢谢!虽然上面的答案并没有直接帮助我,但我明白了你分享你的应用程序的思路。 – 2015-02-11 09:23:26

+0

我必须说,我试着从工作类调用服务,但遇到了相同的挑战,我认为这是因为我有一些关于域对象延迟加载数据的调用。我一定会再次尝试服务使用 - 让我回来。同时,我会尝试发布一些我已经完成的代码,这些代码正在挑战我。这是我第一次使用StackOverflow - 希望我能弄明白这一点:) – 2015-02-11 09:24:44

+0

好了,现在我将具有大量静态方法的util-classes转换为Grails中的Service-classes。在我的工作班级中,我已经定义了'def serviceUtilsService',以便将它注入作业类并调用相同的非静态方法('serviceUtilsService.handleSubjectOrMessageString(ezTable,ezRow,emailReminder.subject)') - 但现在我在'serviceUtilsService'对象上得到一个null异常:(看起来很多人都试过这个,它总是一个定义错误 - 即对象名称不正确。我看不到我' m做错了 – 2015-02-11 11:59:06