I am using the below set of code for an update:
private void updateAvatarPath(Integer param1, String param2, String param3, boolean param4){
Transaction avatarUpdatePathTransaction = session.beginTransaction();
String updateQuery = "query goes here with param";
Query query = session.createSQLQuery(updateQuery);
query.executeUpdate();
avatarUpdatePathTransaction.commit();
session.flush();
}
This function is being called from a loop. So this takes time to update since for each loop it's hitting the DB. Instead of hitting DB every time, to increase the performance I am planning to execute it as batches. But have no idea how to do it.
session.doWork() is one of the solutions which I got. I want to know any other option available to do it.
You should move Transaction avatarUpdatePathTransaction = session.beginTransaction(); before the start of your loop and avatarUpdatePathTransaction.commit(); after the end of your loop.
The recommended pattern is to have one session per "unit of work", in your case this seems to be modifying multiple entities in a single session/transaction.
The session.flush(); is not necessary I think, committing the transaction should flush the session
Related
I have this method that is called from another service:
#Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
public void execute(String sql) {
Query query = entityManager.createNativeQuery(sql);
query.executeUpdate();
}
Basically the client loads multiple sql files and run each sql file in a new transaction, in order to not impact other files execution.
For example this is an example of an sql file, that is cleaning up some data:
begin;
delete from table t where t.created_at < current_date - interval '2 month';
commit;
What I'm trying to do is to log, the outcome of each transaction. For example here, I want to display how many records were deleted. How can I do that from Spring ? I know that you can log something more specific with:
logging.level.org.springframework.transaction=TRACE
, but still I cannot see any outcome. This reveals information about sql that will run and when transaction started/ended.
Second solution was to check the result of:
int count = query.executeUpdate();
, but count is 0, even though the sql code got executed and deletes hundreds of rows.
Thanks upfront for the suggestions !
The problem is as #XtremeBaumer correctly pointed out your script. If you just run executeUpdate with a delete statement it will return the number of affected rows.
But that is not what you are doing. You are executing a code block delimited by begin and end. There might be a way for such a code block to return a value, but that would need to be coded into the code block and is probably highly database specific.
I trying persist a many registers in database reading a file with many lines
I´m using a forech to read the list of objects wrapped in file
logs.stream().forEach(log -> save(log));
private LogData save(LogData log) {
return repository.persist(log);
}
But the inserts are slow
Do i have a way to speed the inserts?
Your way take a long time because you persist element by element, so you go n time to the database, I would like to use Batch processing instead to use one transaction instead of N transaction, so the persist method can be :
public void persist(List<Logs> logs) {
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
logs.forEach(log -> session.save(log));// from the comment of #shmosel
tx.commit();
session.close();
}
Use a Batch Insert, Google "Hibernate Batch Insert" or replace with whatever name of your ORM if it's not Hibernate.
https://www.tutorialspoint.com/hibernate/hibernate_batch_processing.htm
To insert at every line makes this program slowly, why dont you think to collect n lines, and insert n lines together at once.
Theoretically, session.get() method is supposed to hit the database always, no matter whether the entity is stored in the cache or not. But whenever I use session.get() or session.load(), both doesn't hit the database second time.
Session session = factory.openSession();
tx = session.beginTransaction();
Customer cust = (Customer)session.get(Customer.class,2);
System.out.println(cust.getCid()+","+cust.getFirstName()+","+cust.getLastName()+","+cust.getPhone());
Customer cust2 = (Customer)session.get(Customer.class,2);
System.out.println(cust2.getCid()+","+cust2.getFirstName()+","+cust2.getLastName()+","+cust2.getPhone());
tx.commit();
session.close();
and this is the output,
Hibernate: select customer0_.cid as cid1_1_0_, customer0_.firstName as firstNam2_1_0_, customer0_.lastName as lastName3_1_0_, customer0_.email as email4_1_0_, customer0_.phone as phone5_1_0_, customer0_.aid as aid6_1_0_ from mycustomers customer0_ where customer0_.cid=?
2,Sam,pp,9799999999
2,Sam,pp,9799999999
Select query is executed only once and next time, it's retrieved from the cache. Same output if I use session.load() method also.
Am I missing something here? Please clarify.
Here's what's happening here:
The first query on console
It will always return a “proxy”. For example if you do session.load(Customer.class, 2), it will return a proxy object. Proxy object just have an identifier value and nothing else. You can imagine it to be somewhat like this.
customer.id = 2;
customer.fname = null;
customer.lname = null;
customer.address = null;
//rest all properties are null
It will Hit the database whenever you'll access the properties. In your case you're immediately calling ust.getCid() so it will immediately hit the database to fetch those queries. So the first query that you see in your console will appear for both the cases (i.e., session.get() and session.load())
Try doing this and see what your console looks like:
Session session = factory.openSession();
tx = session.beginTransaction();
Customer cust = (Customer)session.get(Customer.class,2);
//do not call any getter.
You'll see the difference on your console.
Why is second query not appearing
Hibernate Second Level Cache
You're trying to access the same object that you've accessed previously. Hibernate will then (instead of fetching it from database again) fetch it from second level cache.
You'll find detailed example of this scenario on this page : Hibernate Second Level Cache.
(just see the last example, it's similar to what you're getting)
Working on a Spring application that uses Hibernate, and in my DAO layer we are running an UPDATE statement to update some values in an Oracle database.
To make sure I'm not crazy, I ran the statement in SQL Developer to make sure it works properly. Here is part of my DAO code:
public void updateObjectInMyTable(SomeClassA objectOfSomeClassA) {
Session session = getCurrentSession();
String sql = "UPDATE SCHEMA_NAME.TABLE_XYZ SET FIRST_NAME=:firstName, LAST_NAME=:lastName, ADDRESS=:address, CITY=:city, ZIPCODE=:zipcode WHERE ID_NUMBER = :idNumber";
SQLQuery query = session.createSQLQuery(sql);
query.setParameter("firstName", objectOfSomeClassA.getFirstName());
query.setParameter("lastName", objectOfSomeClassA.getLastName());
query.setParameter("address", objectOfSomeClassA.getAddress());
query.setParameter("city", objectOfSomeClassA.getCity());
query.setParameter("zipcode", objectOfSomeClassA.getZipcode());
query.setParameter("idNumber", objectOfSomeClassA.getIdNumber());
query.executeUpdate();
}
(Excuse the poor variables names used for substitutions of the real ones.) I did debug on the server and I do not see any errors with query.executeUpdate() It gets to that line, and doesn't pass on to the next statement I have in my service layer.
Anything I'm doing wrong?
Where's your transaction ?!
Use :
session.beginTransaction().commit();
add this in the end line of your code.
I hope this helps you.
i am using both second level cache and query cache. Here is the code snippet
//first block
session = factory.openSession();
company1=(Company)session.get(Company.class, 1);
session.close();
//second block
session = factory.openSession();
tx = session.beginTransaction();
Query updateQuery=session.createQuery("update Company set companyName = 'newCompany' where companyId=1");
updateQuery.setCacheable(true);
updateQuery.executeUpdate();
tx.commit();
session.close();
//Third block
session = factory.openSession();
company1=(Company)session.get(Company.class, 1); // line 1
session.close();
In second block i did update in query . In third block i am getting the company record thru second level cache. What i was expecting i will get the same result(in 3rd block) what i got in first block but i got the updated record (done by query update in 2nd block) i.e "newCompany" at line 1
So looks like query cache and second level cache are in synch with
each other as update done by query cache is picked by second level cache.
UPDATE:-
So How does query and second level cahe works in synch? I mean does query cache first check
under second level cache whether there has been any update for the given query parameter?
The query cache stores IDs returned by previous executions of a cacheable select query.
Let's say you execute the following cacheable query:
select line from OrderLine line join line.order order
where line.status = ? and order.date = ?
If you execute it once, Hibernate will store the IDs of the lines returned by the query in its query cache. And it will store the lines themselves in the second-level cache.
If you execute the same query a second time, with the same parameters, Hibernate will extract the IDs from the query cache, without executing the select query. Then it will get every line by ID (which should be fast since the lines are in the second-level cache)
If you insert, update or delete a line or an order, Hibernate will detect it. Since this modification could affect the result of the cached query, the cache entries associated with this query in the query cache will be evicted. So the nexttime you execute this query again, it will be executed against the database, and the results will be stored again in the query cache.