Spring + Hibernate的save()方法无法工作

3
我附上了以下 Spring 服务(有问题的)代码:

@Async
    public void performSeismicOperations(Integer sessionUserId,
            int seismicFileId, String seismicFileName, ShClstr targetCluster,
            Collection<String> listOperations, String processedFolderName,
            Map<String, Object[]> args, String userNotes) throws IOException {

            .
            .
            .
            /*some code*/
            .
            .
        Date currentDate = new Date(System.currentTimeMillis());

            /*IMMEDIATE JOB ENTRY*/    
        log.info("Start : Inserting in sh_job to assure user");
        ShJob shJob = new ShJob(user, ClusterConstants.JOB_SUBMITTED,
                currentDate, null, null, null);
        shJobDAO.save(shJob);
        log.info("End : Inserting in sh_job to assure user");

        /*some time-consuming operation - 1*/

        SeismicFiles processedSeismicFile = new SeismicFiles(user,
                processedFolderName, 0, HDFSConstants.PROCESSED, currentDate);
        seismicFilesDAO.persist(processedSeismicFile);

        /*some time-consuming operation - 2*/

        log.info("Start : Updating the Hadoop job id");
        shJob.setShjHadoopJobId(hadoopJobId);
        shJobDAO.attachDirty(shJob);
        log.info("End : Updating the Hadoop job id");

            .
            .
            .
            /*some code*/
            .
            .

        log.info("Returning from SeismicHadoopServiceImpl.performSeismicOperations()");
    }

DAO代码

import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.LockMode;
import org.hibernate.Query;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Example;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import com.lnt.seismichadoop.pojo.ShJob;

@Repository
public class ShJobDAO {

    private static final Log log = LogFactory.getLog(ShJobDAO.class);

    @Autowired
    private SessionFactory sessionFactory;

    public void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }

    public void persist(ShJob transientInstance) {
        log.debug("persisting ShJob instance");
        try {
            sessionFactory.getCurrentSession().persist(transientInstance);
            log.debug("persist successful");
        } catch (RuntimeException re) {
            log.error("persist failed", re);
            throw re;
        }
    }

    public void save(ShJob transientInstance) {
        log.debug("SAVING ShJob instance");
        try {
            sessionFactory.getCurrentSession().save(transientInstance);
            log.debug("save successful");
        } catch (RuntimeException re) {
            log.error("save failed", re);
            throw re;
        }
    }

    public void attachDirty(ShJob instance) {
        log.debug("attaching dirty ShJob instance");
        try {
            sessionFactory.getCurrentSession().saveOrUpdate(instance);
            log.debug("attach successful");
        } catch (RuntimeException re) {
            log.error("attach failed", re);
            throw re;
        }
    }

    public void attachClean(ShJob instance) {
        log.debug("attaching clean ShJob instance");
        try {
            sessionFactory.getCurrentSession().lock(instance, LockMode.NONE);
            log.debug("attach successful");
        } catch (RuntimeException re) {
            log.error("attach failed", re);
            throw re;
        }
    }

    public void delete(ShJob persistentInstance) {
        log.debug("deleting ShJob instance");
        try {
            sessionFactory.getCurrentSession().delete(persistentInstance);
            log.debug("delete successful");
        } catch (RuntimeException re) {
            log.error("delete failed", re);
            throw re;
        }
    }

    public ShJob merge(ShJob detachedInstance) {
        log.debug("merging ShJob instance");
        try {
            ShJob result = (ShJob) sessionFactory.getCurrentSession().merge(
                    detachedInstance);
            log.debug("merge successful");
            return result;
        } catch (RuntimeException re) {
            log.error("merge failed", re);
            throw re;
        }
    }

    public ShJob findById(java.lang.Integer id) {
        log.debug("getting ShJob instance with id: " + id);
        try {
            ShJob instance = (ShJob) sessionFactory.getCurrentSession().get(
                    "com.lnt.seismic.dao.ShJob", id);
            if (instance == null) {
                log.debug("get successful, no instance found");
            } else {
                log.debug("get successful, instance found");
            }
            return instance;
        } catch (RuntimeException re) {
            log.error("get failed", re);
            throw re;
        }
    }

    public List findByExample(ShJob instance) {
        log.debug("finding ShJob instance by example");
        try {
            List results = sessionFactory.getCurrentSession()
                    .createCriteria("com.lnt.seismic.dao.ShJob")
                    .add(Example.create(instance)).list();
            log.debug("find by example successful, result size: "
                    + results.size());
            return results;
        } catch (RuntimeException re) {
            log.error("find by example failed", re);
            throw re;
        }
    }

    public List<ShJob> findAll() {
        log.debug("finding JobStatus instance by findAll");
        try {
            Query query = sessionFactory.getCurrentSession().createQuery(
                    "from ShJob");
            List<ShJob> results = query.list();
            log.debug("find by findAll successful, result size: "
                    + results.size());
            return results;
        } catch (RuntimeException re) {
            log.error("find by example failed", re);
            throw re;
        }
    }
}

我的需求是,在处理开始时(/立即作业输入/的代码中),一个条目必须进入作业表。在 /一些耗时操作 - 2/之后,我将使用适当的状态更新同一条目。 虽然我读到了save()和persist()之间的区别,但我的save()仍然推迟了插入操作,直到 /一些耗时操作 - 2/完成,这反过来导致前端显示的条目非常晚。
请指导我犯了哪些错误。 第1次编辑 在我的情况下,用户提交一个操作请求,该请求发送到上述标记为@Async的服务方法——用户必须看到一个带有“已提交”显示的页面,而服务方法仍在进行操作。在这种情况下,我应该使用session.flush()还是需要进行任何代码更改?

你尝试过在保存后执行“flush”操作吗? - Nayan Wadekar
1个回答

3
savepersist,以及通常与持久实体相关的每个操作,都会被延迟到真正必要的时候才执行,以避免不必要的数据库往返。您可以使用session.flush()让Hibernate将所有待处理更改写入数据库,但这并不会使实体对前端可用,因为前端不使用与执行长操作和持久化实体的事务相同的事务来读取数据。由于事务在隔离中运行(默认隔离级别大多数情况下为READ_COMMITTED),事务在另一个事务提交到数据库之前不会看到其他事务写入的任何内容。如果要立即查看插入的实体,请在与其余长时间运行的操作分开的事务中保存它,或将隔离级别更改为READ_UNCOMMITTED。

在我的情况下,用户提交一个操作请求,该请求进入上述标记为@Async的服务方法 - 用户必须看到一个页面,其中显示他的请求状态为“已提交”,而服务方法仍在进行中。 在这种情况下,我应该使用session.flush()还是需要进行任何代码更改? - Kaliyug Antagonist
就像我说的那样:你需要有一个单独的事务,只负责保存工作并在继续长时间操作之前提交。Session.flush() 是无法帮助的。 - JB Nizet
你能提供一个示例代码吗,告诉我如何进行分离事务? - Kaliyug Antagonist
3
将该代码放入另一个Spring bean中,在一个使用@Transactional(propagation = Propagation.REQUIRES_NEW)注解的方法中。并阅读有关Spring文档中事务章节,所有内容都在那里得到了解释。 - JB Nizet

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接