I have a collection of states, that I want to cache for the life of the application, preferably after it is called for the first time. I'm using EclipseLink as my persistence provider. In my EJB3 entity I have the following code:
#Cache
#NamedQueries({
#NamedQuery(
name = "State.findAll",
query = "SELECT s FROM State s",
hints = {
#QueryHint(name=QueryHints.CACHE_USAGE, value=CacheUsage.CheckCacheThenDatabase),
#QueryHint(name=QueryHints.READ_ONLY, value=HintValues.TRUE)
}
)
})
This doesn't seem to do anything though, if I monitor the SQL queries going to MySQL it still does a select each time my Session Bean uses this NamedQuery.
What is the correct way to configure this query so that it is only ever read once from the database, preferably across all sessions?
Edit: I am calling the query like this:
Query query = em.createNamedQuery("State.findAll");
List<State> states = query.getResultList();
The solutions posted here not worked for me. But i've made it work with:
#Cache
#NamedQueries({#NamedQuery(
name = "State.findAll",
query = "SELECT s FROM State s",
hints = {
#QueryHint(name = QueryHints.QUERY_RESULTS_CACHE, value = HintValues.TRUE)
}
)})
Just a guess here, but you might try
query.cacheQueryResults();
after you create it but before you getResultList.
-- MarkusQ
I got EclipseLink 1.0.1 cache to work by adding just the query hint:
Query query = em.createNamedQuery("Person.find");
query.setParameter("NAME", name);
query.setHint("eclipselink.cache-usage", "CheckCacheThenDatabase");
return (Person)query.getSingleResult();
I didn't change the entity at all, and haven't yet tried to configure cache using annotations.
Related
I found similar questions about this error but I can't make it work
I'm working on a java 8, spring 2.6.4 and a MySQL database
I'm trying to do a DELETE native query using JPA and I'm getting this error:
org.springframework.orm.jpa.JpaSystemException: could not extract ResultSet; nested exception is org.hibernate.exception.GenericJDBCException: could not extract ResultSet
this is my query:
#Query(value = "DELETE FROM reservation a WHERE a.slotid =:slotid", nativeQuery = true)
void deleteWhereSlotid(Integer slotid);
and this is the service:
repo.deleteWhereSlotid(reservationSlot.getId());
I've also tried:
#Query(value = "DELETE FROM reservation a WHERE a.slotid =:slotid", nativeQuery = true)
Object deleteWhereSlotid(Integer slotid);
//service
Object object= userCourseResRepo.deleteWhereSlotid(reservationSlot.getId());
but it failed
Usually I delete rows with deleteById(id) which comes with spring
The query works though, I tried it on phpMyadmin console and it worked
Someone know what I can try?
The way you have it set up, Spring Data assume you want to perform a query (typically a SELECT). For DELETE and similar statements that don't return a ResultSet you need to provide an additional #Modifying annotation.
#Modifying
#Query(value = "DELETE FROM reservation a WHERE a.slotid =:slotid", nativeQuery = true)
void deleteWhereSlotid(Integer slotid);
I know is not the best solution, but you can try to use a query SELECT to find your reservation object and then do this repo.deleteById(reservation.getId())
This should allow you to go ahead while you find a better way to do it
If you are using it that way, I believe the query should be:
DELETE a FROM reservation a WHERE a.slotid =:slotid
I am not particularly sure about the code, however, with Mysql, the case seems to be so when giving an alias to the table.
You need to add #Param
#Query(value = "DELETE FROM reservation a WHERE a.slotid =:slotid", nativeQuery = true)
Object deleteWhereSlotid(#Param("slotid")Integer slotid);
As mentioned above, we use the #Param annotation in the method declaration to match parameters defined by name in JPQL/Native query with parameters from the method declaration.
I am trying to run some native SQL queries in my Spring application. I donĀ“t have an entity or JpaRepository class. I know it's strange, but this is a microservice just to collect two count queries and send it to Kafka.
Well trust me, all I need is these two integers from the queries. I run these code and always returns 0. I can see in the logs that Hikari is connecting to the database, so I don't know what to do. Searched a lot, but all answers involved the #Query solution, which does not work for me.
#Repository
#AllArgsConstructor
public class ReportRepository {
private final EntityManager em;
public int numberOfAccounts() {
String sql = "SELECT count(*) FROM account";
Query query = em.createNativeQuery(sql);
System.out.println(query.getFirstResult());
return query.getFirstResult();
}
public int numberOfSubscriptions() {
String sql = "SELECT count(*) FROM subscriptions";
Query query = em.createNativeQuery(sql);
System.out.println(query.getFirstResult());
return query.getFirstResult();
}
}
If you have EntityManager, and from what you are saying it can connect to DB, try this way:
public int numberOfSubscriptions() {
// >> "subscriptions" has to be the exact name of your table
// if does not work, consider trying SUBSCRIPTIONS or Subscriptions
String sql = "SELECT count(*) FROM subscriptions";
Query query = em.createNativeQuery(sql);
// getSingleResult() instead :)
return ((Number) query.getSingleResult()).intValue();
}
There is this (a bit old) JavaDoc for Query.getFirstResult() :
The position of the first result the query object was set to retrieve. Returns 0 if setFirstResult was not applied to the query object
So, I'd say that is not the right method for your case.
Happy Hacking :)
You should be using JDBC instead of an Entity Manager. Under the JPA uses JDBC but it requires defined entites to work. JDBC allows you to manage the connection and run the raw SQL queries.
Here's a link for how to do it in Spring:
https://spring.io/guides/gs/relational-data-access/#_store_and_retrieve_data
I have these annotations:
public class Account {
#Persistent(defaultFetchGroup = "true", dependent = "false")
#Column(name = "user_owner_id")
private User user;
}
public class User {
#Persistent(defaultFetchGroup = "true", mappedBy = "user")
#Element(column = "user_owner_id", dependent = "true")
private Set<Account> accounts;
}
When initiating the Account class, the query on the database use a SELECT * FROM accounts where exists (SELECT id from users where id=23)
I am trying to give datanucleus an annotation that tells it to run on the database SELECT a.* FROM accounts a JOIN users u on a.id = u.user_id where u.id = 23 as this is more optimal.
So which annotation should I use to make data nucleus change its query formation?
--- addition ----
This is a stripped down version of how we're retrieving the data:
PersistenceManager persistenceManager = persistenceManagerFactory.getPersistenceManager();
persistenceManager.getFetchPlan().setMaxFetchDepth(FetchPlan.FETCH_SIZE_GREEDY);
Query query = persistenceManager.newQuery("javax.jdo.query.JDOQL", null);
query.setClass(User.class);
query.setFilter("this.uuid==p1");
query.declareParameters("java.lang.String p1");
final List<E> entities = (List<E>) query.execute(uuid);
E entity = entities.iterator().next();
return persistenceManager.detachCopy(entity);
You are performing a Query just to get one object, which is very inefficient. Instead you could easily do
User u = pm.getObjectById(User.class, 1);
and this would likely issues 2 SQLs in total; 1 to get the basic User object, and 1 to get the Accounts connected to that User. There would be no EXISTS clause.
With regards to what you are actually doing. A Query is issued. A Query is general and in most use-cases will return multiple objects. The filter clause of the query can be complex. The Query is converted into an SQL to get the basic User fields. It can't get the related objects in a single call, so your log will likely say something about BULK FETCH (or something similar, whatever DataNucleus calls it). This will have an EXISTS clause with the EXISTS subquery restricting the second query to the objects the Query applies to). They do this to avoid the N+1 problem. Using EXISTS is, in general, the most appropriate for the general case of a query. In your specific situation it would have been nice to have an INNER JOIN, but I don't think that is supported as a BULK FETCH option currently. Their code is open source and I know they have asked people to contribute things in the past where they want alternative handling ... so you could contribute something if you want to use a query in this precise situation.
I am using hibernate OGM to talk to my MongoDB instance. I had to get a list of all the products with category "abc". I am using the native query approach to achieve this as following:
String stringQuery = "db.Message.find({'CATEGORY':'" + category + "})";
Query query = entityManagerProvider.get().createNativeQuery(stringQuery, Product.class);
productList = query.getResultList();
I am not sure if it is the right approach to do this as I see a too much hard coding (look at the collection name). Can I use the .find() method to achieve the same thing?
We are using vertx server with gradle as building tool.
Do you mean the EntityManager.find()? You can use it if you filter using the primary key. It doesn't seem the case in your example.
What you can do is write a JP-QL query:
productList = entityManagerProvider.get().createQuery( "SELECT p FROM Product p WHERE p.category=:category", Product.class ).setParameter("category", category).getResultList();
I'm assuming that you have an entity Product with attribute category.
I have a named query as below;
#NamedQuery(name = "MyEntityClass.findSomething", query = "SELECT item FROM MyTable mytbl")
Now I want to append dynamic sort clause to this query (based on UI parameters)
Can I get an example using JPQL for doing the same (like how to set a dynamic ORDER BY in the Entity class)
I have already tried using CriteriaQuery, but was looking for a JPQL implementation now.
NamedQueries are by definition NOT dynamic, it is not correct to change them programmatically.
So the way to go is to create a JPQL query (but not a named query) like this:
TypedQuery<MyEntity> query = em.createdQuery("SELECT item FROM MyEntity item ORDER BY "+sortingCol, MyEntity.class);
On the other hand, if you REALLY want to use the named query, you could do that the following way:
#NamedQuery(name = "MyEntityClass.findSomething", query = MyEntity.NAMED_QUERY)
#Entity
public class MyEntity {
public static final NAMED_QUERY= "SELECT item FROM MyTable mytbl";
//+your persistent fields/properties...
}
//and later in your code
TypedQuery<MyEntity> query = entityManager.createQuery(MyEntity.NAMED_QUERY + " ORDER BY " + sortingCol, MyEntity.class);
Complementing for JPA 2.1
As of JPA 2.1 it is possible to define named queries programmatically.
This can be achieved using entityManagerFactory.addNamedQuery(String name, Query).
Example:
Query q = this.em.createQuery("SELECT a FROM Book b JOIN b.authors a WHERE b.title LIKE :title GROUP BY a");
this.em.getEntityManagerFactory().addNamedQuery("selectAuthorOfBook", q);
// then use like any namedQuery
Reference here
This can be useful, for instance, if you have the orderby field defined as a application parameter. So, when the application starts up or on the first run of the query, you could define the NamedQuery with the defined OrderBy field.
On the other side, if your OrderBy can be changed anytime (or changes a lot), then you need dynamic queries instead of NamedQuery (static). It would not worth to (re)create a NamedQuery every time (by performance).
#NamedQuery
Persistence Provider converts the named queries from JPQL to SQL at deployment time.
Until now, there is no feature to create/update the query with #NamedQuery annotation at runtime.
On the other hand, you can use Reflection API, to change the annotation value at runtime. I think It is not solution, also it is not you wanted .
em.createQuery()
Persistence Provider converts the dynamic queries from JPQL to SQL every time it is invoked.
The main advantage of using dynamic queries is that the query can be created based on the user inputs.