Java 使用了错误的JDBC驱动程序?

Java 使用了错误的JDBC驱动程序?,java,jdbc,postgresql-9.3,Java,Jdbc,Postgresql 9.3,我有一个方法,可以将一条记录插入Postgres数据库,并返回为该记录生成的标识字段。问题是,如果我在POM文件中包含红移驱动程序,那么将使用该驱动程序而不是Postgres驱动程序,并且红移驱动程序不允许返回标识值 代码是: try { Class.forName( "org.postgresql.Driver" ).newInstance(); Connection connection = DriverManager.getConnection( "jdbc:postgresql:

我有一个方法,可以将一条记录插入Postgres数据库,并返回为该记录生成的标识字段。问题是,如果我在POM文件中包含红移驱动程序,那么将使用该驱动程序而不是Postgres驱动程序,并且红移驱动程序不允许返回标识值

代码是:

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();
}
使用此POM时,其工作原理如下:

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

org.postgresql
postgresql
9.4-1201-jdbc41
使用此POM时,它不起作用:

<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>

亚马逊网站
redshift.jdbc
1.1.2.0002
org.postgresql
postgresql
9.4-1201-jdbc41
是什么让Java选择红移驱动程序而不是Postgres驱动程序

(红移驱动程序的类路径是com.amazon.jdbc41.driver,因此我认为这不是类路径冲突)


TIA

您的问题是,Java支持JDBC4.0的
ServiceLoader
机制

在JDBC4中,
DriverManager
将从其jar文件中的
META-INF/services/java.sql.Driver
设置中查找并注册驱动程序。调用
getConnection()
时,DriverManager将为给定的jdbc URL选择第一个合适的驱动程序

现在红移和postgres驱动程序在JDBCURL方面有所不同,但是(引用红移文档):

使用以前的JDBC:p格式指定的JDBC URLostgresql://endpoint:port/database 仍然有效

现在,发生的事情是,来自redshift的JDBC驱动程序被加载到服务条目上,并将自己作为redshift JDBC URL和postgres URL的驱动程序

我不能确切地说,
DriverManager
是否允许通过加载另一个驱动程序来覆盖现有的jdbc驱动程序链接,但解决问题的方法是使用显式控件,首先加载postgres驱动程序(如果URL只注册一次),或者在红移驱动程序之后显式加载它(如果可以覆盖JDBC URL映射)


我不知道是否存在禁止红移驱动程序注册postgres URL的属性。

我能够让驱动程序以正确的顺序一致加载的唯一方法是添加:

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;
        }
    }
}
静态{
//将红移驱动程序放在末端,这样它就不会
//与postgres查询冲突
java.util.Enumeration drivers=DriverManager.getDrivers();
while(drivers.hasMoreElements()){
Driver d=drivers.nextElement();
if(d.getClass().getName().equals(“com.amazon.redshift.jdbc41.Driver”)){
试一试{
DriverManager.deregisterDriver(d);
登记的司机经理(d);
}捕获(SQLE异常){
抛出新的RuntimeException(“无法注销红移驱动程序”);
}
打破
}
}
}

这很糟糕,但确实起到了作用。

如下文所述,PGDatasource也使用DriverManager,但可以直接创建
org.postgresql.jdbc4.jdbc4连接

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

我已经打开了驱动程序jar,至少在当前版本中,没有包名冲突。JDBCURL冲突(我想)是一种“方便”功能,只需使用旧的URL,放入新的jar并使用新的驱动程序。否则我不想在这里作出判断,因为OP只是问了为什么会发生这种情况。感谢thst为我指明了正确的方向。解决方案(到目前为止)是调用DriverManager.deregisterDriver().看起来像是一个难题,但在我找到更好的方法之前,它会让我重新开始。谢谢!如果你不想使用红移驱动程序,为什么要包括它?我们尝试过这个,但是PGPoolgDataSource在幕后使用DriverManager,所以结果是一样的。请参阅