繁体   English   中英

在使用Executor服务创建的线程中使用声明式事务

[英]Use declarative Transaction in Thread created using Executor Service

我有一个带有注释@Controller的服务层类,并且在服务调用中正在线程中生成,并且正在更新数据库中的某些内容。 我在线程的方法中使用了@transaction注解。 但是我收到了休眠异常“找不到会话”。 我是否需要向Thread添加任何注释?

org.hibernate.HibernateException:在org.hibernate.internal.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:978)的org.hibernate.internal.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:978)上的org.springframework.orm.hibernate4.SpringSessionContext.currentSession(SpringSessionContext.java:97)上找不到当前线程的会话com.mediaiq.cms.persistence.AgencyRepository.getById(AgencyRepository.java:20)上的.mediaiq.commons.persistence.BaseRepository.getCurrentSession(BaseRepository.java:30)在com.mediaiq.mail.client.AgencyLookupReportByDayClient.emailAgencyBgencyLookupConfirm .java:84),位于com.mediaiq.mail.client.AgencyLookupReportByDayClient.sendemailreport(AgencyLookupReportByDayClient.java:67),位于com.mediaiq.mail.client.BaseMailClient.run(BaseMailClient.java:222),位于java.util.concurrent。 Java的Executors $ RunnableAdapter.call(Executors.java:471)在java.util.concurrent.FutureTask $ Sync.innerRun(FutureTask.java:334)在java.util.concurrent.FutureTask.run(FutureTask.java:166)在Java .util.concurrent.ThreadPoolExecutor.run java.util.concurrent.ThreadPoolExecutor $ Worker.run(ThreadPoolExecutor.java:615)处的Worker(ThreadPoolExecutor.java:1145)在java.lang.Thread.run(Thread.java:722)处

@Repository
public class BaseMailClient implements Runnable {

    public BaseMailClient() {

    }

    public BaseMailClient(PlacementsRepository placementsRepository, SessionFactory sessionFactory, String sessionID) {
    this.placementsRepository = placementsRepository;
    this.sessionFactory = sessionFactory;
    this.sessionID = sessionID;
    }

    public BaseMailClient(AgencyRepository agencyRepository, SessionFactory sessionFactory, String sessionID) {

    this.agencyRepository = agencyRepository;
    this.sessionFactory = sessionFactory;
    this.sessionID = sessionID;
    }

    private String      sessionID        = null;

    @Autowired
    private SessionFactory  sessionFactory;


    @Autowired
    private PlacementsRepository  placementsRepository;
    @Autowired
    private AgencyRepository      agencyRepository;



    final static Logger    logger          =LoggerFactory.getLogger(BaseMailClient.class);



    @Override
    public void run()
    {

        sendemailreport();

    }

@Transactional
    public void sendemailreport()
    {
        checkSessionID();
        try {
        emailAgencyLookupConfirmation();
        emailAgencyLookup();
        }
        catch (IOException | FailedToCreateTempFile e) {
        logger.info("Failed To mail due to exception :" + e.getMessage());
        }
        catch (Throwable e) {
        logger.info("Failed To mail due to exception :" + e.getMessage());
        }
    }

}

服务等级:

@Transactional
@Controller
@RequestMapping(URLEndPoints.EMAIL)
public class SendMailService {

    @Autowired
    PlacementsRepository       placementsRepository;
    @Autowired
    AgencyRepository       agencyRepository;
    /**
     * 
     */
    @Autowired
    private SessionFactory   sessionFactory;

    @Autowired
    private ThreadPoolTaskExecutor mailJobExecutor;

    final static Logger     logger = LoggerFactory.getLogger(SendMailService.class);
 @RequestMapping(method = RequestMethod.POST, value = URLEndPoints.EMAIL_AGENCY_LOOKUP_BY_DAY, produces = "application/json")
    @ResponseBody
    public String emailAgencyLookupByDay(ServletRequest request,@PathVariable("agencyID") Integer agencyID,
              @PathVariable("startDate") @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) Date startDate,
              @PathVariable("endDate") @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) Date endDate )
    {
        logger.debug("POST:SendEmail:AgencyLookup");
        String sessionId = getSessionIDFromCookie(request);
        BaseClient mailServiceClient = new BaseClient(getAgencyRepository(), getSessionFactory(), sessionId);
        logger.debug("Getting Executor Instance");
        mailJobExecutor.submit(mailServiceClient);
        logger.debug("Submitted to Executor");
        return "SUCCESS";
    }
}

这里有些错误。

首先,您自己创建了BaseClient对象,因此Spring无法添加@Transactional行为。

BaseClient mailServiceClient = new BaseClient(getAgencyRepository(), getSessionFactory(), sessionId);

相反,您应该让Spring为您创建那种类型的bean。 使用prototype范围。

其次,您需要仔细阅读Spring文档中有关Spring代理机制的条目。 不幸的是,从同一个类中的非事务方法中调用@Transactional方法时,您不能指望任何事务行为,这就是您在这里所做的

@Override
public void run()
{
    sendemailreport();
}

@Transactional
public void sendemailreport()
{

sendemailreportthis引用上调用, this引用是对象本身,而不是代理。 因此,它将没有任何交易行为。

考虑在异步执行的同时查看@Async批注。

在Spring外部创建的线程将不会附加休眠会话。 您将需要将新的休眠会话手动附加到线程;

Session session = SessionFactoryUtils.openSession(sessionFactory);
try
{
    TransactionSynchronizationManager.bindResource(sessionFactory, new SessionHolder(session));
}
catch(Exception e)
{
    Logger.debug("Session already bound");
}

(您将需要注入sessionFactory)。

在线程完成之前,请确保会话未绑定;

public static void closeSession(Session se)
{
    try
    {
        try
        {
            TransactionSynchronizationManager.unbindResource(sessionFactory);
        }
        finally
        {
            if (se != null && se.isOpen() && se.isConnected())
            {
                SessionFactoryUtils.closeSession(se);
            }
        }
    }
    catch (HibernateException e)
    {
        Logger.fatal("Could not close session", e);
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM