EclipseLink connections deadlock - java

Single threaded standalone java app entering a deadlock? Yes, with EclipseLink this is very easy. So after a week of debugging a very complex multi threaded app, I managed to narrow down the problem to this:
If you have only 1 thread in application, you'd assume that you need a DB connection pool of size 1 and that everything should work. Well, not in this case:
public void singleThreadedMethod() {
User u;
--start JPA transaction / create EM (1)--
u = em.find(User.class, userId);
-- end JPA transaction / close EM --
--start JPA transaction / create EM (2)--
u.getCompany(); // lazy assoc (3)
-- end JPA transaction / close EM--
}
EclipseLink will take 1 connection for (1), then return it to the pool. Then take another connection for (2), then try to take another connection for (3), although it looks like the code is inside a single transaction. Trick is that u is not managed in this transaction (2), but still "manages" to get to the DB to get its lazy association. If the DB pool size is 1, this creates a deadlock, since (2) is holding the only connection that (3) (inside (2)) is waiting on. Note that this is NOT a deadlock in DB, but in connection pool in Java.
This creates a debugging nightmare when you have pool of 20 connections and less than 20 threads and you wonder where that deadlock comes from!
I guess it's a long shot, but - is there any way to stop EclipseLink from doing what it does? I.e. to stop it from fetching lazy associations when not inside persistence context? Or to use thread's existing persistence context if it's there.

Related

How to SET LOCK MODE in java application

I am working on a Java web application that uses Weblogic to connect to an Informix database. In the application we have multiple threads creating records in a table.
It happens pretty often that it fails and the following error is thrown:
java.sql.SQLException: Could not do a physical-order read to fetch next row....
Caused by: java.sql.SQLException: ISAM error: record is locked.
I am assuming that both threads are trying to insert or update when the record is locked.
I did some research and found that there is an option to set the database that instead of throwing an error, it should wait for the lock to be released.
SET LOCK MODE TO WAIT;
SET LOCK MODE TO WAIT 17;
I don't think that there is an option in JDBC to use this setting. How do I go about using this setting in my java web app?
You can always just send that SQL straight up, using createStatement(), and then send that exact SQL.
The more 'normal' / modern approach to this problem is a combination of MVCC, the transaction level 'SERIALIZABLE', retry, and random backoff.
I have no idea if Informix is anywhere near that advanced, though. Modern DBs such as Postgres are (mysql does not count as modern for the purposes of MVCC/serializable/retry/backoff, and transactional safety).
Doing MVCC/Serializable/Retry/Backoff in raw JDBC is very complicated; use a library such as JDBI or JOOQ.
MVCC: A mechanism whereby transactions are shallow clones of the underlying data. 2 separate transactions can both read and write to the same records in the same table without getting in each other's way. Things aren't 'saved' until you commit the transaction.
SERIALIZABLE: A transaction level (also called isolationlevel), settable with jdbcDbObj.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE); - the safest level. If you know how version control systems work: You're asking the database to aggressively rebase everything so that the entire chain of commits is ordered into a single long line of events: Each transaction acts as if it was done after the previous transaction was completed. The simplest way to implement this level is to globally lock all the things. This is, of course, very detrimental to multithread performance. In practice, good DB engines (such as postgres) are smarter than that: Multiple threads can simultaneously run transactions without just being frozen and waiting for locks; the DB engine instead checks if the things that the transaction did (not just writing, also reading) is conflict-free with simultaneous transactions. If yes, it's all allowed. If not, all but one simultaneous transaction throw a retry exception. This is the only level that lets you do this sequence of events safely:
Fetch the balance of isaace's bank account.
Fetch the balance of rzwitserloot's bank account.
subtract €10,- from isaace's number, failing if the balance is insufficient.
add €10,- to rzwitserloot's number.
Write isaace's new balance to the db.
Write rzwitserloot's new balance to the db.
commit the transaction.
Any level less than SERIALIZABLE will silently fail the job; if multiple threads do the above simultaneously, no SQLExceptions occur but the sum of the balance of isaace and rzwitserloot will change over time (money is lost or created – in between steps 1 & 2 vs. step 5/6/7, another thread sets new balances, but these new balances are lost due to the update in 5/6/7). With serializable, that cannot happen.
RETRY: The way smart DBs solve the problem is by failing (with a 'retry' error) all but one transaction, by checking if all SELECTs done by the entire transaction are not affected by any transactions that been committed to the db after this transaction was opened. If the answer is yes (some selects would have gone differently), the transaction fails. The point of this error is to tell the code that ran the transaction to just.. start from the top and do it again. Most likely this time there won't be a conflict and it will work. The assumption is that conflicts CAN occur but usually do not occur, so it is better to assume 'fair weather' (no locks, just do your stuff), check afterwards, and try again in the exotic scenario that it conflicted, vs. trying to lock rows and tables. Note that for example ethernet works the same way (assume fair weather, recover errors afterwards).
BACKOFF: One problem with retry is that computers are too consistent: If 2 threads get in the way of each other, they can both fail, both try again, just to fail again, forever. The solution is that the threads twiddle their thumbs for a random amount of time, to guarantee that at some point, one of the two conflicting retriers 'wins'.
In other words, if you want to do it 'right' (see the bank account example), but also relatively 'fast' (not globally locking), get a DB that can do this, and use JDBI or JOOQ; otherwise, you'd have to write code to run all DB stuff in a lambda block, catch the SQLException, check the SqlState to see if it is indicating that you should retry (sqlstate codes are DB-engine specific), and if yes, rerun that lambda, after waiting an exponentially increasing amount of time that also includes a random factor. That's fairly complicated, which is why I strongly advise you rely on JOOQ or JDBI to take care of this for you.
If you aren't ready for that level of DB usage, just make a statement and send "SET LOCK MDOE TO WAIT 17;" as SQL statement straight up, at the start of opening any connection. If you're using a connection pool there is usually a place you can configure SQL statements to be run on connection start.
The Informix JDBC driver does allow you to automatically set the lock wait mode when you connect to the server.
Simply pass via the DataSource or connection URL the following parameter
IFX_LOCK_MODE_WAIT=17
The values for JDBC are
(-1) Wait forever
(0) not wait (default)
(> 0) wait this many seconds
See https://www.ibm.com/support/knowledgecenter/SSGU8G_14.1.0/com.ibm.jdbc.doc/ids_jdbc_040.htm
Connection conn = DriverManager.getConnection ( "jdbc:Informix-sqli://cleo:1550:
IFXHOST=cleo;PORTNO=1550;user=rdtest;password=my_passwd;IFX_LOCK_MODE_WAIT=17";);

Hibernate internal functioning

I'm working on Spring + Hibernate applications. We have applied transaction for service class methods. My questions
Can hibernate execute all db statements of the service method with single connection/session or it uses multiple connections? If it uses multiple connections is it possible to rollback db statements over multiple connections in case of any runtime exceptions?
Suppose if the service method's business logic execution takes more time than removeAbandonedTimeout value, how does the commit/rollback happens on abandoned connection?
Please correct me if i'm wrong any where. Thanks in advance.
UPDATE:-
If the query takes more time than removeAbandonedTimeout it throws exception. Suppose my service method has two db calls, between those two calls some business logic (with no db calls) is there. Before executing the first query it creates db connection, assume first db call took 1 second, and then the business logic execution took 60 seconds. If the connection is abandoned it this moment (if we set removeAbandonedTimeout to 60 seconds), to execute second db query it creates another connection, right? If the second query execution fails it has to rollback first query as they both share same transaction. How could it happen with abandoned connection?
Hibernate will do what you told it to :
When integrating with spring, it will use spring managed transaction. Check where you are opening / closing tx (use of #Transactional on public method or directly using TransactionTemplate) : all hibernate queries inside will run in the same transaction.
This is a question related to your connection pool (dbcp ?). Do not activate the removeAbandonedTimeout flag : removeAbandonedOnMaintenance : from documentation :
Setting one or both of these to true can recover db connections
from poorly written applications which fail to close connections.
If you are using typical spring / hibernate coding pattern, you are not poorly writting your application (from a database resource point of view), so no need to activate this flag : let your long running thread keep it's transaction. If an operation is running so slow without running any db query (that it would have triggered dbcp cleanup), you have two options :
Don't keep the connection to the database : cut your transaction in two : one before the long running process, one after
If you need to keep the tx open (because you have database lock you do not want to lose for example), try to optimize the code in between using cpu sampling tool for example.
Answers for your questions:
With single connection we can execute all db statements of service.We cannot rollback db statements over multiple connections at a time.
In general the removeAbandonedTimeout value should be set to the longest running query your applications might have.If the removeAbandonedTimeout exceeds and if removeAbandoned = true, the db connections can be recovered.

How can I request a specific connection from com.mchange.v2.c3p0.ComboPooledDataSource?

Problem:
Program uses com.mchange.v2.c3p0.ComboPooledDataSource to connect to Sybase server
Program executes 2 methods, runSQL1() and runSQL2(), in sequence
runSQL1() executes SQL which creates a #temptable
SELECT * INTO #myTemp FROM TABLE1 WHERE X=2
runSQL2() executes SQL which reads from this #temptable
SELECT * FROM #myTemp WHERE Y=3
PROBLEM: runSQL2() gets handed a different DB connection from the pool than the one handed to runSQL1().
However, Sybase #temptables are connection-specific, therefore runSQL2() fails when it can't find the table.
The most obvious solution I can think of (aside from degenerate one of making pool size 1, at which point we don't even need a pool), is to somehow remember which specific connection from the pool was used by runSQL1(), and have runSQL2() request the same connection.
Is there a way to do this in com.mchange.v2.c3p0.ComboPooledDataSource?
If possible, I'd like an answer which is concurrency-safe (in other words, if connection used in runSQL1() is being used by another thread, runSQL2()'s call to get connection will wait until that connection is released by another thread).
However, if that's impossible, I'm OK with the answer which assumes that DB connections (the ones I care about) are all happening in one single thread, and therefore any connection requested by runSQL2() will be 100% available if it was available to runSQL1().
I'm also welcoming of any solutions that address the problem some other way, as long as they don't involve "stop using #temptables" as part of the solution.
Easiest and most obvious way to do that is just to request connection from the pool and then run runSQL1() and runSQL2() with that connection. Usage pattern being suggested in the question goes against general design principles of connection pool managers, as it will effectively promote them to some kind of transaction manager.
There are Java frameworks that might aid in the above. For example in Spring #Transaction or TransactionTemplate can be used to demarcate transaction boundaries and it will guarantee that single connection is used by single thread (or more precisely, according to transaction propagation annotations). Spring can use many transaction managers, but probably simplest would be to use DataSourceTransactionManager and it can also be configured to use c3p0 as DataSource.

How to resolve java.sql.SQLException distributed transaction waiting for lock

We are using Oracle 11G and JDK1.8 combination.
In our application we are using XAConnection, XAResource for DB transaction.
ie) distributed transactions.
On few occasions we need to kill our Java process to stop the application.
After killing, if we restart our application then we are getting the below exception while doing DB transaction.
java.sql.SQLException: ORA-02049: timeout: distributed transaction
waiting for lock
After this for few hours we are unable to use our application till the lock releases.
Can someone provide me some solution so that we can continue working instead of waiting for the lock to release.
I have tried the below option:
a) Fetched the SID and killed the session using alter command.After this also table lock is not released.
I am dealing with very small amount of data.
I followed one topic similar with that with tips about what to do with distributed connections.
Oracle connections remains open until you end your local session or until the number of database links for your session exceeds the value of OPEN_LINKS. To reduce the network overhead associated with keeping a database link open, then use this clause to close the link explicitly if you do not plan to use it again in your session.
I believe that, by closing your connections and sessions after DDL execution, this issue should not happens.
Other possibility is given on this question:
One possible way might be to increase the INIT.ORA parameter for distributed_lock_timeout to a larger value. This would then give you a longer time to observe the v$lock table as the locks would last for longer.
To achieve automation of this, you can either
- Run an SQL job every 5-10 seconds that logs the values of v$lock or the query that sandos has given above into a table and then analyze it to see which session was causing the lock.
- Run a STATSPACK or an AWR Report. The sessions that got locked should show up with high elapsed time and hence can be identified.
v$session has 3 more columns blocking_instance, blocking_session, blocking_session_statusthat can be added to the query above to give a picture of what is getting locked.
I hope I helped you, my friend.

JTA - how is transaction registered?

I am using the following piece of code I found online (Here) as an example of JTA Transaction processing:
// Get a UserTransaction
UserTransaction txn = new InitialContext().lookup("java:comp/UserTransaction");
try {
System.out.println("Starting top-level transaction.");
txn.begin();
stmtx = conn.createStatement(); // will be a tx-statement
stmtx.executeUpdate("INSERT INTO test_table (a, b) VALUES (1,2)");
stmtx.executeUpdate("INSERT INTO test_table2 (a, b) VALUES (3,4)");
System.out.print("\nNow attempting to rollback changes.");
txn.rollback();
}
I have a few questions, in general, about the JTA that are drawn from the example above:
I presume the whole point of saying txn.begin and then rollback is to be able to (apperently) rollback TWO SQL statements correct?
Each of the update queries were TRANSACTIONS themselves, right? They must have succeded so that we can get to rollback call at the bottom. Well, if they succeded i.e. commited, how on earth can we roll them back all of a sudden?
The most important question: what happens when we say txn.begin()? I understand from the JTA API that it is supposed to register this transaction with a calling thread by TransactionManager instance. How is TM even linked to the UserTransaction? And finally, how is the txn aware of the fact that we modified the DB twice and is able to speak to DB to roll it back? We have not registered ANY ResourceManagers with it so it should not be aware of any resources being at play...
I am a bit lost here, so any info would be appreciated... Question 3 bothers me the most.
yes, or event just one. It's also the ability of committing the transaction at the end, and thus have the other concurrent transaction only see the new state after the transaction has been committed, and not all the temporary states between the beginning and the end of the transaction (i.e. the I in ACID)
No. An update is an update. It's executed as part of the transaction that you begun previously. If one of them doesn't succeed, you'll have an exception, and can still choose to commit the transaction (i.e. have all the previous updates committed), or to rollback the transaction (i.e. have all the previous updates canceled).
The UserTransaction has a reference to its transaction manager, presumably. When you get a connection from a DataSource in a Java EE environment, the DataSource is linked to the transaction manager of the Java EE container, and rollbacking the JTA transaction will use the XA protocol to rollback all the operations done on all the data sources during the transaction. That's the container's business, not yours.
There's a lot to learn about transactions, but maybe I can give you a head start:
Yes. But you will usually only want to rollback in case of a problem - some step of the transaction could not be completed because of a technical issue (syntax error, table not found, segment overrun, ...) or an application logic problem (customer has not enough funds for all order line items for example).
Given auto commit mode is disabled, the inserts are not committed before you actually commit. They are temporarily applied to the database using a Write-Ahead-Log (PostgreSQL, InnoDB-Engine, Oracle) with sophisticated Multi-Version-Concurrency-Control (MVCC) which determines which state of the database each transactional client can see. A very interesting topic :-).
A UserTransaction is registered with your current Thread. Resources (i.e. Databases or Messaging services) enlist themselves with the UserTransaction. This is usually only necessary when you are using distributed transactions (XA transactions, 2PC).
I suggest to get a good read on SQL programming (for example Head First SQL) and check out the Java EE 6 tutorial.

Categories