Hibernate EntityManager找不到对象(NoResultException),但对象在DB中

时间:2014-11-11 07:58:06

标签: java mysql hibernate jpa entity

我们正在使用服务层类来执行hibernate entitymanager操作,比如查找或持久化实体到我们的mysql数据库。我们运行集成测试(10000次),对数据库执行持久化,在第二步中,我们要查找此实体并更新实体的列('状态')。问题是,两个操作都是独立的,意味着什么:

  1. 创建实体并坚持
  2. 通过命名查询找到此特定实体并更新
  3. 有时,随机重复(1000,3500,6000)后,命名查询找不到实体,但我们在调试和获取NoResultException时看到实体在数据库中。

    以下是我们的示例代码:

    的persistence.xml

    <persistence>
        <persistence-unit name="GDCT_PU" transaction-type="RESOURCE_LOCAL">
    
            <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
    
            <!-- the JNDI data source -->
            <!--<non-jta-data-source>java:comp/env/jdbc/testDS</non-jta-data-source>-->
    
            <class>com.ikea.hrms.gdct.persistence.config.domain.Sequence</class>
            <class>com.ikea.hrms.gdct.persistence.config.domain.Journal</class>
    
            <properties>
            <!-- if this is true, hibernate will print (to stdout) the SQL it executes,
                    so you can check it to ensure it's not doing anything crazy -->
    
            <!-- since most database servers have slightly different versions of the
                SQL, Hibernate needs you to choose a dialect so it knows the subtleties of
                talking to that server -->
                <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/>
    
                <property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/DB_RU_PT"/>
    
                <property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver"/>
    
                <property name="hibernate.connection.username" value="dbru_pt"/>
                <property name="hibernate.connection.password" value="peterkloeppel1234"/>
    
                <property name="hibernate.connection.useUnicode" value="true" />
                <property name="hibernate.connection.characterEncoding" value="UTF-8" />
                <property name="hibernate.connection.release_mode" value="on_close"/>
    
                <!-- JDBC connection pool (use the built-in) -->
                <property name="hibernate.connection.pool_size" value="100" />
                <property name="org.hibernate.flushMode" value="COMMIT"/>
    
            <!-- this tell Hibernate to update the DDL when it starts, very useful
                for development, dangerous in production -->
                <property name="hibernate.hbm2ddl.auto" value="create"/>
            </properties>
        </persistence-unit>
    </persistence>
    

    SequenceService.java

    public static synchronized Sequence findOne(String personnelAreaCode, String documentType, String documentCreationDate, int seqNumber) {
        logger.info("Find one specific Sequence.");
    
        Sequence sequence = null;
    
        try {
            checkEM();
    
            if (EMFGlobal.getInstance().getLock().tryLock(10, TimeUnit.SECONDS)) {
                logger.info("Find one: " + personnelAreaCode + "-" + documentCreationDate + "-" + seqNumber + "-" + documentType);
                Query query = em.createNamedQuery(
                        "Sequence.findOne", Sequence.class);
    
                sequence = (Sequence) query
                        .setParameter("personalAreaCode", personnelAreaCode)
                        .setParameter("documentType", documentType)
                        .setParameter("documentCreationDate", documentCreationDate)
                        .setParameter("seqNumber", seqNumber)
                        .getSingleResult();
            }
        }
        catch(NoResultException nre) {
            logger.error(nre);
        }
        catch (InterruptedException e) {
            e.printStackTrace();
        }
        catch (JDBCConnectionException jdbcConnectionExc) {
            logger.debug("Could not prepare Statement Sequence.findOne");
            jdbcConnectionExc.printStackTrace();
        }
        catch (Exception e) {
            logger.error(e);
        }
        finally {
            disconnectEntityManager();
            EMFGlobal.getInstance().getLock().unlock();
        }
    
        return sequence;
    }
    
    
    public static synchronized void persistSequence(Sequence sequence) {
        // persist with state "Created"
        try {
            Sequence tmpSequence = SequenceService.findOne(sequence.getPersonalAreaCode(), sequence.getDocumentType(), sequence.getDocumentCreationDate(), sequence.getSeqNumber());
    
            if (EMFGlobal.getInstance().getLock().tryLock(10, TimeUnit.SECONDS)) {
                checkEM();
                em.getTransaction().begin();
    
                if (tmpSequence == null) {
                    em.persist(sequence);
                } else {
                    em.merge(sequence);
                }
    
                em.flush();
                em.getTransaction().commit();
            }
        } catch (org.hibernate.PersistentObjectException e) {
            logger.debug("Persisting sequence number went wrong. Probably problems with EntityManager.", e);
        } catch (InterruptedException e) {
            logger.error(e);
        } finally {
            disconnectEntityManager();
            EMFGlobal.getInstance().getLock().unlock();
        }
    }
    
    
    private synchronized static void checkEM() {
        logger.info("Init Entity Manager.");
        if (em == null || !em.isOpen()) {
            em = EMFGlobal.getInstance().getEm();
        } else {
            logger.info("EntityManager checked. EM is open and not null!");
        }
    }
    
    /**
     * Disconnecting EntityManager used by this class.
     */
    private static synchronized void disconnectEntityManager() {
        logger.info("Disconnecting the EntityManager.");
        if (em != null) {
            em.clear();
            if (em.isOpen()) {
                em.close();
            }
            em = null;
        }
    }
    

    SequenceTest.java

    public void testGenerateApprove() {
        Sequence s = null;
        for (int i = 1; i < 10000; i++) {
            try {
                s = SequenceNumberManager.generateNewSequence("\\021", "002", "141123");
                logger.error("During generateNewSequence for: \\021, 002, 141123");
            } catch (Exception e) {
                e.printStackTrace();
            }
    
            try {
                SequenceNumberManager.approveSequence(s);
            } catch (Exception e) {
                logger.error("During approveSequences for sequence: " + s.toString());
                e.printStackTrace();
            }
        }
    }
    

    SequenceNumberManager.java

    public static synchronized Sequence generateNewSequence(final String personalArea, final String form, final Date date) throws Exception {
        String personnelAreaCode = Constants.getPersonnelAreaCode().get(personalArea);
    
        String documentType = Constants.getformIdToDocType().get(form);
        if (documentType == null) {
            documentType = "";
        }
    
        SimpleDateFormat sdf = new SimpleDateFormat("yyMMdd");
    
        final char separator1 = '-';
    
        final String documentCreationDate = sdf.format(date);
    
        final char separator2 = separator1;
    
        logger.info("Getting next highest sequence number.");
        final int sequenceNumber = getNextSequenceNumber(personnelAreaCode, documentType, documentCreationDate);
    
        final char separator3 = separator1;
    
        Sequence sequence = new Sequence(personnelAreaCode, separator1, documentCreationDate, separator2,
                sequenceNumber, separator3, documentType);
    
        sequence.setFormNumber(form);
    
        Sequence seq = SequenceService.findOne(sequence.getPersonalAreaCode(), sequence.getDocumentType(), sequence.getDocumentCreationDate(), sequenceNumber);
    
        if (seq == null) {
            SequenceService.persistSequence(sequence);
        } else {
            logger.error("TAKING AN OLD SEQUENCE NUMBER!!!");
            return seq;
        }
    
        return sequence;
    }
    
    
    public static synchronized void approveSequence(Sequence sequence) throws Exception {
            String sequenceStr = sequence.toString();
            // check if approved
            if (sequence.getState().equalsIgnoreCase("Created")) {
                // set state to approved
                sequence.setState("Approved");
    
                java.util.Date persistingDate = new java.util.Date();
                java.sql.Date sqlDate = new java.sql.Date(persistingDate.getTime());
                sequence.setPersistingDate(sqlDate);
    
                SequenceService.persistSequence(sequence);
    
            } else if (sequence.getState().equalsIgnoreCase("Approved")) {
                logger.error("Sequence: " + sequenceStr + " is already approved. Please generate a new Sequence number.");
                throw new Exception("Sequence: " + sequenceStr
                        + " is already approved. Please generate a new Sequence number.");
            }
    
    }
    

    EMFGlobal.java

    public class EMFGlobal {
        private static Logger logger = Logger.getLogger(ReportingManager.class);
    
        private static EntityManagerFactory emf;
        private EntityManager em;
        private ReentrantLock lock;
    
        public void initEntityManagerFactory() {
            logger.info("Initializing the EntityManagerFactory for persistence unit GDCT_PU");
            if(emf == null || !emf.isOpen()) {
                emf = Persistence.createEntityManagerFactory("GDCT_PU");
            }
        }
    
        public void destroyEntityManagerFactory() {
            if(emf != null) {
                if(emf.isOpen()) {
                    emf.close();
                }
                emf = null;
            }
        }
    
    
        private static EMFGlobal instance = null;
    
        private EMFGlobal() {
            initEntityManagerFactory();
        }
    
        public static EMFGlobal getInstance() {
            if (EMFGlobal.instance == null) {
                EMFGlobal.instance = new EMFGlobal();
            }
            return EMFGlobal.instance;
        }
    
        public EntityManagerFactory getEmf() {
            initEntityManagerFactory();
            return emf;
        }
    
        public EntityManager getEm() {
            if(emf == null) {
                initEntityManagerFactory();
            }
            if(em == null || !em.isOpen()) {
                em = emf.createEntityManager();
            }
            return em;
        }
    
        public Lock getLock() {
            if(lock == null) {
                lock = new ReentrantLock();
            }
            return lock;
        }
    }
    

    Sequence.java

    @Entity(name = "sequence")
    @NamedQueries(value = {
            @NamedQuery(name = "Sequence.findByPersonalAreaCodeAndDocumentTypeAndDocumentCreationDate",
                    query = "SELECT s FROM sequence s WHERE s.personalAreaCode = :personalAreaCode AND s.documentType = :documentType AND s.documentCreationDate = :documentCreationDate"),
            @NamedQuery(name = "Sequence.findAll",
                    query = "SELECT s FROM sequence s"),
            @NamedQuery(name = "Sequence.findOne",
                    query = "SELECT s FROM sequence s WHERE s.personalAreaCode = :personalAreaCode AND s.documentType = :documentType AND s.documentCreationDate = :documentCreationDate AND s.seqNumber = :seqNumber"),
            @NamedQuery(name = "Sequence.getNextSequenceNumber",
                    query = "SELECT s FROM sequence s WHERE s.seqNumber=(SELECT max(s.seqNumber) FROM sequence s WHERE s.personalAreaCode = :personalAreaCode AND s.documentType = :documentType AND s.documentCreationDate = :documentCreationDate) AND s.personalAreaCode = :personalAreaCode AND s.documentType = :documentType AND s.documentCreationDate = :documentCreationDate")
    })
    public class Sequence implements Serializable {
    
        @Id
        @GeneratedValue(strategy = GenerationType.AUTO)
        private int seqId;
        private String personalAreaCode;
        @Column(nullable = false, length = 1)
        private char separator1;
        @Column(nullable = false, length = 6)
        private String documentCreationDate; // format: yyMMdd
        @Column(nullable = false, length = 1)
        private char separator2;
        @Column(nullable = false)
        private int seqNumber;
        @Column(nullable = false, length = 1)
        private char separator3;
        @Column(nullable = false)
        private String documentType;
    
        @Column(nullable = false)
        private String state;
        private Date persistingDate;
        @Column(nullable = false)
        private String formNumber;
    
    
        public Sequence() {
            // no-args constructor required by JPA spec
            // this one is protected since it shouldn't be used directly
        }
    
        /**
         * Constructs Sequence with state "Created".
         *
         * @param personalAreaCode     Personnel Area Code (PAC, e.g. RSO).
         * @param separator1           Separator between PAC and DCD.
         * @param documentCreationDate Document Creation Date (DCD).
         * @param separator2           Separator between DCD and SN.
         * @param seqNumber            Sequence count Number (SN).
         * @param separator3           Separator between SN and DT.
         * @param documentType         Document Type (DT).
         */
        public Sequence(String personalAreaCode, char separator1, String documentCreationDate, char separator2, int seqNumber, char separator3, String documentType) {
            this.personalAreaCode = personalAreaCode;
            this.separator1 = separator1;
            this.separator2 = separator2;
            this.seqNumber = seqNumber;
            this.separator3 = separator3;
            this.documentType = documentType;
            this.documentCreationDate = documentCreationDate;
            this.state = "Created";
        }
    
        public int getSeqId() {
            return seqId;
        }
    
        public void setSeqId(int seqId) {
            this.seqId = seqId;
        }
    
        public String getPersonalAreaCode() {
            return personalAreaCode;
        }
    
        public void setPersonalAreaCode(String personalAreaCode) {
            this.personalAreaCode = personalAreaCode;
        }
    
        public char getSeparator1() {
            return separator1;
        }
    
        public void setSeparator1(char separator1) {
            this.separator1 = separator1;
        }
    
        public char getSeparator2() {
            return separator2;
        }
    
        public void setSeparator2(char separator2) {
            this.separator2 = separator2;
        }
    
        public int getSeqNumber() {
            return seqNumber;
        }
    
        public void setSeqNumber(int seqNumber) {
            this.seqNumber = seqNumber;
        }
    
        public char getSeparator3() {
            return separator3;
        }
    
        public void setSeparator3(char separator3) {
            this.separator3 = separator3;
        }
    
        public String getDocumentType() {
            return documentType;
        }
    
        public void setDocumentType(String documentType) {
            this.documentType = documentType;
        }
    
        public String getDocumentCreationDate() {
            return documentCreationDate;
        }
    
        public void setDocumentCreationDate(String documentCreationDate) {
            this.documentCreationDate = documentCreationDate;
        }
    
        public String getState() {
            return state;
        }
    
        public void setState(String state) {
            this.state = state;
        }
    
        public Date getPersistingDate() {
            return persistingDate;
        }
    
        public void setPersistingDate(Date persistingDate) {
            this.persistingDate = persistingDate;
        }
    
        public String getFormNumber() {
            return formNumber;
        }
    
        public void setFormNumber(String formNumber) {
            this.formNumber = formNumber;
        }
    
        @Override
        public String toString() {
            return this.getPersonalAreaCode() + this.getSeparator1() + this.getDocumentCreationDate() + this.getSeparator2()
                    + this.getSeqNumber() + this.getSeparator3() + this.getDocumentType();
        }
    
        @Override
        public boolean equals(Object o) {
            if(o instanceof Sequence) {
                Sequence seq = (Sequence) o;
                return this.toString().equals(seq.toString());
            }
            else {
                return false;
            }
        }
    }
    

    我们希望有人可以帮助我们。我们还尝试了很多东西,比如在每次交易之前创建EntityManagerFactory和EntityManager,然后关闭它,但它变得更糟。感谢您提供任何帮助或建议。

0 个答案:

没有答案