Wrong JDBC driver being used?

做~自己de王妃 提交于 2020-01-11 06:04:31

问题


I have a method that inserts a record into a Postgres DB and returns the identity field generated for said record. The problem is, if I include the Redshift driver in my POM file, that driver is getting used instead of the Postgres driver - and the Redshift driver doesn't allow returning the identity value.

The code is:

try {
  Class.forName( "org.postgresql.Driver" ).newInstance();
  Connection connection = DriverManager.getConnection( "jdbc:postgresql://localhost:5433/postgres", "postgres", "password" );
  Statement stmt = connection.createStatement();
  stmt.execute( "insert into public.job ( job_name ) values ( 'test' )" , Statement.RETURN_GENERATED_KEYS );
  ResultSet keyset = stmt.getGeneratedKeys();
  if ( keyset.next() ) System.out.println( keyset.getLong( 1 ) );
}
catch ( Exception e ) {
  e.printStackTrace();
}

When this POM is used, it works:

<dependencies>
    <dependency>
        <groupId>org.postgresql</groupId>
        <artifactId>postgresql</artifactId>
        <version>9.4-1201-jdbc41</version>
    </dependency>
</dependencies>

When this POM is used, it does not work:

<dependencies>
    <dependency>
        <groupId>com.amazonaws</groupId>
        <artifactId>redshift.jdbc</artifactId>
        <version>1.1.2.0002</version>
    </dependency>
    <dependency>
        <groupId>org.postgresql</groupId>
        <artifactId>postgresql</artifactId>
        <version>9.4-1201-jdbc41</version>
    </dependency>
</dependencies>

What is making Java choose the Redshift driver rather than the Postgres driver?

(the Redshift driver's classpath is com.amazon.jdbc41.Driver, so I wouldn't think it's a classpath conflict)

TIA


回答1:


Your problem is, that Java supports the ServiceLoader mechanism with JDBC 4.0.

In JDBC 4, the DriverManager will find and register drivers from the META-INF/services/java.sql.Driver setting in their jar file. When you call getConnection() the DriverManager will choose the first suitable driver for the jdbc URL given.

Now redshift and postgres driver are different in terms of jdbc url, but (quoting from the redshift docs http://docs.aws.amazon.com/redshift/latest/mgmt/configure-jdbc-connection.html#obtain-jdbc-url):

A JDBC URL specified with the former format of jdbc:postgresql://endpoint:port/database will still work.

Now, what happens, is, that the JDBC driver from redshift is loaded over the service entry and places himself as the driver for the redshift jdbc URL and the postgres one.

I cannot tell exactly if the DriverManager allows overwriting existing jdbc-driver-links by loading another driver, but a solution to your problem could be the explicit control to either load the postgres driver first (if URL will be registered only once) or to explicitly load it after the redshift driver (if JDBC URL mapping can be overwritten).

I cannot tell, if there is a property to disallow the redshift driver to register for the postgres URL.




回答2:


The only way I've been able to get the drivers to load consistently in the right order was to add:

static {
    // Put the redshift driver at the end so that it doesn't
    // conflict with postgres queries
    java.util.Enumeration<Driver> drivers =  DriverManager.getDrivers();
    while (drivers.hasMoreElements()) {
        Driver d = drivers.nextElement();
        if (d.getClass().getName().equals("com.amazon.redshift.jdbc41.Driver")) {
            try {
                DriverManager.deregisterDriver(d);
                DriverManager.registerDriver(d);
            } catch (SQLException e) {
                throw new RuntimeException("Could not deregister redshift driver");
            }
            break;
        }
    }
}

Which is pretty gross, but does the job.




回答3:


As commented below PGDatasource uses DriverManger too, but it is possible directly create org.postgresql.jdbc4.Jdbc4Connection:

Properties info = new Properties();
info.put("password", "postgres");
Jdbc4Connection c = new Jdbc4Connection(new HostSpec[]{new HostSpec("localhost", 5432)}, "postgres", "postgres", info, "");


来源:https://stackoverflow.com/questions/31304195/wrong-jdbc-driver-being-used

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!