I have a basic requirement :
1) Need a hibernate session manager which is called each time I open and close or do anything else using session.
2) It should work as a wrapper around the hibernate session.
3) For example : I create a session utility , which will allow at a time creating 5 sessions only , and if 5 of them are already in used , my request has to wait till I get one of the 5 session back.
There really isn't a need to write a special Session Manager to do this as you can exploit a connection pool to easily handle this behavior for you.
What you first need to do is define your connection pool with a maximum number of available connections, which in your case would be 5. Then you want to configure the connection pool so that it has a wait timeout with something reasonable. Just understand that this timeout can be problematic in a denial of service attack scenario, so use at your own risk.
With the connection pool properly configured, if the first 5 are doing some long-running task that takes several seconds and the 6th request comes in, it will wait to acquire a connection with the database from the pool before it continues, so you'll only ever have 5 concurrent connections happening with your database at any point.
Related
I have a scenario in production for a web app, where when a form is submitted the data gets stored in 3 tables in Oracle DB through JDBC. Sometimes I am seeing connection time out errors in logs while the app is trying to connect to Oracle DB through Java code. This is intermittent.
Below is the exception:
SQL exception while storing data in table
java.sql.SQLRecoverableException: IO Error: Connection timed out
Most of the times the web app is able to connect to data base and insert values in it but some times and I am getting this time out error and unable to insert data in it. I am not sure why am I getting this intermittent issue. When I checked the connections pool config in my application, I noticed the following things:
Pool Size (Maximum number of Connections that this pool can open) : 10
Pool wait (Maximum wait time, in milliseconds, before throwing an Exception if all pooled Connections are in use) : 1000
Since the pool size is just 10 and if there are multiple users trying to connect to data base will this connection time out issue occur ?
Also since there are 3 tables where the data insertion occurs we are doing the whole insertion in just one connection itself. We are not opneing each DB connection for each individual table.
NOTE: This application is deployed on AEM (Content Management system) server and connections pool config is provided by them.
Update: I tried setting the validation query in the connections pool but still I am getting the connection time out error. I am not sure whether the connections pool has checked the validation query or not. I have attached the connections pool above for reference.
I would try two things:
Try setting a validation query so each time the pool leases a connection, you're sure it's actually available. select 1 from dual should work. On recent JDBC drivers that should not be required but you might give it a go.
Estimate the concurrency of your form. A 10 connections pool is not too small depending on the complexity of your work on DB. It seems you're saving a form so it should not be THAT complex. How many users per day do you expect? Then, on peak time, how many users do you expect to be using the form at the same time? A 10 connections pool often leases and retrieves connections quite fast so it can handle several transactions per second. If you expect more, increase the size slightly (more than 25-30 actually degrades DB performance as more queries compete for resources there).
If nothing seems to work, it would be good to check what's happening on your DB. If possible, use Enterprise Manager to see if there are latches while doing stuff on those three tables.
I give this answer from programming point of view. There are multiple possibilities for this problem. These are following and i have added appropriate solution for it. As connection timeout occurs, means your new thread do not getting database access within mentioned time and it is due to:
Possibility I: Not closing connection, there should be connection leakage somewhere in your application Solution
You need to ensure this thing and need to check for this leakage and close the connection after use.
Possibility II: Big Transaction Solution
i. Is these insertion synchronized, if it is so then use it very carefully. Use it at block level not method level. And your synchronized block size should be minimum as much as possible.
What happen is if we have big synchronized block, we give connection, but it will be in waiting state as this synchronized block needs too much time for execution. so other thread waiting time increases. Suppose we have 100 users, each have 100 threads for that operation. 1st is executing and it takes too long time. and others are waiting. So there may be a case where 80th 90th,etc thread throw timeout. And For some thread this issue occurs.
So you must need to reduce size of the synchronized block.
ii. And also for this case also check If the transaction is big, then try to cut the transaction into smaller ones if possible:-
For an example here, for one insertion one small transaction. for second other small transaction, like this. And these three small transaction completes operation.
Possibility III: Pool size is not enough if usability of application is too high Solution
Need to increase the pool size. (It is applicable if you properly closes all the connection after use)
You can use Java Executor service in this case .One thread One connection , all asynchronous .Once transaction completed , release the connection back to pool.That way , you can get rid of this timeout issue.
If one connection is inserting the data in 3 tables and other threads trying to make connection are waiting, timeout is bound to happen.
I wrote a script that uses MyBatis to execute a massive number of inserts into multiple databases. The previous script didn't use MyBatis an was, more or less, twice as fast (25 min for a million records, 1 hour 10 minutes using MyBatis). I have tried different things, but I don't know exactly how to configure MyBatis to increase its performance. Some specific considerations about my problem and solution:
The databases are in a VPC, so network time is important.
I use guice to bind the mappers for each database. Connection information is set programmatically. The mappers are get then when I need to execute an insert.
The rows that need to be inserted are not sorted, so they are enqueued by database. When a queue reaches a given size, a multirow insert is executed. Can I use something better with injected mappers?
I use pooled connections. Does this mean that 3 connections are opened when the mapper is first used and then reused? If a given mapper is used only every few minutes, those idle connections are closed?
Sometimes I get this error randomly:
org.apache.ibatis.transaction.TransactionException: Error configuring
AutoCommit. Your driver may not support getAutoCommit() or
setAutoCommit(). Requested setting: false.
Cause:
com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure
The last packet successfully received from the server was 4,030,088 milliseconds ago.
The last packet sent successfully to the server was 0 milliseconds ago.
What can I do to increase the performance and to avoid the communication error?
1、it seems that you need to change your connection pool param.
database such as mysql may close a connection when it's idle for a target time interval, but the connection pool may not be noticed ,so when your mapper use a closed connection , the CommunicationsException occurs.
(1)if you use c3p0 ,you can specify the idle_test_period to solve this problem.
(2) or you can specify jdbc Timeout Settings(Max Wait Time、Idle Timeout)
2、connection pool has minSize and maxSize property , when your idle connection num is greater then minSize, the exceed part will be closed.
I think you have to make optimization of mysql configuration to bulk insert : enter link description here
It look like mybatis try to set autocommit to false, and that's a good optimization.
And I think it's better to have an instance of mapper by database and create 3 datasources with guice.
Another way is to use sqlimport but it's a big break.
In my standalone app, generating over 1000 threads in single time and each thread has it's own Hibernate session. But in this case, count of sessions hits over database max connections restriction that throws an error.
I've tried to set .getCurrentSession() instead of .openSession(), but it brought no effect, because Hibernate opens new own session for each new thread anyway.
How can i round this problem? Can i set somehow the count of slots for concurrent connections? For e.g. pass 100 connections and let another 900 to wait till these 100 will be closed to process this further?
Using a connection pool can help solve this.
Here is a post about setting up a connection pool Can you only have one hibernate session per thread in java?
Most people utilize a connection pool, like C3P0 that can be used to
ensure session reuse and speed up your code.
The best structure I use is to create a SessionFactory once in
application launch, as this sets up the connection pool to the
database. Then, utilizing maybe a singleton pattern to keep a single
SessionFactory, request new sessions for each transaction you perform
from the single SessionFactory. Hibernate will utilize the underlying
connection pool to handle session reuse for speed and optimization.
Here is another post on various connection pooling libraries available.
By default, Hibernate ships with the ability to obtain a data source
implementation ( javax.sql.DataSource ) from JNDI by setting the
properties appropriately
hibernate default connection pooling
You can Use 'ExecutorService' to manage the 1000 threads, limit to make only 100 threads running and the others will stay in the queue.
However, I think it's not good to have so many threads in you app. I assuming you are working on a web service app, and may have 1000 requests coming in at the same time, and the old school solution is to create 1000 threads to handle that. But epoll will just be better, you can consider about some NIO framework such as MINA/Netty.
While stress testing my JPA based DAO layer (Running 500 simultanious updates at the same time each in a separate thread). I encountered following - system always stuck unable to make any progress.
The problem was, that there were no available connections at some point for any thread, so no running thread could make any progress.
I have investigated this for a while and the root was REQUIRES_NEW annotation on add method in one of my JPA DAO's.
So the scenario was:
Test starts acquiring new Connection from ConnectionPool to start transaction.
After some initial phase, I call add on my DAO, causing it to request another Connection from ConnectionPool which there are no, because all the Connections by that time, were taken by parallel running tests.
I tried to play with DataSource configurations
c3p0 stucks
DBCP stucks
BoneCP stucks
MySQLDataSource fail some requests, with error - number of connections exceeded allowed.
Although I solved it by getting read of REQUIRES_NEW, with which all DataSources worked perfectly, still the best result seems to be of MySQLDataSource, since it did not stuck and just fail:)
So it seems you should not use REQUIRES_NEW at all, if you expect high throughput.
And my question:
Is there a configuration for either DataSources that could prevent this REQUIRES_NEW problem?
I played with checkout timeout in c3p0, and tests started to fail, as expected.
2 sec - 8 % passed
4 sec - 12 % passed
6 sec - 16 % passed
8 sec - 26 % passed
10 sec - 34 % passed
12 sec - 36 % passed
14/16/18 sec - 40 % passed
This is highly subjective ofcourse.
MySQLDataSource with plain configurations gave 20% of passed tests.
What about configuring a timeout for obtaining the connection? If the connection can't be obtained in say 2 seconds, the pool will abort and throw an exception.
Also note that REQUIRES is more typical. Often you'd want a call chain to share a transaction instead of starting a new transaction for each new call in a chain.
Probably any of the Connection pools can be configured to deal with this in any number of ways. Ultimately, all that REQUIRES_NEW is probably forcing your app to acquire more than one Connection per client, which is multiplying the stressfulness of your stress tests. If pools are hanging, it's probably because they are running out of Connections. If you set a sufficiently large pool size, you might resolve the issue. Alternatively, as Arjan suggests above, you can configure pools to "fail fast" instead of hanging indefinitely, if clients have to wait for a Connection. With c3p0, the config param for that would be checkoutTimeout.
Without more information about exactly what's going on when you say a Connection pool "stucks", this is necessarily guesswork. But under very high concurrent load, with any Connection pool, you'll either need to make lots of resources available (high maxPoolSize + numHelperThreads in c3p0), kick out excess clients (checkoutTimeout), or let clients just endure long (but finite!) wait times.
In JDBC can we say the transaction begins as soon as we get the connection and finishes
as we close the connection. IS this right? If yes can we say In different requests sharing
the same connection, even all the uncommitted transactions will be visible to all
all requests?
#BalusC - This is not correct really. By default autocommit is set to true, which means that transaction begins before any JDBC operation and finishes RIGHT AFTER that single operation - not when connection is closed.
But you are right that sharing connection is indeed not good, If you want to multi-thread your DB it's best to handle it in the way that you have thread pool (look for ThreadPoolExecutor in java.util.concurrent) and for each thread you get a separate connection. ConnectionPool is also a good one, but I would rather limit that through ThreadPool - this way there is never a thread waiting for a connection from the pool.
That's right. That's the default behaviour. You can take over this control by setting the auto commit to false by connection.setAutoCommit(false) after retrieving the connection and committing the transaction by connection.commit() after doing all queries.
However, sharing a connection between different requests (threads) is at its own already a bad design. Your application is this way not threadsafe. You do not want to share the same connection among different threads. If all you want is eliminating the cost of connecting a database, then you should consider using a connection pool.
first rule when you access the database.
Every nontransactional operation should:
1.open connection, if have connection pool then get connection from the pool
2. Create execute statement
3. if is read query then map the result set.
4. close the result set.
5. close the statement.
6. close the connection.
if you want your operation to be in transaction then you should consider this approach:
Operation 1:
1. getSharedConnection
2.create/execute statement
3. if is read query then map the result set.
4. close resultSEt
5. close statement
operation 2:
Same as operation 1.
and the transaction:
public void updateInTransaction(){
Connection conn=pool.getConnection();//or you can create a new connection
conn.setAutocommit(false);
operation1(conn);
operation2(conn);
conn.close;
}
This is just basics for small applications.
If you are developing bigger applicatoin you should using same framework like JDBCTemplates from Springsoruce.