[ 
https://issues.apache.org/jira/browse/OPENJPA-2904?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Pawel Veselov updated OPENJPA-2904:
-----------------------------------
    Description: 
We have some custom code that we use to get the underlying connection object 
from OpenJPA.

At first we were doing this:
{code:java}
    public Connection getRawConnection(EntityManager em) {
        OpenJPAEntityManager oem = OpenJPAPersistence.cast(em);
        return (Connection) oem.getConnection();
    }
{code}

But sometimes we need the connection object before the entity manager has been 
otherwise used in any way. And the transaction of this connection should match 
the one created by JPA. So we changed this to:

{code:java}
    public Connection getRawConnection(EntityManager em) {
        OpenJPAEntityManager oem = OpenJPAPersistence.cast(em);
        oem.beginStore();
        return (Connection) oem.getConnection();
    }
{code}

This sometimes fails with an NPE if the connection object hasn't been 
initialized yet. So we changed this to:

But sometimes we need the connection object before the entity manager has been 
otherwise used in any way. And the transaction of this connection should match 
the one created by JPA. So we changed this to:

{code:java}
    public Connection getRawConnection(EntityManager em) {
        OpenJPAEntityManager oem = OpenJPAPersistence.cast(em);
        oem.getConnection();
        oem.beginStore();
        return (Connection) oem.getConnection();
    }
{code}

This, however, has an interesting side-effect. The returned 
{{JDBCStoreManager.ClientConnection}} class seems to be quickly GCed, which 
makes it close the underlying connection. In essence, calling 
{{oem.getConnection}} is bad unless the connection is retained, it really 
messes things up (see comment for the stack traces)

We've now again changed this to:

{code:java}
    public Connection getRawConnection(EntityManager em) {
        OpenJPAEntityManager oem = OpenJPAPersistence.cast(em);
        Connection c = (Connection)oem.getConnection();
        oem.beginStore();
        return c;
    }
{code}

This should work now, but the possibility that {{getConnection()}} actually 
results in a connection closure is probably bad.


  was:
(looking at commit 05069dfee, but this code hasn't changed in ages).

There is a number of methods that chain to {{JDBCStore.getClientConnection()}}
* {{StoreManager.getClientConnection()}}
* {{StoreContext.getConnection()}}
* {{OpenJPAEntityManager.getConnection()}}
* {{EntityManagerImpl.unwrap()}}

Callers of these methods typically use the retrieved connection object for an 
operation, and then let go of it, without any cleanup (as they are supposed to).

However, {{JDBCStore.getClientConnection()}} implementation creates an instance 
of {{JDBCStoreManager.ClientConnection}} class every time it's called. These 
instances, considering how they are used, are therefore short-lived

However, the implementation {{JDBCStoreManager.ClientConnection}} closes the 
underlying connection object on finalization.

This has a relatively high chance of having the underlying connection closed 
before it's actually properly released.

I don't necessarily know what the right fix for this is, but locally I will 
just make ClientConnection a field of RefCountConnection, it's a lightweight 
class so I can create it right away, then I'll have 
{{JDBCStore.getClientConnection()}} just return that. There may be some gotchas 
there, but I just need a quick solution because this suddenly became a 
persistent problem.

I've overridden the pooled connection implementation to try to trace the 
connection random connection closure that we are experiencing under some random 
scenarios, and I attached an exception to the connection object when it's 
closed, and I see when an attempt to use a closed connection happens - it's 
because the GC closed it through {{JDBCStoreManager.ClientConnection}}.



> OpenJPAEntityManager.getConnection() may lead to sudden connection closure
> --------------------------------------------------------------------------
>
>                 Key: OPENJPA-2904
>                 URL: https://issues.apache.org/jira/browse/OPENJPA-2904
>             Project: OpenJPA
>          Issue Type: Bug
>    Affects Versions: 3.2.0, 3.2.1, 3.2.2
>            Reporter: Pawel Veselov
>            Priority: Minor
>
> We have some custom code that we use to get the underlying connection object 
> from OpenJPA.
> At first we were doing this:
> {code:java}
>     public Connection getRawConnection(EntityManager em) {
>         OpenJPAEntityManager oem = OpenJPAPersistence.cast(em);
>         return (Connection) oem.getConnection();
>     }
> {code}
> But sometimes we need the connection object before the entity manager has 
> been otherwise used in any way. And the transaction of this connection should 
> match the one created by JPA. So we changed this to:
> {code:java}
>     public Connection getRawConnection(EntityManager em) {
>         OpenJPAEntityManager oem = OpenJPAPersistence.cast(em);
>         oem.beginStore();
>         return (Connection) oem.getConnection();
>     }
> {code}
> This sometimes fails with an NPE if the connection object hasn't been 
> initialized yet. So we changed this to:
> But sometimes we need the connection object before the entity manager has 
> been otherwise used in any way. And the transaction of this connection should 
> match the one created by JPA. So we changed this to:
> {code:java}
>     public Connection getRawConnection(EntityManager em) {
>         OpenJPAEntityManager oem = OpenJPAPersistence.cast(em);
>         oem.getConnection();
>         oem.beginStore();
>         return (Connection) oem.getConnection();
>     }
> {code}
> This, however, has an interesting side-effect. The returned 
> {{JDBCStoreManager.ClientConnection}} class seems to be quickly GCed, which 
> makes it close the underlying connection. In essence, calling 
> {{oem.getConnection}} is bad unless the connection is retained, it really 
> messes things up (see comment for the stack traces)
> We've now again changed this to:
> {code:java}
>     public Connection getRawConnection(EntityManager em) {
>         OpenJPAEntityManager oem = OpenJPAPersistence.cast(em);
>         Connection c = (Connection)oem.getConnection();
>         oem.beginStore();
>         return c;
>     }
> {code}
> This should work now, but the possibility that {{getConnection()}} actually 
> results in a connection closure is probably bad.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to