我指我的最後一個問題,這個話題,你可以在這裏找到無狀態的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)爲方法調用獲取自己的實例,然後實例返回到池中。
嘗試使用StringBuffer(線程安全)而不是字符串並檢查 – HJK 2015-03-02 09:18:37
首先感謝但StringBuffer沒有任何改變。問題仍然存在。 – 2015-03-02 09:50:45
每個EJB一次只處理一個請求。對於第二個請求,它將使用另一個無狀態bean。種族情況不會如此。在Singleton中,容器無論如何都會鎖定EJB。在某種意義上運行2線程,你怎麼做? – HJK 2015-03-02 12:33:00