java - 在使用执行器服务创建的线程中使用声明性事务

标签 java spring hibernate

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

org.hibernate.HibernateException: No Session found for current thread at org.springframework.orm.hibernate4.SpringSessionContext.currentSession(SpringSessionContext.java:97) at org.hibernate.internal.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:978) at com.mediaiq.commons.persistence.BaseRepository.getCurrentSession(BaseRepository.java:30) at com.mediaiq.cms.persistence.AgencyRepository.getById(AgencyRepository.java:20) at com.mediaiq.mail.client.AgencyLookupReportByDayClient.emailAgencyLookupConfirmation(AgencyLookupReportByDayClient.java:84) at com.mediaiq.mail.client.AgencyLookupReportByDayClient.sendemailreport(AgencyLookupReportByDayClient.java:67) at com.mediaiq.mail.client.BaseMailClient.run(BaseMailClient.java:222) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471) at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:334) at java.util.concurrent.FutureTask.run(FutureTask.java:166) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) at 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)范围。

第二,你需要仔细阅读这篇entry in the Spring documentation about Spring's proxying mechanism.不幸的是,当从同一个类中的非事务方法调用 @Transactional 方法时,您不能期望任何事务行为,这就是您在此处所做的

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

@Transactional
public void sendemailreport()
{

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

Consider looking into the @Async annotation alongside asynchronous execution.

关于java - 在使用执行器服务创建的线程中使用声明性事务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21141459/

相关文章:

java - TCP 客户端/服务器通信只发送第一条消息?

java - Android 至 PC RFCOMM channel

java - 对 jpa 实体管理器和延迟加载感到困惑

java - 使用 Hibernate @NaturalId 查找实体有什么好处

java - JUnit 如何测试构造函数?

java - 简单的Java计算器(需要小数帮助)

java - 无法呈现请求 [/countries] 的错误页面,因为响应已提交。因此,响应可能有错误的状态代码

java - Hibernate Validator 注释不适用于 spring mvc

java - Spring Data - 无法捕获服务层中的 DataIntegrityViolationException

c# - 批量HQL插入