休眠会话无故关闭

时间:2018-06-22 10:24:38

标签: spring hibernate jpa

我已经为此苦苦挣扎了好几天,我真的不知道这里发生了什么。 我有一些由用户触发的进程,它们发生在单独的线程上,该线程执行一些操作,并更新数据库中有关用户可以检索的进度的条目。 直到最近,这一切都运行良好,突然之间,有时似乎与任何事物都不相关,这些过程在第一次尝试延迟加载实体时失败。它们以几种不同的错误之一失败,所有这些错误最终都源于以某种方式关闭的休眠状态:

org.hibernate.SessionException: Session is closed. The read-only/modifiable setting is only accessible when the proxy is associated with an open session.

-

org.hibernate.SessionException: Session is closed!

-

org.hibernate.LazyInitializationException: could not initialize proxy - the owning Session was closed

-

org.hibernate.exception.GenericJDBCException: Could not read entity state from ResultSet : EntityKey[com.rdthree.plenty.domain.crops.CropType#1]

-

java.lang.NullPointerException
 at com.mysql.jdbc.ResultSetImpl.checkColumnBounds(ResultSetImpl.java:766)

我正在使用spring @Transactional来管理我的交易

这是我的配置:

@Bean
public javax.sql.DataSource dataSource() {
    // update TTL so that the datasource will pick up DB failover - new IP
    java.security.Security.setProperty("networkaddress.cache.ttl", "30");
    HikariDataSource ds = new HikariDataSource();
    String jdbcUrl = "jdbc:mysql://" + plentyConfig.getHostname() + ":" + plentyConfig.getDbport() + "/"
            + plentyConfig.getDbname() + "?useSSL=false";
    ds.setJdbcUrl(jdbcUrl);
    ds.setUsername(plentyConfig.getUsername());
    ds.setPassword(plentyConfig.getPassword());
    ds.setConnectionTimeout(120000);
    ds.setMaximumPoolSize(20);
    return ds;
}

@Bean
public JpaTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
    JpaTransactionManager manager = new JpaTransactionManager();
    manager.setEntityManagerFactory(entityManagerFactory);
    return manager;
}

@Bean
@Autowired
public LocalContainerEntityManagerFactoryBean entityManagerFactory(javax.sql.DataSource dataSource) {
    LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
    factory.setDataSource(dataSource);
    factory.setPackagesToScan("com.rdthree.plenty.domain");
    Properties properties = new Properties();
    properties.put("org.hibernate.flushMode", "ALWAYS");
    properties.put("hibernate.cache.use_second_level_cache", "true");
    properties.put("hibernate.cache.use_query_cache", "true");
    properties.put("hibernate.cache.region.factory_class",
            "com.rdthree.plenty.config.PlentyInfinispanRegionFactory");
    properties.put("hibernate.cache.infinispan.statistics", "true");
    properties.put("hibernate.cache.infinispan.query", "distributed-query");
    properties.put("hibernate.enable_lazy_load_no_trans", "true");
    if (plentyConfig.getProfile().equals(PlentyConfig.UNIT_TEST)
            || plentyConfig.getProfile().equals(PlentyConfig.PRODUCTION_INIT)) {
        properties.put("hibernate.cache.infinispan.cfg", "infinispan-local.xml");
    } else {
        properties.put("hibernate.cache.infinispan.cfg", "infinispan.xml");
    }

    factory.setJpaProperties(properties);
    HibernateJpaVendorAdapter adapter = new HibernateJpaVendorAdapter();
    adapter.setShowSql(false);
    adapter.setDatabasePlatform("org.hibernate.dialect.MySQLDialect");
    factory.setJpaVendorAdapter(adapter);
    return factory;
}

它的工作方式是由用户触发的线程遍历计划的集合并应用每个计划,应用计划的过程也会更新数据库上的进度实体。 整个线程bean标记为事务性的:

@Component
@Scope("prototype")
@Transactional(propagation = Propagation.REQUIRES_NEW, isolation = Isolation.READ_COMMITTED)
public class TemplatePlanApplicationThreadBean extends AbstractPlentyThread implements TemplatePlanApplicationThread {

...

@Override
public void run() {
    startProcessing();
    try {
        logger.trace(
                "---Starting plan manifestation for " + fieldCropReplaceDatePlantationDates.size() + " fields---");
        List<Plan> plans = new ArrayList<>();
        for (FieldCropReplaceDatePlantationDates obj : fieldCropReplaceDatePlantationDates) {
            for (TemplatePlan templatePlan : obj.getTemplatePlans()) {
                try {
                    plans.add(planService.findActivePlanAndManifestTemplatePlan(templatePlan, organization,
                            obj.getPlantationDate(), obj.getReplacementStartDate(), obj.getFieldCrop(),
                            autoSchedule, schedulerRequestArguments, planApplicationProgress, false));
                } catch (ActivityException e) {
                    throw new IllegalArgumentException(e);
                }
            }
            Plan plan = plans.get(plans.size() - 1);
            plan = planService.getEntityById(plan.getId());
            if (plan != null) {
                planService.setUnscheduledPlanAsSelected(plan);
            }
            plans.clear();
        }
        if (planApplicationProgressService.getEntityById(planApplicationProgress.getId()) != null) {
            planApplicationProgressService.deleteEntity(planApplicationProgress.getId());
        }
    } catch (Exception e) {
        logger.error(PlentyUtils.extrapolateStackTrace(e));
        connector.createIssue("RdThreeLLC", "plenty-web",
                new GitHubIssueRequest("Template plan application failure",
                        "```\n" + PlentyUtils.extrapolateStackTrace(e) + "\n```", 1, new ArrayList<>(),
                        Lists.newArrayList("plentytickets")));
        planApplicationProgress.setFailed(true);
        planApplicationProgressService.saveEntity(planApplicationProgress);
    } finally {
        endProcessing();
    }
}

这是线程调用的方法:

@Override
@Transactional(propagation = Propagation.REQUIRES_NEW)
public synchronized Plan findActivePlanAndManifestTemplatePlan(TemplatePlan templatePlan,
        ServiceProviderOrganization organization, Date plantationDate, Date replacementDate, FieldCrop fieldCrop,
        boolean autoSchedule, SchedulerRequestArguments schedulerRequestArguments, Progress planProgress,
        boolean commit) throws ActivityException {
    Plan oldPlan = getLatestByFieldCrop(fieldCrop);
    List<Activity> activitiesToRemove = oldPlan != null
            ? findActivitiesToRemoveAfterDate(oldPlan, replacementDate != null ? replacementDate : new Date())
            : new ArrayList<>();
    List<PlanExpense> planExpensesToRemove = oldPlan != null
            ? findPlanExpensesToRemoveAfterDate(oldPlan, replacementDate != null ? replacementDate : new Date())
            : new ArrayList<>();
    Date oldPlanPlantationDate = oldPlan != null ? inferPlanDates(oldPlan).getPlantationDate() : null;
    if (oldPlan != null) {
        if (commit) {
            oldPlan.setReplaced(true);
        }
        buildPlanProfitProjectionForPlanAndField(oldPlan, Sets.newHashSet(activitiesToRemove),
                Sets.newHashSet(planExpensesToRemove));
    }
    if (commit) {
        for (Activity activity : activitiesToRemove) {
            activityService.deleteEntity(activity.getId());
        }
        for (PlanExpense planExpense : planExpensesToRemove) {
            planExpenseService.deleteEntity(planExpense.getId());
        }
    }
    oldPlan = oldPlan != null ? getEntityById(oldPlan.getId()) : null;
    Plan plan = manifestTemplatePlan(templatePlan, oldPlan, organization,
            plantationDate != null ? plantationDate : oldPlanPlantationDate, replacementDate, fieldCrop,
            autoSchedule, schedulerRequestArguments, planProgress, commit);
    if (!commit) {
        setPlanAllocationsUnscheduled(plan);
    }
    return plan;
}

使我丧命的是错误仅在某些时候发生,所以我无法真正调试它,也无法将它与任何内容相关联。

关于什么原因导致会话关闭的任何想法?

我尝试关闭任何其他线程,因此基本上这是唯一正在运行的线程,没有帮助

谢谢

0 个答案:

没有答案
相关问题