Можем ли мы назначить пользовательские подсказки запросов для JPA NamedQueries
Мы обязаны добавлять номера запросов к каждому запросу, которое выполняет наше приложение.
Пример: ВЫБРАТЬ * ОТ... ГДЕ... QUERYNO 123456;
OpenJPA поддерживает подсказки запросов, но только для конкретных подсказок в конкретных реализациях.
...
Query q = em.createQuery("select m from Magazine m where ... ");
q.setHint("openjpa.hint.OptimizeResultCount", new Integer(2));
q.setHint("openjpa.FetchPlan.ReadLockMode","WRITE");
List r = q.getResultList();
...
Но в соответствии со спецификацией JPA и openjpa "Недопустимые подсказки или подсказки, которые не могут быть обработаны конкретной базой данных, игнорируются. В противном случае неправильные подсказки приведут к возникновению исключения ArgumentException". Так что указание "QUERYNO" в качестве подсказки, похоже, никак не повлияет.
Как мне создать пользовательскую подсказку для запроса во время выполнения?
... Query q = em.createQuery ("выберите m из журнала m, где..."); q.setHint ("com.me.CustomQueryNoHint", new Integer (2234)); List r = q.getResultList ();...
3 ответа
Не полный ответ, а просто указатель...
QueryCounter
public class QueryCounter {
private static long COUNTER = 0;
private static long next() {
return ++COUNTER;
}
private static String getHintValue() {
return "/*Query No. " + next() + " */";
}
public static void setQueryCount(Query query) {
/* EclipseLink */
//query.setHint(QueryHints.HINT, getHintValue());
query.setHint("eclipselink.sql.hint", getHintValue());
/* OpenJPA + Oracle */
//query.setHint("openjpa.hint.OracleSelectHint", getQueryHint());
/* OpenJPA + MySQL */
//query.setHint("openjpa.hint.MySQLSelectHin", getQueryHint());
}
}
использование
Organization sun = new Organization("Sun");
em.persist(sun);
tx.commit();
Assert.assertNotNull(sun.getEntityId());
Query query = em.createQuery("SELECT org.entityId FROM Organization org WHERE org.entityId = " + sun.getEntityId());
QueryCounter.setQueryCount(query);
query.getResultList();
/*ServerSession does NOT log ReadObjectQuery??*/
query = em.createQuery("SELECT org FROM Organization org WHERE org.entityId = " + sun.getEntityId());
QueryCounter.setQueryCount(query);
query.getResultList();
query = em.createQuery("SELECT org.entityId FROM Organization org WHERE org.entityId = " + sun.getEntityId());
QueryCounter.setQueryCount(query);
query.getResultList();
Приставка
[EL Finest]: 2010-11-20 19:06:16.45--UnitOfWork(717879615)--Thread(Thread[main,5,main])--Execute query ReportQuery(referenceClass=Organization sql="SELECT entity_id FROM organization_tt WHERE (entity_id = ?)")
[EL Fine]: 2010-11-20 19:06:16.475--ServerSession(699542937)--Connection(1949550475)--Thread(Thread[main,5,main])--SELECT /*Query No. 1 */ entity_id FROM organization_tt WHERE (entity_id = ?)
bind => [1]
[EL Finest]: 2010-11-20 19:06:23.372--UnitOfWork(717879615)--Thread(Thread[main,5,main])--Execute query ReadObjectQuery(referenceClass=Organization sql="SELECT entity_id, name FROM organization_tt WHERE (entity_id = ?)")
[EL Finest]: 2010-11-20 19:06:35.916--UnitOfWork(717879615)--Thread(Thread[main,5,main])--Execute query ReportQuery(referenceClass=Organization sql="SELECT entity_id FROM organization_tt WHERE (entity_id = ?)")
[EL Fine]: 2010-11-20 19:06:35.92--ServerSession(699542937)--Connection(1949550475)--Thread(Thread[main,5,main])--SELECT /*Query No. 3 */ entity_id FROM organization_tt WHERE (entity_id = ?)
bind => [1]
OpenJPA имеет похожую концепцию 1.8.7. Специфичные для базы данных советы. Посмотрите, могут ли эти конкретные советы решить вашу цель.
ОБНОВЛЕННЫЙ ОТВЕТ
@ Эдди, посмотри, может ли это тебе помочь...........
CustomLogFactory
public class MyLogFactory extends org.apache.openjpa.lib.log.LogFactoryImpl {
/* copied from LogFactoryImpl.NEWLINE */
private static final String NEWLINE = J2DoPrivHelper.getLineSeparator();
private boolean sqlLogger;
@Override
public Log getLog(String channel) {
if("openjpa.jdbc.SQL".equals(channel)) { // OR equalsIgnoreCase(channel) ???
sqlLogger = true;
}
return super.getLog(channel);
}
@Override
protected LogImpl newLogImpl() {
if(sqlLogger) {
sqlLogger = false; /* once an SQL Logger is created, we dont't need any more instances */
return new LogImpl() {
private long sqlCounter = 0;
@Override
protected String formatMessage(short level, String message, Throwable t) {
if(isSQLString(message)) {
StringBuffer formattedMessage = new StringBuffer(super.formatMessage(level, message, t));
StringBuffer queryNo = new StringBuffer();
queryNo.append(" [Query # ").append(++sqlCounter).append("]").append(NEWLINE);
formattedMessage.delete(formattedMessage.length() - NEWLINE.length(), formattedMessage.length());
formattedMessage.append(queryNo);
return formattedMessage.toString();
}
return super.formatMessage(level, message, t);
}
/* just a sample implementation; checks whether message contains the word "executing"
* more concrete implementation should check the message for SELECT, UPDATE, INSERT INTO, ALTER.... clauses */
private boolean isSQLString(String message) {
if(message.contains("executing")) {
return true;
}
return false;
}
};
}
return super.newLogImpl();
}
}
peristence.xml
<property name="openjpa.Log" value="org.opensource.logger.MyLogFactory(DefaultLevel=WARN, Runtime=INFO, Tool=INFO, SQL=TRACE)"/>
Тестовое задание
EntityManager em = Persistence.createEntityManagerFactory("default").createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
Person person = new Person();
person.setName("Bond-OO7");
person.setAge(22);
em.persist(person);
tx.commit();
em.close();
Приставка
............
2084 default TRACE [main] openjpa.jdbc.SQL - <t 346613126, conn 1551158018> executing prepstmnt 556472773 SELECT SEQUENCE_OWNER AS SEQUENCE_SCHEMA, SEQUENCE_NAME FROM ALL_SEQUENCES [Query # 1]
2136 default TRACE [main] openjpa.jdbc.SQL - <t 346613126, conn 1551158018> [52 ms] spent
2305 default TRACE [main] openjpa.jdbc.SQL - <t 346613126, conn 2026561073> executing prepstmnt 6637010 INSERT INTO Person (id, age, name) VALUES (?, ?, ?) [params=?, ?, ?] [Query # 2]
2306 default TRACE [main] openjpa.jdbc.SQL - <t 346613126, conn 2026561073> [1 ms] spent
............
Ссылка
указание "QUERYNO" в качестве подсказки, похоже, не оказывает никакого влияния.
Правильный. Согласно документу, который вы цитировали, "QUERYNO" является недопустимой подсказкой, поэтому он игнорируется. Документ несколько сбивает с толку, но я верю, что его можно интерпретировать, чтобы поддержать поведение, которое вы наблюдали.:-)
Как мне создать пользовательскую подсказку для запроса во время выполнения?
Это гораздо более высокая задача. Я не верю, что OpenJPA был разработан для того, чтобы разрешать написание пользовательских подсказок запросов.
Я еще немного подумал о вашей реальной проблеме желания добавить конкретную строку в КАЖДЫЙ SQL, и я не думаю, что это будет очень легко сделать в OpenJPA. Возможно, вы могли бы написать обертку для вашего драйвера JDBC и добавить в нее строку к каждому SQL?
Вместо того, чтобы использовать JPQL и пытаться навязать в запросе материал, относящийся к конкретному поставщику, вы рассматривали возможность написания собственного запроса, который сопоставлен с типом возвращаемого объекта?
em.createNativeQuery(YOUR_DB2_NATIVE_SQL_QUERY_STRING, Magazine.class)
Это будет больше работать для вас, так как ваш собственный запрос должен выбрать значения столбцов, которые соответствуют сопоставленным столбцам в классе сущности, но это должно работать. Когда вы используете собственный SQL, механизм запросов не должен анализировать и интерпретировать специфичный для поставщика SQL, поэтому ваше специфичное для DB2 предложение в конце должно быть передано в базовую базу данных во время выполнения.