我正在运行一个运行良好的Grails 2.2.4项目。最近我遇到了一个问题。应用程序打印报告,并以PDF格式下载。客户在该报告的数据库中有大量记录,因此报告需要花费大量时间来生成。因此,我需要将其添加为在后台运行的新线程,并生成报告并将其邮寄给用户。
所以我创建了一个实现Runnable的新类,并调用从控制器调用的相同服务。
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();
}
}
}
控制器代码如下。
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();
}
我的grails项目中的src / java中还有另一个java类,标记为@component,SessionFactory是自动装配的。当从控制器调用报告生成服务时,以下方法可以正常工作。
@Component
class DataSQLSupport{
private static SESSION_FACTORY;
public DataSQLSupport() {}
@Autowired
public void setSessionFactory(SessionFactory sessionFactory) {
SESSION_FACTORY = sessionFactory;
}
public static SessionFactory getSessionFactory(){
return SESSION_FACTORY;
}
public static List<Object[]> getDataList(final String dataQuery) {
Session currentSession = SESSION_FACTORY.getCurrentSession();
Query query = currentSession.createSQLQuery(dataQuery);
return (List<Object[]>) query.list();
}
}
但是当从上面的控制器方法中创建的新线程调用时,getCurrentSession方法抛出异常。
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
我尝试在datasource.groovy中添加以下内容
hibernate.current_session_context_class = 'thread'
我也试过从服务而不是控制器调用线程,但这也没有用。我还在线程中打开了事务。
我已经搜索了解决方案,但大多数情况下我发现是配置问题。但是,当我的项目工作时,如果直接从控制器调用报告生成服务,则只有在创建新线程时才会出现问题。所以它似乎不是配置问题。
我已添加代码以在新主题中创建新会话,但似乎无法正常工作。
问题还在于src / java类代码(我上面已添加)。来自新线程的其他服务中的数据库交互工作正常。问题仅出在getCurrentSession上。 openSession在grails中的src.java类中运行得很好。
请提出可能存在的问题。
答案 0 :(得分:0)
以下是我根据Quartz插件的作用在异步处理线程池中进行会话的过程:
// Inject persistence interceptor
PersistenceContextInterceptor persistenceInterceptor
void myMethod() {
persistenceInterceptor.init()
// insert code here. Transactions are handled by service classes.
persistenceInterceptor.flush()
persistenceInterceptor.clear()
persistenceInterceptor.destroy()
}
我希望能帮助你。