2017-07-16 5 views
0

Ich habe ein Grails 2.2.4 Projekt, das läuft gut. Kürzlich habe ich ein Problem bekommen. Die Anwendung druckt einen Bericht und dieser wird als PDF heruntergeladen. Ein Kunde hat eine große Menge an Datensätzen in der Datenbank für diesen Bericht und daher benötigt der Bericht viel Zeit für die Generierung. Daher muss ich dies als neuen Thread hinzufügen, der im Hintergrund ausgeführt wird und den Bericht generiert und an den Benutzer sendet.Hibernate Sitzung Problem mit neuen Thread von Grails Controller gestartet

Also habe ich eine neue Klasse erstellt, die Runnable implementiert und den gleichen Dienst aufruft, der vom Controller aufgerufen wurde.

public class JasperReportProcessor implements Runnable { 

    private static final Logger LOG =  LoggerFactory.getLogger(JasperReportProcessor.class); 

    private ReportProcessor reportProcessor; 
    private Parties party; 
    private String bObject; 
    private String contextUrl; 
    private String shipmentIds; 
    private Map<String, String> parameters; 
    private Locale locale; 


    public JasperReportProcessor() {} 

    public JasperReportProcessor(final ReportProcessor reportProcessor, final Parties party, 
     final String bObject, final String contextUrl, final String  shipmentIds, final Map<String, String> parameters) { 
    this.reportProcessor = reportProcessor; 
    this.party = party; 
    this.bObject = bObject; 
    this.contextUrl = contextUrl; 
    this.shipmentIds = shipmentIds; 
    this.parameters = parameters; 
    this.locale = locale; 
    } 

    @Override 
    public void run() { 
    SessionFactory sessionFactory = DataSQLSupport.getSessionFactory(); 
    Session currentSession = null; 
    Transaction tx =null; 
    try { 
     currentSession = sessionFactory.openSession(); 
     tx = currentSession.beginTransaction(); 
     LOG.info("THREAD STARTED for REPORT...................."); 
     //Below code was earlier called directly from Controller. 
     Object[] reportData = this.reportProcessor.process(this.party,  this.bObject, this.contextUrl, this.shipmentIds, this.parameters,  this.locale); 
     LOG.info("REPORT generated....{}", reportData[0]); 
     LOG.info("THREAD ENDED..........."); 
     tx.commit(); 
    } catch (Exception ex) { 
     LOG.error("OMG ERROR in THREAD....", ex); 
     tx.rollback(); 
    } finally { 
     currentSession.flush(); 
     currentSession.close(); 
    } 

    } 

} 

Der Controller-Code ist wie folgt.

if(!shippingReportProcessor.isReportLarge(params.selecteditems, params.level)){ 
        Object[] reportData = shippingReportProcessor.process(session["usercompany"], bObject, url, params.selecteditems, params, request.getLocale()) 

        response.setContentType(new MimetypesFileTypeMap().getContentType(reportData[0])) 
        response.setHeader("Content-disposition", "attachment; filename=\""+reportData[0]+"\"") 
        response.outputStream << reportData[1] 
        } else { 
        Thread reportThread = new Thread(new JasperReportProcessor(tpsynergyUtilsService, shippingReportProcessor, session["usercompany"], bObject, url, params.selecteditems, params, request.getLocale())); 
        reportThread.start(); 
        } 

Ich habe auch eine andere Java-Klasse in src/java in meinem Grails-Projekt, das als @component markiert ist, wird Session autowired. Die untere Methode funktioniert einwandfrei, wenn der Berichterstellungsdienst vom Controller aus aufgerufen wird.

Die getCurrentSession-Methode wird jedoch unterhalb der Ausnahme ausgelöst, wenn sie von einem neuen Thread aufgerufen wird, der in der obigen Controller-Methode erstellt wurde.

Message: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here 
    Line | Method 
->> 238 | getDataList in tpsynergy.DataSQLSupport 
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
| 51 | process  in tpsynergy.reports.ShippingReportProcessor 
| 58 | run . . . . in tpsynergy.reports.JasperReportProcessor 
^ 745 | run   in java.lang.Thread 

I haben versucht, die unten in datasource.groovy

hibernate.current_session_context_class = 'thread' 

Zugabe habe ich auch versucht, den Faden von Dienst anstelle der Controller Aufrufen aber auch nicht funktioniert. Ich habe auch die Transaktion in Thread geöffnet.

Ich habe nach der Lösung gesucht, aber meistens fand ich Konfigurationsprobleme. Aber seit meinem Projekt arbeitet Flossen, wenn der Berichtserstellungsdienst direkt vom Controller aufgerufen wird und das Problem nur auftritt, wenn ein neuer Thread erstellt wird. Es scheint also kein Konfigurationsproblem zu sein.

Ich habe Code hinzugefügt, um neue Sitzung im neuen Thread zu erstellen, aber das scheint nicht zu funktionieren.

Auch das Problem ist nur mit dem Klassencode src/java (die ich oben hinzugefügt habe). DB-Interaktionen in anderen Diensten von neuem Thread funktionieren einwandfrei. Das Problem tritt nur bei getCurrentSession auf. openSession funktioniert perfekt in src.java class in grails.

Bitte schlagen Sie vor, was das Problem sein könnte.

Antwort

0

Hier ist, was ich habe eine Sitzung in einem Asynchron-Verarbeitungs-Thread-Pool auf, was die Quartz-Plugin tut Basis getan habe:

// Inject persistence interceptor 
PersistenceContextInterceptor persistenceInterceptor 

void myMethod() { 
    persistenceInterceptor.init() 

    // insert code here. Transactions are handled by service classes. 

    persistenceInterceptor.flush() 
    persistenceInterceptor.clear() 
    persistenceInterceptor.destroy() 
} 

Ich hoffe, das hilft dir.

Verwandte Themen