2015-02-10 44 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