2015-03-02 48 views
1
產生

我指我的最後一個問題,這個話題,你可以在這裏找到無狀態的EJB導致錯誤的SQL:MySQL Syntax Error by combining CASE and LIMIT (only sometimes) - generated by JPA可能的競爭條件beetween通過JPA

錯誤發生還是老樣子,但我發現了一些有趣的事實。但首先這裏是我的結構: 我使用的是JSF 2.2,Java EE,JPA和MySQL。該Web應用程序正在Glassfish 4.1服務器中運行。

的JSF-查看調用從以下視圖 - 控制器列表:

@javax.faces.view.ViewScoped 
@Named 
public class ControllerErfolgskontrolle extends ControllerAbstract { 

    @Inject 
    private SvEnGenerierteAufgabe svEnGenerierteAufgabe; 

    private List<EntityGenerierteAufgabe> generierteAufgabenBenutzer; 

    @PostConstruct 
    private void doInit() { 
    generierteAufgabenBenutzer = svEnGenerierteAufgabe.getByLimitedSorted(
      getControllerSession().getBenutzer()); 
    } 

    public List<EntityGenerierteAufgabe> getGenerierteAufgabenBenutzer() { 
    return generierteAufgabenBenutzer; 
    } 
} 

的視圖Contorller從EJB SvEnGenrierteAufgabe收到有關名單(generierteAufgabenBenutzer):

@javax.ejb.Stateless 
public class SvEnGenerierteAufgabe { 

    @PersistenceContext 
    EntityManager em; 

    public List<EntityGenerierteAufgabe> getByLimitedSorted(EntityBenutzer benutzer) { 

    String query = "SELECT ga, " 
      + " CASE WHEN (ga.changeTime > ga.createTime) THEN ga.changeTime " 
      + "  ELSE ga.createTime END AS myorder " 
      + "FROM EntityGenerierteAufgabe ga " 
      + "WHERE ga.benutzer=:benutzer " 
      + "ORDER BY myorder DESC"; 
    List<EntityGenerierteAufgabe> aufgaben = new ArrayList<>(); 
    List<Object[]> results = null; 

    results = em.createQuery(query) 
      .setParameter("benutzer", benutzer) 
      .setMaxResults(6) 
      .getResultList(); 

    for (Object[] result : results) { 
     aufgaben.add((EntityGenerierteAufgabe) result[0]); 
    } 

    return aufgaben; 
    } 
} 

在大多數案件一切正常,如預期。但是,當我在至少兩個不同的線程的EntityManager做壓力測試通過JMeter的與一時無法創建一個正確的方式MySQL的查詢和它導致這樣的MySQLSyntaxErrorException:

Internal Exception: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'FROM ENTITYGENERIERTEAUFGABE WHERE (BENUTZER_ID = 2) ORDER BY CASE WHEN (CHANGE' at line 1 
Error Code: 1064 
Call: SELECT ID AS a1, BEARBEITUNGSZEIT AS a2, CHANGETIME AS a3, CREATETIME AS a4, FORTSCHRITT AS a5, ISTBEENDET AS a6, AUFGABENTYP_ID AS a7, LEVEL_ID AS a8, BENUTZER_ID AS a9, CASE WHEN (CHANGETIME > CREATETIME) THEN CHANGETIME WHEN CREATETIME THEN FROM ENTITYGENERIERTEAUFGABE WHERE (BENUTZER_ID = ?) ORDER BY CASE WHEN (CHANGETIME > CREATETIME) THEN CHANGETIME WHEN CREATETIME THEN DESC LIMIT ?, ? 
    bind => [3 parameters bound] 
Query: ReportQuery(referenceClass=EntityGenerierteAufgabe sql="SELECT ID AS a1, BEARBEITUNGSZEIT AS a2, CHANGETIME AS a3, CREATETIME AS a4, FORTSCHRITT AS a5, ISTBEENDET AS a6, AUFGABENTYP_ID AS a7, LEVEL_ID AS a8, BENUTZER_ID AS a9, CASE WHEN (CHANGETIME > CREATETIME) THEN CHANGETIME WHEN CREATETIME THEN FROM ENTITYGENERIERTEAUFGABE WHERE (BENUTZER_ID = ?) ORDER BY CASE WHEN (CHANGETIME > CREATETIME) THEN CHANGETIME WHEN CREATETIME THEN DESC LIMIT ?, ?") 
    at ... 

實際的語法錯誤是WHEN CREATETIME THEN根本不屬於那裏的部分。

我推測一些無狀態實例與不同EntityManager實例之間可能存在競爭條件,這會導致EntityManager有時會生成錯誤的SQL。

這只是一個想法,但是當我用@ javax.ejb.Singleton替換@ javax.ejb.Stateless時,一切正常。所以我的問題是:我做錯了什麼?據我所知,有一個無狀態實例池,每個客戶端(在這種情況下,ViewController)爲方法調用獲取自己的實例,然後實例返回到池中。

+0

嘗試使用StringBuffer(線程安全)而不是字符串並檢查 – HJK 2015-03-02 09:18:37

+0

首先感謝但StringBuffer沒有任何改變。問題仍然存在。 – 2015-03-02 09:50:45

+0

每個EJB一次只處理一個請求。對於第二個請求,它將使用另一個無狀態bean。種族情況不會如此。在Singleton中,容器無論如何都會鎖定EJB。在某種意義上運行2線程,你怎麼做? – HJK 2015-03-02 12:33:00

回答

0

我做了一些測試: 我用休眠作爲JPA提供者,而不是的EclipseLink和結果是錯誤不再出現。

那麼EclipseLink實現中可能存在一個bug?

+0

現在我已經在相同的組合中測試了EclipseLink 2.6.0.RC1,並且出現相同的錯誤。所以2.6.0版本不能解決問題。 – 2015-03-09 13:36:48