我正在使用Java EE上下文中的带有MySQL数据库和JPA的JSF Web应用程序。

我正在使用以下JPQL从数据库中获取一些数据。 EntityGenerierteAufgabe具有字段createTime和changeTime。写入数据库条目时设置CreateTime。在这种情况下,changeTime为NULL。数据库条目更新时,还将设置changeTime。现在,我想从该表中选择并按changeTime(如果已设置)对条目进行排序,否则按createTime进行排序。而且我想限制结果的数量。

String query = "SELECT ga FROM EntityGenerierteAufgabe ga "
        + "WHERE ga.benutzer=:benutzer "
        + "ORDER BY CASE WHEN (ga.changeTime > ga.createTime) THEN ga.changeTime ELSE ga.createTime END DESC";
aufgaben = em.createQuery(query)
        .setParameter("benutzer", benutzer)
        .setMaxResults(6)
        .getResultList();


此JPQL对于一个用户(BrowserSession)正常工作。如果我使用jMeter做一些压力测试,并且使用多个线程(多个BrowserSession)并调用JSF-Page(调用此JPQL),则多次会导致SOMETIMES出现以下错误:

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 FROM ENTITYGENERIERTEAUFGABE WHERE (BENUTZER_ID = ?) ORDER BY CASE  WHEN (CHANGETIME > CREATETIME) THEN CHANGETIME WHEN CREATETIME THEN  DESC LIMIT ?, ?
bind => [3 parameters bound]
Query: ReadAllQuery(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 FROM ENTITYGENERIERTEAUFGABE WHERE (BENUTZER_ID = ?) ORDER BY CASE  WHEN (CHANGETIME > CREATETIME) THEN CHANGETIME WHEN CREATETIME THEN  DESC LIMIT ?, ?")
at org.eclipse.persistence.exceptions.DatabaseException.sqlException(DatabaseException.java:340)
at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.basicExecuteCall(DatabaseAccessor.java:682)
at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeCall(DatabaseAccessor.java:558)
at org.eclipse.persistence.internal.sessions.AbstractSession.basicExecuteCall(AbstractSession.java:2002)
at org.eclipse.persistence.sessions.server.ServerSession.executeCall(ServerSession.java:570)
at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.executeCall(DatasourceCallQueryMechanism.java:242)
at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.executeCall(DatasourceCallQueryMechanism.java:228)
at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.executeSelectCall(DatasourceCallQueryMechanism.java:299)
at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.selectAllRows(DatasourceCallQueryMechanism.java:694)
at org.eclipse.persistence.internal.queries.ExpressionQueryMechanism.selectAllRowsFromTable(ExpressionQueryMechanism.java:2738)
at org.eclipse.persistence.internal.querie
Information:   s.ExpressionQueryMechanism.selectAllRows(ExpressionQueryMechanism.java:2691)
at org.eclipse.persistence.queries.ReadAllQuery.executeObjectLevelReadQuery(ReadAllQuery.java:495)
at org.eclipse.persistence.queries.ObjectLevelReadQuery.executeDatabaseQuery(ObjectLevelReadQuery.java:1168)
at org.eclipse.persistence.queries.DatabaseQuery.execute(DatabaseQuery.java:899)
at org.eclipse.persistence.queries.ObjectLevelReadQuery.execute(ObjectLevelReadQuery.java:1127)
at org.eclipse.persistence.queries.ReadAllQuery.execute(ReadAllQuery.java:403)
at org.eclipse.persistence.queries.ObjectLevelReadQuery.executeInUnitOfWork(ObjectLevelReadQuery.java:1215)
at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.internalExecuteQuery(UnitOfWorkImpl.java:2896)
at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1804)
at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1786)
at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1751)
at org.eclipse.persistence.internal.jpa.QueryImpl.executeReadQuery(QueryImpl.java:258)
... 124 more
Caused by: 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 'DESC LIMIT 0, 6' at line 1
at sun.reflect.GeneratedConstructorAccessor204.newInstance(Unknown Source)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:526)
at com.mysql.jdbc.Util.handleNewInstance(Util.java:377)
at com.mysql.jdbc.Util.getInstance(Util.java:360)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:978)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3887)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3823)
at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2435)
at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2582)
at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2530)
at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:1907)
at com.mysql.jdbc.PreparedStatement.executeQuery(PreparedStatement.java:2030)
at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeSelect(DatabaseAccessor.java:1007)
at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.basicExecuteCall(DatabaseAccessor.java:642)
... 144 more


如您所见,SQL查询的构建不正确。内部错误:ORDER BY CASE何时(CHANGETIME> CREATETIME)则CHANGETIME何时CREATETIME THEN DESC LIMIT?

这很奇怪,因为它有时会工作,但有时却无法工作。

一些额外的信息:
我正在使用JSF 2.2。实例化相关的ViewController时,将调用带有JPQL的方法:

@javax.faces.view.ViewScoped
@Named
public class ControllerErfolgskontrolle implements Serializable {

  @Inject
  private SvEnGenerierteAufgabe svEnGenerierteAufgabe;

  private List<EntityGenerierteAufgabe> generierteAufgabenBenutzer;

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

  ...
}


以及相关的SvEnGenerierteAufgabe-Class和创建JPQL的方法:

@Stateless
public class SvEnGenerierteAufgabe {

  @PersistenceContext
  EntityManager em;

  public List<EntityGenerierteAufgabe> getByLimitedSorted(EntityBenutzer benutzer) {

    List<EntityGenerierteAufgabe> aufgaben = new ArrayList<>();
    String query = "SELECT ga FROM EntityGenerierteAufgabe ga "
            + "WHERE ga.benutzer=:benutzer "
            + "ORDER BY CASE WHEN (ga.changeTime > ga.createTime) THEN ga.changeTime ELSE ga.createTime END DESC";
    aufgaben = em.createQuery(query)
            .setParameter("benutzer", benutzer)
            .setMaxResults(6)
            .getResultList();

    return aufgaben;
  }
}


我正在使用以下版本:
-Glassfish 4.1(内部版本13)
-Eclipse Persistence Services-2.5.2.v20140319-9ad6abd
-MySQL版本:5.5.27
-mysql-connector-java-5.1.34

当我未设置限制(setMaxResults(...))或删除订单时,我可以使用来自不同jMeter-Test-Threads的多个调用来工作。两者在某些情况下(如前所述)一起无法使用。

更新1:

我之前也测试过Alex JPQL。我现在又做了一次。结果将生成以下SQL:

SELECT ID AS a1, ..., CHANGETIME AS a3, CREATETIME AS a4, ...,
CASE  WHEN (CHANGETIME > CREATETIME) THEN CHANGETIME ELSE CREATETIME END
FROM ENTITYGENERIERTEAUFGABE WHERE (BENUTZER_ID = ?) ORDER BY CASE
WHEN (CHANGETIME > CREATETIME) THEN CHANGETIME ELSE CREATETIME END DESC LIMIT ?, ?


这也很好。但是在进行渗透测试时我遇到了同样的问题。有时,超过1600个请求(两个并行线程,每个发送800个请求)工作正常,某些问题我遇到了这个问题:

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


和生成的SQL(在第一个THEN CHANGETIME之后是WHEN CREATETIME):

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 ?, ?


我认为某个地方存在同步问题或事务问题,有时会导致错误的SQL,这时会发送来自不同客户端的许多请求。但是我没有发现问题。
有人知道吗?我会测试它更新此问题。

最佳答案

 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";

10-07 17:55