P6SpyDriver cannot be cast to javax.sql.XADataSour

2019-07-20 12:30发布

问题:

P6spy v2 has a support for xa datasources - P6spy on github

In my jboss AS 7 standalone-full-ha.xml, i have the following datasource configurations.

<xa-datasource jndi-name="java:jboss/datasources/MyDS" pool-name="v" enabled="true" use-java-context="true" use-ccm="false">
                <xa-datasource-property name="ServerName">
                    localhost
                </xa-datasource-property>
                <xa-datasource-property name="PortNumber">
                    5432
                </xa-datasource-property>
                <xa-datasource-property name="DatabaseName">
                    MyDB
                </xa-datasource-property>
                <driver>p6spy</driver>
                <xa-pool>
                    <min-pool-size>50</min-pool-size>
                    <max-pool-size>150</max-pool-size>
                    <is-same-rm-override>false</is-same-rm-override>
                    <interleaving>false</interleaving>
                    <pad-xid>false</pad-xid>
                    <wrap-xa-resource>false</wrap-xa-resource>
                </xa-pool>
                <security>
                    <user-name>postgres</user-name>
                    <password>postgres</password>
                </security>
                <validation>
                    <validate-on-match>false</validate-on-match>
                    <background-validation>false</background-validation>
                </validation>
                <statement>
                    <share-prepared-statements>false</share-prepared-statements>
                </statement>
            </xa-datasource>
            <drivers>
                <driver name="h2" module="com.h2database.h2">
                    <xa-datasource-class>org.h2.jdbcx.JdbcDataSource</xa-datasource-class>
                </driver>
                <driver name="postgresql" module="org.postgresql">
                    <xa-datasource-class>org.postgresql.xa.PGXADataSource</xa-datasource-class>
                </driver>
                <driver name="p6spy" module="com.p6spy">
                    <xa-datasource-class>com.p6spy.engine.spy.P6SpyDriver</xa-datasource-class>
                </driver>
            </drivers>

After that, i put the p6spy-2.0.1.jar in jboss\modules\com\p6spy\main folder and also defined the module.xml file. Also, i put the spy.properties file alongwith the P6spy.jar and in that added the line to enable postgres driver

realdriver=org.postgresql.Driver

With all these settings, when i start my server, i get the following exception.

    Throwable while attempting to get a new connection: null: javax.resource.ResourceException: Could not create connection
    at org.jboss.jca.adapters.jdbc.xa.XAManagedConnectionFactory.getXAManagedConnection(XAManagedConnectionFactory.java:447)
    at org.jboss.jca.adapters.jdbc.xa.XAManagedConnectionFactory.createManagedConnection(XAManagedConnectionFactory.java:385)
    at org.jboss.jca.core.connectionmanager.pool.mcp.SemaphoreArrayListManagedConnectionPool.createConnectionEventListener(SemaphoreArrayListManagedConnectionPool.java:761)
    at org.jboss.jca.core.connectionmanager.pool.mcp.SemaphoreArrayListManagedConnectionPool.getConnection(SemaphoreArrayListManagedConnectionPool.java:343)
    at org.jboss.jca.core.connectionmanager.pool.AbstractPool.getSimpleConnection(AbstractPool.java:397)
    at org.jboss.jca.core.connectionmanager.pool.AbstractPool.getConnection(AbstractPool.java:365)
    at org.jboss.jca.core.connectionmanager.AbstractConnectionManager.getManagedConnection(AbstractConnectionManager.java:329)
    at org.jboss.jca.core.connectionmanager.tx.TxConnectionManagerImpl.getManagedConnection(TxConnectionManagerImpl.java:368)
    at org.jboss.jca.core.connectionmanager.AbstractConnectionManager.allocateConnection(AbstractConnectionManager.java:464)
    at org.jboss.jca.adapters.jdbc.WrapperDataSource.getConnection(WrapperDataSource.java:129)
    at org.hibernate.ejb.connection.InjectedDataSourceConnectionProvider.getConnection(InjectedDataSourceConnectionProvider.java:67) [hibernate-entitymanager-4.0.1.Final.jar:4.0.1.Final]
    at org.hibernate.engine.jdbc.internal.JdbcServicesImpl$ConnectionProviderJdbcConnectionAccess.obtainConnection(JdbcServicesImpl.java:253) [hibernate-core-4.0.1.Final.jar:4.0.1.Final]
    at org.hibernate.engine.jdbc.internal.JdbcServicesImpl.configure(JdbcServicesImpl.java:119) [hibernate-core-4.0.1.Final.jar:4.0.1.Final]
    at org.hibernate.service.internal.StandardServiceRegistryImpl.configureService(StandardServiceRegistryImpl.java:75) [hibernate-core-4.0.1.Final.jar:4.0.1.Final]
    at org.hibernate.service.internal.AbstractServiceRegistryImpl.initializeService(AbstractServiceRegistryImpl.java:159) [hibernate-core-4.0.1.Final.jar:4.0.1.Final]
    at org.hibernate.service.internal.AbstractServiceRegistryImpl.getService(AbstractServiceRegistryImpl.java:131) [hibernate-core-4.0.1.Final.jar:4.0.1.Final]
    at org.hibernate.cfg.SettingsFactory.buildSettings(SettingsFactory.java:71) [hibernate-core-4.0.1.Final.jar:4.0.1.Final]
    at org.hibernate.cfg.Configuration.buildSettingsInternal(Configuration.java:2270) [hibernate-core-4.0.1.Final.jar:4.0.1.Final]
    at org.hibernate.cfg.Configuration.buildSettings(Configuration.java:2266) [hibernate-core-4.0.1.Final.jar:4.0.1.Final]
    at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1735) [hibernate-core-4.0.1.Final.jar:4.0.1.Final]
    at org.hibernate.ejb.EntityManagerFactoryImpl.<init>(EntityManagerFactoryImpl.java:84) [hibernate-entitymanager-4.0.1.Final.jar:4.0.1.Final]
    at org.hibernate.ejb.Ejb3Configuration.buildEntityManagerFactory(Ejb3Configuration.java:904) [hibernate-entitymanager-4.0.1.Final.jar:4.0.1.Final]
    at org.hibernate.ejb.Ejb3Configuration.buildEntityManagerFactory(Ejb3Configuration.java:889) [hibernate-entitymanager-4.0.1.Final.jar:4.0.1.Final]
    at org.hibernate.ejb.HibernatePersistence.createContainerEntityManagerFactory(HibernatePersistence.java:73) [hibernate-entitymanager-4.0.1.Final.jar:4.0.1.Final]
    at org.jboss.as.jpa.service.PersistenceUnitServiceImpl.createContainerEntityManagerFactory(PersistenceUnitServiceImpl.java:162) [jboss-as-jpa-7.1.1.Final.jar:7.1.1.Final]
    at org.jboss.as.jpa.service.PersistenceUnitServiceImpl.start(PersistenceUnitServiceImpl.java:85) [jboss-as-jpa-7.1.1.Final.jar:7.1.1.Final]
    at org.jboss.msc.service.ServiceControllerImpl$StartTask.startService(ServiceControllerImpl.java:1811)
    at org.jboss.msc.service.ServiceControllerImpl$StartTask.run(ServiceControllerImpl.java:1746)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) [rt.jar:1.7.0_40]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) [rt.jar:1.7.0_40]
    at java.lang.Thread.run(Thread.java:724) [rt.jar:1.7.0_40]
Caused by: java.lang.ClassCastException: com.p6spy.engine.spy.P6SpyDriver cannot be cast to javax.sql.XADataSource
    at org.jboss.jca.adapters.jdbc.xa.XAManagedConnectionFactory.getXADataSource(XAManagedConnectionFactory.java:553)
    at org.jboss.jca.adapters.jdbc.xa.XAManagedConnectionFactory.getXAManagedConnection(XAManagedConnectionFactory.java:430)
    ... 30 more

At this step i am clueless as to how should i make it work.

Edit: As per quintonm's reply, i used com.p6spy.engine.spy.P6ConnectionPoolDataSource class which implements XADatasource. But now i am getting the following exception.

Caused by: javax.resource.ResourceException: Could not find accessor on XADataSource: 
    at org.jboss.jca.adapters.jdbc.xa.XAManagedConnectionFactory.getXADataSource(XAManagedConnectionFactory.java:629)
    at org.jboss.jca.adapters.jdbc.xa.XAManagedConnectionFactory.getXAManagedConnection(XAManagedConnectionFactory.java:430)
    ... 30 more
Caused by: java.lang.NoSuchMethodException: com.p6spy.engine.spy.P6ConnectionPoolDataSource.setDatabaseName(java.lang.String)
    at java.lang.Class.getMethod(Class.java:1655) [rt.jar:1.7.0_40]
    at org.jboss.jca.adapters.jdbc.xa.XAManagedConnectionFactory.getXADataSource(XAManagedConnectionFactory.java:597)

Also, following the generic instructions stated in P6spy's documentation, i used the 'RealDataSource' property in xa-datasource-properties but it then says no such property exist.

回答1:

The problem that you are currently facing is that JBoss is expecting you to use a class that implements the Datasource interface in xa-datasource-class. For the P6Spy driver definition, you are using P6SpyDriver which implements java.sql.Driver. Instead of using P6SpyDriver, you want to use com.p6spy.engine.spy.P6ConnectionPoolDataSource.

P6Spy's support for DataSource implementations in JNDI is a little different than using a Driver class. Instead of modifying the JDBC URL, you must setup a second JDNI DataSource. The one that the application connects to will be the P6Spy DataSource. That DataSource will be a proxy to the real data source. The instructions for setting this up are be found here.

Note: The instructions say that you should use P6DataSource. However, since you need XA support, you will need to use P6ConnectionPoolDataSource.

For a better understanding of how this works, you can take a look at the test for XADataSources - XADataSourceTest

If you have any problems getting this to work, just post a message to p6spy-users@googlegroups.com or enter an issue



回答2:

well, after the update of the question, your config should look like this. Didn't give it a test try, but in general, you need to proxy your existing one (postgres one) via p6spy:

<xa-datasource jndi-name="java:jboss/datasources/MyDSReal" pool-name="v" enabled="true" use-java-context="true" use-ccm="false">
            <xa-datasource-property name="ServerName">
                localhost
            </xa-datasource-property>
            <xa-datasource-property name="PortNumber">
                5432
            </xa-datasource-property>
            <xa-datasource-property name="DatabaseName">
                MyDB
            </xa-datasource-property>
            <driver>postgresql</driver>
            <xa-pool>
                <min-pool-size>50</min-pool-size>
                <max-pool-size>150</max-pool-size>
                <is-same-rm-override>false</is-same-rm-override>
                <interleaving>false</interleaving>
                <pad-xid>false</pad-xid>
                <wrap-xa-resource>false</wrap-xa-resource>
            </xa-pool>
            <security>
                <user-name>postgres</user-name>
                <password>postgres</password>
            </security>
            <validation>
                <validate-on-match>false</validate-on-match>
                <background-validation>false</background-validation>
            </validation>
            <statement>
                <share-prepared-statements>false</share-prepared-statements>
            </statement>
        </xa-datasource>
<xa-datasource jndi-name="java:jboss/datasources/MyDS" pool-name="v" enabled="true" use-java-context="true" use-ccm="false">
            <driver>p6spy</driver>
            <xa-pool>
                <min-pool-size>50</min-pool-size>
                <max-pool-size>150</max-pool-size>
                <is-same-rm-override>false</is-same-rm-override>
                <interleaving>false</interleaving>
                <pad-xid>false</pad-xid>
                <wrap-xa-resource>false</wrap-xa-resource>
            </xa-pool>
            <security>
                <user-name>postgres</user-name>
                <password>postgres</password>
            </security>
            <validation>
                <validate-on-match>false</validate-on-match>
                <background-validation>false</background-validation>
            </validation>
            <statement>
                <share-prepared-statements>false</share-prepared-statements>
            </statement>
        </xa-datasource>

        <drivers>
            <driver name="h2" module="com.h2database.h2">
                <xa-datasource-class>org.h2.jdbcx.JdbcDataSource</xa-datasource-class>
            </driver>
            <driver name="postgresql" module="org.postgresql">
                <xa-datasource-class>org.postgresql.xa.PGXADataSource</xa-datasource-class>
            </driver>
            <driver name="p6spy" module="com.p6spy">
                <xa-datasource-class>com.p6spy.engine.spy.P6ConnectionPoolDataSource</xa-datasource-class>
            </driver>
        </drivers>

Moreover I think you don't need spy.properties file if you're OK with default config. As RealDriver property would be needed if going the driver way (not the datasource one as you do now).

UPDATE:

removed section reported as problematic:

            <xa-datasource-property name="RealDataSource">
                java:jboss/datasources/MyDSReal
            </xa-datasource-property>                

if that is a problem in the DS config => let's configure it in a different way, you can go for any of available:

  • System properties
  • Environment variables or
  • spy.properties

where you need to set:

realdatasource=java:jboss/datasources/MyDSReal

UPDATE 2:

I gave it a test try and it seems p6spy doesn't support the XA Datasources for the JBoss / Wildfly (yet). For more details, see the official docs: http://p6spy.github.io/p6spy/2.0/install.html