I use Hibernate and Oracle SQL in my project. When I call createNativeQuery method of the entity Manager, the entity manager doesn't answer any call (even from different browsers) before the method returns. The query takes long time but it is called in new a thread. Why is the entity manager blocked?
NOTE: When I call JPQL query, the problem disappears.
#PersistenceContext
private EntityManager entityManager;
//blocking other transactions, cannot make any read from the same entityManager until this method is completed.
#Transactional(readOnly=true)
public void testMethod1(String query) {
Query q = entityManager.createNativeQuery(query);
// CANNOT SET LOCKMODE because it is not JPQL : q.setLockMode(LockModeType.NONE) //throws exception
List<Object[]> result = q.getResultList();
}
#Transactional(readOnly=true)
public void testMethod2(String jpql) {
Query q = entityManager.createQuery(jpql);
List<Object> result = q.getResultList();
}
I was able to reproduce your problem using other databases (SQL Anywhere in my case).
After this I took a look at Hibernate JavaDocs and it says that your problem is the default behavior, because JPA requires that setLockMode should be applied only on non-native queries.
To have a workaround to this, Hibernate makes use of the QueryHints of the query:
NATIVE_LOCKMODE:
Available to apply lock mode to a native SQL query since JPA requires that Query.setLockMode(javax.persistence.LockModeType) throw an IllegalStateException if called for a native query.
To use QueryHints you should do something like this:
#Transactional(readOnly=true)
public void testMethod1(String query) {
Query q = entityManager.createNativeQuery(query);
q.setHint(QueryHints.NATIVE_LOCKMODE, LockModeType.NONE);
List<Object[]> result = q.getResultList();
}
I have also identified that if you use the #TransactionAttribute above your method the problem might not occur, example:
#TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public void testMethod1(String query) {
Query q = entityManager.createNativeQuery(query);
q.setHint(QueryHints.NATIVE_LOCKMODE, LockModeType.NONE);
List<Object[]> result = q.getResultList();
}
Please, try the solutions given above and let us know if the problem was solved or not, good luck!
Related
I am locking one row from a table using PESSIMISTIC_WRITE in MySQL .
However when I execute 'select' statement using MySQL Workbench that particular row is still visible.
Is there any way not to show-up this row when I use 'select' statement. Although I am not able to update that locked row, which means PESSIMISTIC_WRITE lock is working correctly.
Service Layer
#Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = {Exception.class})
public List<Employee> getEmployeeList()
{
return employeeDAO.getEmploeeList();
}
Dao Layer
#Override
public List<Employee> getEmploeeList() {
List<Employee> employeeList = null;
this.session = this.sessionFactory.getCurrentSession();
String myQry = "from Employee";
employeeList = session.createQuery(myQry, Employee.class)
.setMaxResults(1)
.setLockMode(LockModeType.PESSIMISTIC_WRITE)
.getResultList();
Employee e = employeeList.get(0);
return employeeList;
}
The entire code is available at https://github.com/vishy-wisy/Java/tree/main/LockingDemo
Thanks in advance for your help!
I have an procedure in oracle database which takes two parameters:
procedure some_procedure(int x, int y)
My project is using spring boot + hibernate. So, the question is how I can execute this stored procedure using batching (for example 100) from java code?
I've found some examples with usage of #Procedure annotation and also with StoredProcedureQuery - but those were only for simple not batching call.
And also could someone explain when I should use #Procedure annotation instead of StoredProcedureQuery?
When calling stored procedure, you get OUT parameters and can,t change it through calling. If stored procedure return ref_cursor, and you want to limit records, change stored procedure.
With StoredProcedureQuery you will write more code and manually manage calling process (get entityManager, open transaction, make a call, close transaction ...). With JPA repository you describe procedure by annotations and go. But both approaches work.
UPD:
Oh, little misunderstanding. You can call procedure several times in one transaction with StoredProcedureQuery, is this what you want? Code looks like this:
public class ProcedureCall {
#Autowired
private EntityManagerFactory entityManagerFactory;
public void executeProcedureWithoutResult(Map<String, ?> parameters, String procedureName) {
EntityManager em = entityManagerFactory.createEntityManager();
StoredProcedureQuery procedureQuery1 = em.createNamedStoredProcedureQuery(procedureName);
StoredProcedureQuery procedureQuery2 = em.createNamedStoredProcedureQuery(procedureName);
fillProcedureParameters(procedureQuery1, parameters);
fillProcedureParameters(procedureQuery2, parameters);
try {
em.getTransaction().begin();
procedureQuery1.execute();
procedureQuery2.execute();
em.getTransaction().commit();
} catch (Exception e) {
rollbackTransaction(e, em.getTransaction());
} finally {
if (em.isOpen()) {
em.close();
}
}
}
private void fillProcedureParameters(StoredProcedureQuery sp, Map<String, ?> parameters) {
if (parameters.size() > 0) {
for (HashMap.Entry<String, ?> rec : parameters.entrySet()) {
sp.setParameter(rec.getKey(), rec.getValue());
}
}
}
Maybe it even works, if you execute one procedureQuery twice, but I didn't try.
I am trying to update the existing rows in database table using JPA #Query Annotation. I want to perform Soft delete by updating the Deleted_Flag to YES from NO.
Here is my Code snippet:
#Modifying
#Query("UPDATE TBL_NAME SET DELETE_FLAG = 'YES' WHERE DELETE_FLAG = 'NO'
AND FILE_NM = :FILE_NM")
public void softDelete(#Param("FILE_NM") String fileName)
{
}
I am not getting any error, but data is not being updated in database.
Actual result must be like all the existing rows must be updated with DELETE_FLAG to YES.
Make sure you invoke the repository method with an active transaction.
Actually, in my last project I use the following idiom for updating a flag :
Entity is annotated with Hibernetish:
#Entity
#Table(name="myTable")
#Where(clause = "is_deleted = 0")
#Cacheable
public class MyTable {}
Actual update comes with a trivial find method:
#Transactional
public void deleteById(#NonNull final Long themeId) {
themeRepository.findById(themeId).orElseThrow(() -> new EntityNotFoundException(THEME_NOT_FOUND + themeId))
.setDeleted(true);
}
I try to use handle query for updating table in the SQL database.
Code:
#Autowired
private ProducerRepository producerRepository;
public void update(Producer producer){
String name = producer.getProducerName();
long id = producer.getId();
// producerRepository.save(producer); //this method works well.
producerRepository.update(name, id); //handle attempt - throws exeption in this string
}
ProducerRepository:
#Repository
public interface ProducerRepository extends JpaRepository<Producer, Long>{
#Query(nativeQuery = true, value = "UPDATE producer SET producer_name = :pName WHERE id = :id")
Producer update(
#Param("pName") String pName,
#Param("id") long id
);
}
All parameters of the producer entity are correct and producerRepository.save(producer) works well.
(also I out in console name and id fields - all right)
So, I can save producer in the database, but, when I try to use update() method I get the error.
Can not issue data manipulation statements with executeQuery()
PS
sql query in the console also works well
(UPDATE producer SET producer_name = 'some name' WHERE id = ....)
It should be noted that other SQL native queries in repository work correctly. So the spring/hibernate/jdbc settings are correct.
Use annotation #Modifying.
This will trigger the query annotated to the method as updating query
instead of a selecting one.
From 2.2.6 Modifying queries https://docs.spring.io/spring-data/jpa/docs/1.3.4.RELEASE/reference/html/jpa.repositories.html
In case above solution not work use this
#Modifying
#Transactional
#Query(value ="delete from admindata where user_name = :userName AND group_name = :groupName",nativeQuery = true)
public void deleteadminUser(#Param("userName") String userName,#Param("groupName") String groupName);
#Query(nativeQuery = true, value = "UPDATE producer SET producer_name = :pName WHERE id = :id")
Producer update(
#Param("pName") String pName,
#Param("id") long id
);
your update method is returning Producer Object, the return should be either int or void, since you are returning Producer entity, Spring JPA is thinking that it has to fetch the object instead of updating it, that is the reason it is executing executeQuery, instead of executeUpdate and also you need to #Modifying annotation.
I love the type safety CriteriaQuery brings ing JPA 2.0 but it also brings a bit of boiler-plate code. For example, let say I have an entity called NamedEntity, which simply has an id and a String field called "name" (assume it has the unique constraint set to true). Here's what the NamedEntityManager might look like:
public class NamedEntityManager
{
//inject using your framework
EntityManager entityManager;
//retrieve all existing entities of type NamedEntity from DB
public Iterable<NamedEntity> queryAll()
{
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<NamedEntity> query = builder.createQuery(NamedEntity.class);
return entityManager.createQuery(query).getResultList();
}
//retrieve a single entity of type NamedEntity from DB using specified name
public NamedEntity queryByName(String name)
{
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<NamedEntity> query = builder.createQuery(NamedEntity.class);
Root<NamedEntity> root = query.from(NamedEntity.class);
query = query.where(root.<NamedEntity>get("name").in(name));
//skipped the try/catch block for the sake of brevity
return entityManager.createQuery(query).getSingleResult();
}
}
Is there a way to condense the code in order to avoid copying/pasting the same lines of code into each query method? Perhaps somehow reuse the CriteriaQuery object?
I was looking for something like that, you could take a look at Querydsl (LGPL licensed) which can have JPA as backend.
Im still reading into it, but from their examples, it looks pretty clean.
HQLQuery q = new HibernateQuery(session);
QCat cat = new QCat("cat"); // query type
List<Cat> cats = q.from(cat).where(cat.name.between("A", "B")).list(cat);
In JPA 2.1, it will most probably be possible to mix JPQL and Criterias. With such an approach you could define a base query with JPQL and then use the Criteria API to dynamically add small parts.
I figure the API will be less verbose then, since you only need to use small parts of it.
Then Use JPA-2.0 MetaData model.
http://docs.jboss.org/hibernate/jpamodelgen/1.0/reference/en-US/html_single/
It seems there's no way to reduce the amount of code. I guess something had to be sacrificed to gain type safety.
Way outdated, this post, but I want to add what I recently built for simple queries
public static class Jpa2Whatsoever {
private final EntityManager em;
public class Jpa2WhatsoeverProgress<T> {
private CriteriaQuery<T> cq;
private List<Predicate> predicates = new ArrayList<>();
private Root<T> root;
public Jpa2WhatsoeverProgress(Class<T> type) {
this.cq = em.getCriteriaBuilder().createQuery(type);
this.root = cq.from(type);
}
public Jpa2WhatsoeverProgress<T> where(String attributeName, Object value) {
Predicate equal = em.getCriteriaBuilder().equal(root.get(attributeName), value);
predicates.add(equal);
return this;
}
public List<T> getResultList() {
Predicate[] predicatesArray = new Predicate[predicates.size()];
TypedQuery<T> typedQuery = em.createQuery(cq.select(root).where(predicates.toArray(predicatesArray)));
List<T> resultList = typedQuery.getResultList();
return Collections.unmodifiableList(resultList);
}
}
public Jpa2Whatsoever(EntityManager entityManager) {
this.em = entityManager;
}
public <T> Jpa2WhatsoeverProgress<T> select(Class<T> type) {
return new Jpa2WhatsoeverProgress<T>(type);
}
}
You can use it like this
List<MyEntity> matchingEntities = new Jpa2Whatsoever(entityManager).select(MyEntity.class).where("id", id).where("due", new Date()).getResultList();
In the end I stopped this. Mainly because I saw that I had only two queries and I would have to extend the DSL to get the required query characteristics into it, such as
greater than, less than
Metamodel support
QueryBuilder.currentDate() and alike.
Further, I find it ugly to always call where while it actually corresponds to a more SQLly and. Anyway, if someone is interested in a very simple query API, it is still worth a try.
BTW: Forget about the names, this was a prototype, nothing more.