我们正在使用服务层类来执行hibernate entitymanager操作,比如查找或持久化实体到我们的mysql数据库。我们运行集成测试(10000次),对数据库执行持久化,在第二步中,我们要查找此实体并更新实体的列('状态')。问题是,两个操作都是独立的,意味着什么:
有时,随机重复(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,然后关闭它,但它变得更糟。感谢您提供任何帮助或建议。