当前位置: 首页 > 知识库问答 >
问题:

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

牛经赋
2023-03-14

我有一个服务层类,它有annotation@Controller和我在线程中生成的服务调用,它正在更新数据库中的某些内容。我在thread的方法中使用了@transaction注释。但我遇到了hibernate异常“找不到会话”。我需要为线程添加任何注释吗?

lient.runHibernateException:在lient.java:222没有找到当前线程的Session 4. SpringSessionCjava.util.concurrent.会话(SpringSessionCdapter.call)在xecutors.java:471SessionFactoryIjava.util.concurrent.货币会话(SessionFactoryIync.inner)在ask.java:334BaseRjava.util.concurrent.货币会话(BaseRask.run)在ask.java:166AgencyRjava.util.concurrent.ById(AgencyRxecutor.run)在com.mediaiq.mail.client.AgencyLookupReportByDayClient.emailAgencyLookupConfirming(AgencyLookupReportByDayClient.java:84)在com.mediaiq.mail.client.AgencyLookupReportByDayClient.sendemailreport(AgencyLookupReportByDayClient.java:67)在com.mediaiq.mail.client.BaseMailCorg.hibernate.(BaseMailCorg.springframework.orm.hibernate)在ontext.currentExectors$RunnableAontext.java:97(Eorg.hibernate.internal.)在mpl.getFutureTask$Smpl.java:978运行(FutureTcom.mediaiq.commons.persistence.)在epository.getFutureTepository.java:30(FutureTcom.mediaiq.cms.persistence.)在epository.getThreadPoolEepository.java:20工作者(ThreadPoolExector. java: 1145)在java. util. concurrent. ThreadPoolExecececle

@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";
    }
}

共有2个答案

夏侯腾
2023-03-14

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

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);
    }
}
壤驷经国
2023-03-14

这里有几件事不对劲。

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

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

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

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

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

@Transactional
public void sendemailreport()
{

sendmailreport引用上调用,该引用是对象本身,而不是代理。因此,它不会有任何事务行为。

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

 类似资料:
  • 我想做的是,创建一个executor服务(具有固定数量的线程)-->,然后将新线程的创建/新线程的任务执行移交给该executor。 由于我对Executor非常陌生,所以我想知道的是,我如何更改上面的代码,以便不是形成一个新的单独的线程,而是在线程池中创建一个新线程。我看不到任何创建线程的命令(在线程池中)-->将上面的任务移交给那个线程(而不是像上面那样移交给一个独立的线程)。 请告诉我如何解

  • 我在詹金斯内部写了一个声明性管道。此管道应在远程Docker服务器上的Docker容器中运行。 我阅读了自定义执行环境: 自定义执行环境 Pipeline的设计可以轻松地将Docker映像用作单个阶段或整个管道的执行环境。这意味着用户可以定义其管道所需的工具,而无需手动配置代理。实际上,任何可以打包在Docker容器中的工具。只需对Jenkins文件进行少量编辑即可轻松使用。 它工作,但它使用詹金

  • 问题内容: 问题答案: 它比您想象的简单得多: 比起您,您只需要使用新的即可。 有关更多信息,您可以阅读一些文档。 但是,在您的代码中您犯了一些错误: 该参数必须是一个对象不是“已调用”对象。 要处理许多请求,您需要构建一个线程池。如果仅使用一个线程,则它是主线程还是“子”线程没有任何区别。

  • 请说出这段代码有什么问题。

  • 我正在将ApacheFelixSCR注释迁移到OSGI声明性服务[AEM]。在迁移过程中,我无法在DS中找到基数的精确替换。 现有的SCR实施: 现在它在OSGi声明性服务中迁移如下 在DS注释实现中,我必须映射@Property中存在的参数基数。请推荐我

  • 我尝试将Azure服务总线与ApacheQPID和Spring与事务集成。 但Azure服务总线AMQP实现似乎不支持事务。这是真的吗?我没有找到相关信息。 这是我的JMS配置 这是我的spring集成片段: 它与session transact=“false”配合使用,但与session transact=“true”配合使用时会产生错误: QPID跟踪