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.
Related
I have implemented following code part:
public void computeAllBilling() {
orderRepository.getAll().parallel().forEach(ordreEntity -> {
Billing billing = computedBilling(orderEntity);
billingRepository.save(billing);
entityManager.detach(ordreEntity);
});
}
public interface BillingRepository extends JpaRepository<BillingEntity, String> {
#QueryHints(value = {
#QueryHint(name = org.hibernate.jpa.QueryHints.HINT_FETCH_SIZE, value = "1"),
#QueryHint(name = org.hibernate.jpa.QueryHints.HINT_CACHEABLE, value = "false"),
#QueryHint(name = org.hibernate.jpa.QueryHints.HINT_READONLY, value = "true")
})
#Query(value = "SELECT o.* FROM raw.ordre o", nativeQuery = true)
Stream<BillingEntity> getAll();
}
I need to stream my reading very quickly from one table, but in our business processing, we need to save the billing at the ending (after reader one order its billing must be saved)
But following this link: https://www.geekyhacker.com/2019/03/26/high-performance-data-fetching-using-spring-data-jpa-stream/
I need finally to save in another repository, not the reader repository.
Anyone know a mean to avoid
"org.springframework.dao.InvalidDataAccessApiUsageException: You're trying to execute a streaming query method without a surrounding transaction that keeps the connection open so that the Stream can actually be consumed. Make sure the code consuming the stream uses #Transactional or any other way of declaring a (read-only) transaction.
"
please ? Great thank, and best regards
Adrian
I am learning spring boot caching to apply this concept in our organization's project and I made a sample project called employe cache. I have four methods in my controller and service component insert, update, get, and getAll.For insert and get #Cacheable is working perfectly. Now I am calling getAllEmployee() first time then it is fetching data from the database. After that I am trying to update with #CachePut it updates the value in the database and again I am calling getAllEmployee() then it didn't return updated value from the cache. I also refer to the documentation for #CachePut. I also refer to some other documents like this and this but I didn't solve my problem. Also, When I am calling, no error is raised.
What I Tried is
These are my two APIs from EmplyeeController.java
#PostMapping(value = "/updateSalary")
private Boolean updateSalary(#RequestParam int salary, #RequestParam Integer id) {
return empService.updateSalary(salary, id);
}
#GetMapping(value = "/getAllEmployee")
private Object getAllEmployee() {
List<EmployeeMapping> empList = empService.getAllEmployee();
return !empList.isEmpty() ? empList : "Something went wrong";
}
These are my two methods from EmployeeService.java. I applied different keys to update the method but didn't work. My getAll() method has no parameter so I tried all the keys techniques for no parameter methods from here then also I didn't get any results.
#CachePut(key = "#root.method.name")
public Boolean updateSalary(int salary, int id) {
System.err.println("updateSalary method is calling in service");
if (empRepo.salary(salary, id) != 0) {
return true;
}
return false;
}
#Cacheable(key = "#root.method.name")
public List<EmployeeMapping> getAllEmployee() {
return empRepo.findAllEmployee();
}
These are my two methods from EmployeeRepository.java. I used #SqlResultSetMappings and #NamedNativeQueriesin EmployeeMetaModel.java with EmployeeMapping.java but there is no error in native query in EmployeeMetaModel.java because it's giving result from database.
#Transactional
#Modifying
#Query("update employee_cache e set e.salary = ?1 where e.id = ?2")
int salary(int salary, int id);
#Query(name = "EmployeeListQuery", nativeQuery = true)
List<EmployeeMapping> findAllEmployee();
Kindly help me to get rid of this I just need an updated value from the cache using getAllEmployee() after updateSalary() called.
There is an issue with how you've defined caching via annotations. Your #CachePut and #Cacheable don't use the same cache key. What you should actually have is something like this:
#CachePut(value = "employees", key = "T(org.springframework.cache.interceptor.SimpleKey).EMPTY")
public List<EmployeeMapping> updateSalary(int salary, int id) {
// update salary and return the list of employees
}
#Cacheable(value = "employees")
public List<EmployeeMapping> getAllEmployee() {
// return the list of employees
}
Here #CachePutand #Cacheable have the same cache key.d Now, when you call the updateSalary() method, #CachePut will replace the existing cached value for key "employees", with the result of the method i.e. list of employees with updated salary.
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 have an entity that is exposed by the following repository:
public interface InsertRepository extends PagingAndSortingRepository<InsertEntity, Long>, QueryDslPredicateExecutor<InsertEntity>, QueryDslBinderCustomizer<QInsertEntity> {
#Override
default void customize(QuerydslBindings bindings, QInsertEntity insert) {
bindings.bind(String.class).all(StringPath path, Collection<? extends String> values) -> {
BooleanBuilder predicate = new BooleanBuilder();
values.forEach(value -> predicate.or(path.containsIgnoreCase(value)));
return predicate;
});
}
}
What I'd like it to do is that all GET query parameters are chained as logical OR so that a query like ?description=searchText&customerName=searchText would execute an SQL query that looks as follows:
WHERE description LIKE '%searchText%' OR customerName LIKE '%searchText%'
However, I must be doing something wrong because it doesn't work - it is putting all query parameters into an AND query. That results in only those records being selected that contain searchText in customerName AND their description.
You can use named parameters such as
Example 53. Using named parameters
http://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.query-methods.query-creation
public interface UserRepository extends JpaRepository<User, Long> {
#Query("select u from User u where u.firstname = :firstname or u.lastname = :lastname")
User findByLastnameOrFirstname(#Param("lastname") String lastname,
#Param("firstname") String firstname);
}
The answer provided by #kafkas is not accurate at all. There are quite few problems with it:
Annotation #Query is obsolette - Spring automatically does it for you, you just need to type the name of the method properly.
Annotations #Param are obsolette - Spring automatically takes parameters in given order, matched with those in method name.
You return single User entity, but you still use findBy instead of findOne - this leads to an error, if more than one record is found.
The last, but not least - provided method will not use LIKE comparation, but equals instead. You should use findByXXXContaining if You wish to launch SQL query like: ... WHERE firstname LIKE "%name%"
Using Spring, I suggest not using JpaRepository if You don't need to. The simplest implementation is CrudRepository and it covers most use cases.
In summary, Your method should be simplified and look somewhere like that:
public interface UserRepository extends CrudRepository<User, Long> {
User findOneByLastnameContainingOrFirstnameContaining(String lastname, String firstname);
}
This should result in query:
SELECT * FROM User u WHERE u.lastname LIKE '%lastname' OR u.firstname LIKE '%firstname%;'
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!