Why Update using #Query in Spring Data Jpa requires #Transactional - spring-boot

I am new to spring boot. I use spring data jpa to deal with database. I have a method to update a table in the database using #Query. But when I try to update I get an exception of invalidDataAccessApiUsageException. when I tried it with #Transactional it gets updated successfully. Aren't updates a single operation so wouldn't it get committed automatically.

There are 2 ways in which transaction execute in SQL
Implicit -> One that means database, while running the write query(UPDATE, INSERT ....), create an isolation and then execute. If an error occurs, the isolation is discarded and no change will be written.
Explicit -> In this you explicitly specify the isolation start using BEGIN , discarding by ROLLBACK and finally writing by COMMIT
Initial versions of postgres (<7.4) had a configuration to called AUTOCOMMIT which when set off, will DISABLE implicit transactions. But this was disabled in 2003 since the databases were smart enough to discard isolations and not create inconsistencies.
In a nutshell at any point running following queries
UPDATE table_name WHERE id IN (....)
or
BEGIN
UPDATE table_name WHERE id IN (....)
COMMIT
are EXACTLY the same.
In JPA autocommit is now just a runtime validation for write queries.

Related

ERROR: cannot execute nextval() in a read-only transaction - PostgreSQL

I can see internal server error on my app developed on spring mvc, using wildfly as the webserver and database is PostgreSQL. What does this exception mean?
ERROR: cannot execute nextval() in a read-only transaction
It was working all fine before. I tried to look for the solution here on stackoverflow but didn't find anything that could fix this issue.
The function nextval() is used to increment a sequence, which modifies the state of the database.
You get that error because you are in a read-only transaction. This can happen because
You explicitly started a read-only transaction with START TRANSACTION READ ONLY or similar.
The configuration parameter default_transaction_read_only is set to on.
You are connected to a streaming replication standby server.
If default_transaction_read_onlyis set to on, you can either start a read-write transaction with
START TRANSACTION READ WRITE;
or change the setting by editing postgresql.conf or with the superuser command
ALTER SYSTEM SET default_transaction_read_only = off;
As others have pointed out nextval() actually updates the database to get a new sequence, so can't be used in a transaction that is marked as read only.
As you're using Spring I suspect this means that you're using the spring-transaction support. If you're using annotation based transaction support, then you'd get a read only transaction if you have
#Transactional(readOnly=true)
That means that when spring starts the transaction it will put it into read only mode.
Remove the readOnly=true bit and a regular writable transaction is created instead.
Spring transaction control at http://docs.spring.io/spring-framework/docs/4.2.x/spring-framework-reference/html/transaction.html
I means exactly what it says, here is example:
t=# create sequence so49;
CREATE SEQUENCE
t=# begin;
BEGIN
t=# select nextval('so49');
nextval
---------
1
(1 row)
t=# set transaction_read_only TO on;
SET
t=# select nextval('so49');
ERROR: cannot execute nextval() in a read-only transaction
t=# end;
ROLLBACK
I presume you connected as so called ro user, which is user with "transaction_read_only" set to true, EG:
t=# select rolconfig from pg_roles where rolname ='ro';
rolconfig
----------------------------
{transaction_read_only=on}
(1 row)
you can switch that off for your user of course, but this is out of scope I believe
https://www.postgresql.org/docs/current/static/sql-set-transaction.html

Custom query within JPA server-managed session

I'm trying to execute an unrelated query (other_table) within a JTA session (server-managed) in order to do some validations, before persisting the bean EJB into DB with JPA.
Here is what I want to do (aprox):
#PersistenceUnit(unitName="DynamicDatabase")
EntityManagerFactory emf;
#TransactionAttribute(TransactionAttributeType.REQUIRED)
private long nextEntryid() {
em = emf.createEntityManager();
Query query = em.createQuery("select t from OTHER_TABLE t");
// do some validation and checking
MyTable bean = new MyTable();
em.persist(bean);
}
However I keep getting a server error, it does not allow to interact with other database items that are not persisted:
org.apache.openjpa.persistence.ArgumentException:
An error occurred while parsing the query filter (query): The name "OTHER_TABLE" is not a recognized entity (...) Perhaps you meant MyTable, which is a close match.
<persistence-unit name="DynamicDatabase" transaction-type="JTA">
<jta-data-source>jdbc/DB2DynamicConnection</jta-data-source>
<class>jorge.java.dynamicdatabase.db.MyTable</class>
</properties>
</persistence-unit>
The question is: what is the proper way to query/alter another table within the same JPA DB connection and JTA transaction?
Pretty newby about this, please be patient with me. Been working on this very long.
Edit: I don't think it's related but FYI I'm using WebSphere Liberty Profile 8.5.5.4, JSDK 8u31, EclipseEE Luna 4.4.2 for Web Dev. Going to add it to tags.
The problem is that you have a #NamedQuery that references the entity OTHER_TABLE, and that does not exist or not marked as being an Entity (try in both Java class and persistence.xml).
If the OtherTable Java class is not an entity and if it MUST remain so, then you could use Constructors in JPQL-queries:
SELECT NEW com.domain.reports.MyReport(u.firstName, u.lastName, u.birthday) FROM User u
If you need to write plain SQL queries, then you could do it using native queries, as they are known in the JPA specification.
Based on Andrei's suggestion, the JPQL (Java Persistence Query Language) operates on objects, not on tables. This means that em.createQuery() can't be used for universal database interaction.
To execute any SQL statement generally speaking (inside the container-managed transaction JTA), it is necessary to get the DB connection from the entity manager (it will return the persistence context unit JPA).
// Get container's objects
em = emf.createEntityManager();
java.sql.Connection conn = em.unwrap(java.sql.Connection.class);
// Run the query
Statement sql = conn.createStatement();
ResultSet rs = sql.executeQuery("select * from OTHER_TABLE");
rs.next()
(...)
//Container-managed connection shouldn't be closed.
rs.close;
sql.close;
Notice that unwrap call works for JPA but not for Hibernate (other questions already exist on this point). Notice the different language used for the SQL statement select * from than a named query JPQL select t from. Exception handling must be also controlled as usual with a } finally { clause.
That way would allow to execute a complex custom statement within server-managed transaction without using JAVA entities and I can finally sleep.

oracle two different session

in our work we create two .net listener,
first one:
calling oracle stored procedure that insert bulk of data into table(table1) using insert into select syntax:
insert into table1 select c1,c2... from tbl2 inner join tbl3....
then we use explicity commit;
second listener:
calling oracle procedure that reading data inserted into table1 via listener1
but we notice that even the record inserted into table1 listener2 couldn't see that recordat same time even that commit is use.
my question is how does cmmit work when we use insert ...select?
is this issue related to session?when listener 1 session end listener 2 can read data?
please help,
thank in advance.
You're using the wrong terms...
A listener is a server application that listens to the incoming client requests and hands it to the DB engine. A listener is not being used on the client end.
A session is not related to the data you can see, a transaction is the object that controls that.
Oracle works in a very clear way - After a transaction has committed - all the new transactions can see it, and already existing transactions can see the new content based on it transaction configurations..
I recommend you reading about isolation levels in that context http://msdn.microsoft.com/en-us/library/system.transactions.isolationlevel(v=vs.110).aspx
By default - the moment (and in DB it is defined by SCN) a transaction have been committed - the data is visible to the client.
Bottom line - your issue is related either to transaction isolation levels (in the case the reading transaction started before the commit), or to the writer, which does not commit the data when you think it is (a transaction issue).
After the call to transaction.Commit() in .net returned - the data is already visible, and other transactions are seeing it.
You're second question was how commit works.
This is a very complicated process in Oracle, so I'll give a really short description:
1. When you commit, Oracle first runs some verifications before the commit itself (for example, runs the deferred constraints).
2. After oracle knows it can safely commit the changes it gets the system time (SCN) , write the commit itself to the redo log, and flushes the data to disk (for consistency).
3. Sends an ACK to the user, that the data is already visible to the world.
4. marks the buffers been used as free.
Something I want to add, just to make sure (and I'm writing it half a sleep - so excuse me if it does not compile...)
In you're .net code - your code should be logically equivalent to it:
OracleConnection con = new OracleConnection(connStr);
con.Open();
OracleTransaction trans = con.BeginTransaction();
OracleCommand cmd = con.CreateCommand();
cmd.Connection = cmd;
cmd.CommandText = "insert into ...";
cmd.ExecuteNonQuery();
cmd.Dispose();
trans.Commit();
trans.Dispose();
con.Close();
con.Dispose();
and if you're using LINQ - make sure you create the transaction scope on the right area.

Application hangs up randomly in jdbcTemplate for update

I am using simpleJdbcTemplate of Spring to execute update with query shown below:
update TABLE B JOIN
(select Column1 from TABLE A
) C ON B.Column2 = C.Column3
set B.Column4 = 1
Transaction timeout is taking place.
Any suggestions?
If the SQL execution is hanging, then either the database is doing a shedload of work trying to execute it, or you have a isolation lock on the required tables caused by another connection to the database from elsewhere.
This almost certainly has nothing to do with Spring, but without more information, it's hard to tell.

How to read changed values with native query during one transaction? (Spring and JPA)

We have container transaction with Spring and JPA (Hibernate). I need to make an update on a table to "flag" some rows via native statements. Then we insert some rows via EntityManager from JPATemplate to this table. After that, we need to calculate changes in the table via native statement (with Oracle's union and minus, complex groups...)
I see that changes from step 1 and 2 are not commited and thats why the statement from 3 fails. I already tried with transaction propagation REQUIRES_NEW, EntityManager.flush... Didn't work.
1) update SOMETABLE acolumn = somevalue (native)
2) persist some values into SOMETABLE (via entity manager)
3) select values from SOMETABLE
Is there a possibility to read the changes from step 1 and 2 in step 3?
I guess you are using the same DataSource in the JpaTransactionManager, JdbcTemplate and JpaTemplate and have enabled #Transactional with this:
<tx:annotation-driven />
Assuming it is not a configuration bug, my best guess is that you're calling on the #Transactional method from a method in the same class?
In that case, you need AspectJ to weave in the transaction logic or refactor the code so the #Transactional method is in another class than the calling method. (The refactor option is the easy and preferred one)
If this doesn't solve your problem, you should add the relevant classes to your question together with relevant log messages.

Resources