As described here (relevant parts),
Play will automatically start the Hibernate entity manager when it finds one or more classes annotated with the
@javax.persistence.Entityannotation... When the JPA entity manager is started you can get it from the application code, using the JPA helper... Play will automatically manage transactions for you. It will start a transaction for each HTTP request and commit it when the HTTP response is sent.
As described here (relevant parts),
There is no built-in JPA implementation in Play 2.0; you can choose any available implementation.. Every JPA call must be done in a transaction so, to enable JPA for a particular action, annotate it with
@play.db.jpa.Transactional. This will compose your action method with a JPA Action that manages the transaction for you.
In my project, there are several data sources referred from different controllers, for example:
Action of the MeteoController.java:
public static void meteoDeviceObjects() {
Query query = JPA.em("meteo").createQuery("FROM MeteoDeviceObject m");
List<MeteoDeviceObjectController> meteoDeviceObjects = query.getResultList();
renderJSON(meteoDeviceObjects);
}
Action of the ClientsController.java:
public static void connectedClients(String connected) {
Query clientQuery = JPA.em("default").createQuery("FROM Client c WHERE c.connected=:connected");
List<Client> connectedClientsList = clientQuery.setParameter("connected", connected).getResultList();
renderJSON(connectedClientsList);
}
I found the connection leak, even with a relatively small load:
Oops: PersistenceException An unexpected error occured caused by exception PersistenceException: org.hibern ate.exception.GenericJDBCException: Could not open connection
play.exceptions.UnexpectedException: Unexpected Error
at play.Invoker$Invocation.onException(Invoker.java:244)
at play.Invoker$Invocation.run(Invoker.java:306)
at Invocation.HTTP Request(Play!)
Caused by: javax.persistence.PersistenceException: org.hibernate.exception.Gener
icJDBCException: Could not open connection
at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityMan
agerImpl.java:1387)
at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityMan
agerImpl.java:1310)
at org.hibernate.ejb.AbstractEntityManagerImpl.throwPersistenceException
(AbstractEntityManagerImpl.java:1397)
at org.hibernate.ejb.TransactionImpl.begin(TransactionImpl.java:62)
at play.db.jpa.JPA.withTransaction(JPA.java:230)
at play.db.jpa.JPA.withinFilter(JPA.java:195)
at play.db.jpa.JPAPlugin$TransactionalFilter.withinFilter(JPAPlugin.java
:299)
at play.Invoker$Invocation.withinFilter(Invoker.java:272)
at play.Invoker$Invocation.run(Invoker.java:289)
... 1 more
Caused by: org.hibernate.exception.GenericJDBCException: Could not open connecti
on
at org.hibernate.exception.internal.StandardSQLExceptionConverter.conver
t(StandardSQLExceptionConverter.java:54)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlException
Helper.java:124)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlException
Helper.java:109)
at org.hibernate.engine.jdbc.internal.LogicalConnectionImpl.obtainConnec
tion(LogicalConnectionImpl.java:221)
at org.hibernate.engine.jdbc.internal.LogicalConnectionImpl.getConnectio
n(LogicalConnectionImpl.java:157)
at org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.doBegi
n(JdbcTransaction.java:67)
at org.hibernate.engine.transaction.spi.AbstractTransactionImpl.begin(Ab
stractTransactionImpl.java:160)
at org.hibernate.internal.SessionImpl.beginTransaction(SessionImpl.java:
1351)
at org.hibernate.ejb.TransactionImpl.begin(TransactionImpl.java:59)
... 6 more
Caused by: java.sql.SQLException: An attempt by a client to checkout a Connectio
n has timed out.
at com.mchange.v2.sql.SqlUtils.toSQLException(SqlUtils.java:118)
at com.mchange.v2.sql.SqlUtils.toSQLException(SqlUtils.java:77)
at org.hibernate.service.jdbc.connections.internal.DatasourceConnectionP
roviderImpl.getConnection(DatasourceConnectionProviderImpl.java:141)
at org.hibernate.internal.AbstractSessionImpl$NonContextualJdbcConnectio
nAccess.obtainConnection(AbstractSessionImpl.java:301)
at org.hibernate.engine.jdbc.internal.LogicalConnectionImpl.obtainConnec
tion(LogicalConnectionImpl.java:214)
... 11 more
Caused by: com.mchange.v2.resourcepool.TimeoutException: A client timed out whil
e waiting to acquire a resource from com.mchange.v2.resourcepool.BasicResourcePo
ol@1cb35c -- timeout at awaitAvailable()
at com.mchange.v2.resourcepool.BasicResourcePool.awaitAvailable(BasicRes
ourcePool.java:1461)
at com.mchange.v2.resourcepool.BasicResourcePool.prelimCheckoutResource(
BasicResourcePool.java:639)
at com.mchange.v2.resourcepool.BasicResourcePool.checkoutResource(BasicR
esourcePool.java:549)
... 14 more
I found some information about it: http://ift.tt/1KLNt95
The
JPA.em()method gets the current entity manager that's associated with the thread, it's intended for use with the@Transactionalannotation. It will get whichever entity manager the annotation says, so if you say@Transactional(value = "mydb"), it will get themydbentity manager. The@Transactionalannotation manages these for you, so that's why there's no leak when you use theem()method.
JPA.em(String)however does not get the entity manager from the thread, it always gets a new entity manager, hence you need to make sure that you clean it up by callingem.close()when you're finished with it (usually in afinallyblock).
Do I need to use @Transactional annotation in Play Framework-1.x to prevent the connection leak? And when I don't explicitly specifying entity manager? For example:
...
public static void update() {
Contact contact = new Contact ();
contact.FirstName = jsonContact.FirstName;
contact.LastName = jsonContact.LastName;
contact.Birthday = jsonContact.Birthday;
contact.Email = jsonContact.Email;
contact.Phone = jsonContact.Phone;
contact.Comment = jsonContact.Comment;
contact.save();
renderJSON(contact);
}
...
I would be very grateful for the information. Thanks to all.
Aucun commentaire:
Enregistrer un commentaire