访问PostgreSQL数据库的JDBC驱动程序有哪些替代方案?

7
我正在使用官方的PostgreSQL JDBC驱动程序,但我遇到了以下问题:
  • 不支持PostgreSQL-ish数据结构,如UUID。
  • 常见的JDBC怪异行为,例如:
    • 没有用于消费PostgreSQL的值的转义函数。
    • 有限的批量执行异构语句的支持。
    • 在向一个表中插入多行时,没有将多个插入语句重写为单个插入语句。
所以问题是 - 是否有任何PostgreSQL数据库驱动程序可以充分利用PostgreSQL的全部功能而不需要太多样板代码?我还使用Scala语言进行开发,因此,如果驱动程序专门为Scala设计,那就太棒了。

7
使用 PreparedStatement 并在其中设置值来处理任何需要转义的内容,批量更新无法用于插入多行数据吗? - ColinD
你的意思是什么:没有用于转义值以供消费的函数 - user330315
@ColinD 对于同质语句来说没问题,但我还需要批量执行异构语句,而Statement.addBatch只能接受SQL语句作为字符串,不能作为另一个语句。 - andreypopp
@a_horse_with_no_name 将 "I'm" 转义为 E'I'm'。请参考上面的评论,了解我为什么需要这种功能。 - andreypopp
1
@andreypopp:就批处理的事情,我真的不知道你想做什么,至于字符串转义... PreparedStatement.setString 应该为您处理任何转义。这就是重点。 - ColinD
1
@andreypopp:转义单引号正是 PreparedStatement 会为您做的事情。关于 addBatch():如果您已经有不同的语句(例如不同的表),那么我不明白您所说的“异构语句”的含义,因为您将无法利用 PostgreSQL 的多行插入功能。 - user330315
6个回答

10

这里似乎有一些(除非我理解不正确)使用JDBC时用户错误的问题。JDBC是一个相当丑陋的API,所以永远不要问是否可以优雅地完成它,只需问是否可以完成。

转义和插入多行应该使用预处理语句和批量操作来处理,正如@ColinD和@a_horse所指出的那样。在底层,我期望良好的JDBC实现能够做到您想要的事情(我对PostgreSQL的实现不熟悉)。

关于UUID,这里有一个解决方案:

All that PostgreSQL can do is convert string literals to uuid.

You can make use of this by using the data type org.postgresql.util.PGobject, which is a general class used to represent data types unknown to JDBC.

You can define a helper class:

public class UUID extends org.postgresql.util.PGobject {
    public static final long serialVersionUID = 668353936136517917L;
    public UUID(String s) throws java.sql.SQLException {
        super();
        this.setType("uuid");
        this.setValue(s);
    }
}

Then the following piece of code will succeed:

 java.sql.PreparedStatement stmt =
 conn.prepareStatement("UPDATE t SET uid = ? WHERE id = 1");
 stmt.setObject(1, new UUID("a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11"));
 stmt.executeUpdate();

感谢您提供注册自己类型句柄的示例,但是其他问题对我来说仍然没有解决。 - andreypopp

4
该驱动程序支持批处理语句以加速大量插入。
而使用批处理语句比使用专有的INSERT语法更具可移植性(据我所知,多行插入和批处理插入之间没有什么大的区别)。
请查看PreparedStatement.addBatch()。
UUID不受支持的原因可能是UUID不是Postgres核心的一部分,仅是一个contrib模块。
编辑: 关于执行异构语句
Postgres驱动程序确实支持在批处理中使用不同类型的语句。
以下代码可以正常工作:
Connection con = DriverManager.getConnection("jdbc:postgresql://localhost/postgres", "foo", "bar");
con.setAutoCommit(false);
Statement stmt = con.createStatement();
stmt.addBatch("create table foo (id integer, data varchar(100))");
stmt.addBatch("insert into foo values (1, 'one')");
stmt.addBatch("insert into foo values (2, 'two')");
stmt.addBatch("update foo set data = 'one_other' where id = 1");
stmt.executeBatch();
con.commit();

虽然您会失去PreparedStatement自动转义的功能。


但是,我还需要使用UUID进行工作,这就是我询问其他PostgreSQL驱动程序是否存在的原因。 - andreypopp

3
我知道这并不能完全回答你的问题,但希望它仍然有用。
我使用的是Java 6和Postgres 8.4。我在我的Maven POM文件中使用的驱动程序是:
<dependency>
    <groupId>postgresql</groupId>
    <artifactId>postgresql</artifactId>
    <version>8.4-702.jdbc4</version>
</dependency>

我正在使用Java的java.util.UUID类以及PreparedStatement.getObject()PreparedStatement.setObject()方法,用于检索和存储UUID。

例如:

pstm.setObject(1, guid); //where pstm is a PreparedStatement and guid is a UUID

并且:

//where rs is a ResultSet
UUID myGuid = (UUID) rs.getObject("my_uuid_column_name"); 

运行良好。

使用更新的驱动程序,以下内容也得到了支持

UUID myGuid = rs.getObject("my_uuid_column_name", UUID.class); 

我注意到Postgres JDBC驱动程序似乎通过getObject()setObject()方法支持java.util.UUID。这个有文档记录吗? - Lukas Eder

1
没有对类似于UUID的PostgreSQL数据结构提供支持。
相反,当前JDBC驱动程序(9.2-1002 JDBC 4)对Postgres 9.x确实通过setObjectgetObject命令支持UUID。在任何数据库中(包括Postgres或其他数据库),这已经是最直接和简单的方式,因为JDBC不将UUID识别为数据类型。
据我所知,不需要像Yishai的另一个答案中建议的那样创建帮助类。
无需进行任何转换或字符串处理。

enter image description here

请查看我的博客文章,了解更多讨论和代码示例。

代码示例摘录:

java.util.UUID uuid = java.util.UUID.randomUUID();
…
preparedStatement.setObject( nthPlaceholder++, uuid ); // Pass UUID to database.

太好了,但它似乎并不总是有效:https://dev59.com/12Ml5IYBdhLWcg3w_bDj - user340535
@user340535 很遗憾,你提供的那个问题毫无用处。没有提供源代码、细节或上下文,因此无法得出结论。另一方面,你可以运行我在这个答案和我的博客文章中发布的源代码。它一直稳定地运行,没有任何问题。 - Basil Bourque

0

0

看一下O/R Broker,它是一个基于Scala JDBC的库,用于关系型数据库访问。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接