使用Java连接到PostgreSQL数据库
首先
由于最近接触各种程序连接到PostgreSQL的机会增多,所以我整理了一下步骤。
由于篇幅较长,本次将尝试连接Java和PostgreSQL。
此外,本文包含了在12/16(六)举办的PostgreSQL非官方会议上的演讲内容。
当天的资料可以在这里查看。
[2018/11/20更新]
我已经发布了一篇关于C#的文章,对当天公布的内容做了一些额外的补充。
如果您想了解有关C#连接方法的信息,请参阅那篇文章。
[2019/2/20修正及追加]
感謝@takuya-fujiwara提供的评论,我修改了JDBC驱动程序的加载部分。
非常感谢您的指正。
关于修正的详细信息,请参阅追加内容。
连接Java到PostgreSQL。
-
- 環境情報
OS:Windows 10
PostgreSQL: 10.1
Java:1.8
JDBC:4.2
首先,假设PostgreSQL和Java的环境已经安装好。
要从Java连接到PostgreSQL,首先需要获取PostgreSQL的JDBC驱动程序。
-
- PostgreSQL JDBC Driver
- https://jdbc.postgresql.org/download.html
在Eclipse中,右键单击要创建的项目并选择”构建路径” -> “配置构建路径”。
然后,在”库”选项卡中选择”添加外部JAR”,并添加从上述来源获取的PostgreSQL JDBC。
然后,我写下了以下代码以连接到PostgreSQL。
作为测试,我们将执行SELECT和INSERT语句的事务。
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class Sample_pos_conn {
public static void main(String[] args) {
Connection conn = null;
Statement stmt = null;
ResultSet rset = null;
//接続文字列
String url = "jdbc:postgresql://123.45.67.89:5432/postgres";
String user = "postgres";
String password = "password";
try{
//PostgreSQLへ接続
conn = DriverManager.getConnection(url, user, password);
//自動コミットOFF
conn.setAutoCommit(false);
//SELECT文の実行
stmt = conn.createStatement();
String sql = "SELECT 1";
rset = stmt.executeQuery(sql);
//SELECT結果の受け取り
while(rset.next()){
String col = rset.getString(1);
System.out.println(col);
}
//INSERT文の実行
sql = "INSERT INTO jdbc_test VALUES (1, 'AAA')";
stmt.executeUpdate(sql);
conn.commit();
}
catch (SQLException e){
e.printStackTrace();
}
finally {
try {
if(rset != null)rset.close();
if(stmt != null)stmt.close();
if(conn != null)conn.close();
}
catch (SQLException e){
e.printStackTrace();
}
}
}
}
我会依次解释上面代码中的关键部分。
连接至PostgreSQL数据库
明确指定要连接的数据库。
这是连接到PostgreSQL的情况(字符串中包含了“postgres”之类的)。
因此,如果要连接其他数据库,字符串当然是不同的。
换句话说,只要重新解释连接相关字符串,对于相同的RDBMS,可以用JDBC做的事情和行为是类似的。
链接字符串
String url = "jdbc:postgresql://<接続先DBサーバのIP or ホスト名>:<DBのポート番号>/<DB名>";
以下是连接到PostgreSQL的信息。此次是一个示例,但根据环境不同,将提供上述信息。
请参考最初的示例代码以获取具体示例。
执行SQL文
在Java中执行SQL语句时,有两种方法,分别是”Statement”和”PreparedStatement”。
“Statement”是直接执行输入的字符串,非常简单。
“PreparedStatement”是预编译并优化过的,还可以后续更改参数,非常优秀。
通常情况下,如果使用相同的SQL语句,我们基本上会使用”PreparedStatement”。
不过这次我们将使用简单的”Statement”。
查询语句
Statement stmt = conn.createStatement();
String sql = "SELECT 1";
rset = stmt.executeQuery(sql);
//SELECT結果の受け取り
while(rset.next()){
String col = rset.getString(1);
System.out.println(col);
}
为了执行SQL语句,我们通过”createStatement”方法初始化”Statement”。尽管它们看起来相似,但通过传递给”createStatement”方法的参数可以改变SELECT结果的接收方式。在下面给出了简单的说明,但通常情况下,您无需指定参数,只需使用默认值即可。
カーソルは順方向にのみ移動可能。
ResultSetのlast()、first()等は使用できない。ResultSet.TYPE_FORWARD_ONLYカーソルは順方向・逆方向に移動可能。
データ取得後に、他の接続によって変更されたデータを反映しない。ResultSet.TYPE_SCROLL_INSENSITIVEカーソルは順方向・逆方向に移動可能。
データ取得後に、他の接続によって変更されたデータを反映する。
読み取り一貫性が保証されなくなるため非推奨。
ResultSetによる更新不可。ResultSet.CONCUR_UPDATABLEResultSetによる更新可能。
updateXXX()等が使用できる。
在 SELECT 语句中,使用 “ResultSet” 类来接收结果。
基本上,可以使用 next() 方法按顺序提取获取到的数据。
在最后一行数据之后再执行 next() 方法,结果将变为 null,因此可以使用 while 循环来获取全部数据。
当从 ResultSet 中提取数据时,需要指定列。
指定列的方法可以是列的索引(从第 0 列开始),或者是列的名称。
如果只想获取最后一条或第一条数据,可以使用last()和first()方法。但是需要注意的是,这两个方法需要在”createStatement”方法的第一个参数中传递ResultSet.TYPE_FORWARD_ONLY。
DML(插入、删除、更新)操作语句
//INSERT文の実行
sql = "INSERT INTO jdbc_test VALUES (1, 'AAA')";
stmt.executeUpdate(sql);
conn.commit();
DML与SELECT不同,不接收结果,所以不使用ResultSet。
因此,在使用「createStatement」方法时不需要指定参数。
但是,必须使用「executeUpdate()」方法来执行SQL语句。
另外,自动提交是关闭的情况下,需要使用commit()方法进行提交,后面会详细说明。
创建语句(CREATE …)
这次的示例中没有包含,但是可以使用与 DML 语句相同的方法执行。
对于 PostgreSQL 来说,DDL 语句不会自动提交,所以在自动提交关闭的情况下,需要像 DML 语句一样显式地提交。
//CREATE文の実行
sql = "CREATE TABLE hoge (col1 integer)";
stmt.executeUpdate(sql);
conn.commit();
提交,回滚
正如前面提到的,可以通过函数执行COMMIT和ROLLBACK操作。
因此,不再需要编写SQL语句了。
//COMMITの実行
conn.commit();
//ROLLBACKの実行
conn.rollback();
交易
自动提交
在使用JDBC时,默认情况下会启用自动提交功能。对于使用PostgreSQL的人来说,这没有问题,但对于其他关系数据库管理系统来说,则需要注意。请注意,由于PostgreSQL也默认启用自动提交功能。
自动提交的启用/禁用是通过setAutoCommit()方法来实现的。
当为true时为启用(默认),当为false时为禁用。
//自動コミットOFF
conn.setAutoCommit(false);
如果想在Java中进行事务处理,通常要禁用自动提交。由于后续的原因,很少需要输入SQL语句的BEGIN。
当自动提交被关闭时的事务处理
如果自动提交被关闭的情况下,JDBC会在SQL开始时自动输入BEGIN。因此,如果明确地写出BEGIN,则数据库中会执行两次BEGIN。由于COMMIT和ROLLBACK也是通过函数提供的,因此在使用Java进行事务处理时,很少会有机会输入与事务相关的SQL。
//BEGIN文の実行
stmt = conn.createStatement();
String sql = "BEGIN";
rset = stmt.executeQuery(sql);
LOG: execute <unnamed>: BEGIN
LOG: execute <unnamed>: BEGIN
WARNING: there is already a transaction in progress
我已将PostgreSQL参数log_statement设置为’all’。
附注:有关加载JDBC驱动程序的补充信息。
如果是JDBC 4.0之前的版本,需要通过Class.forName来明确加载JDBC驱动程序,如下所示:
try{
Class.forName("org.postgresql.Driver");
…
}
catch (ClassNotFoundException e) {
…
}
对于不同种类的JDBC驱动程序,上述字符串的描述是不同的。
如果要声明它,就需要进行ClassNotFoundException的异常处理。
然而,自从JDBC 4.0(=Java 1.6)以后,它会自动加载,因此不再需要上述的手动加载。
在以前版本的JDBC中,要获取一个连接,您首先需要通过调用方法Class.forName来初始化JDBC驱动程序。这个方法需要一个java.sql.Driver类型的对象。每个JDBC驱动程序包含一个或多个实现java.sql.Driver接口的类。Java DB的驱动程序是org.apache.derby.jdbc.EmbeddedDriver和org.apache.derby.jdbc.ClientDriver,而MySQL Connector/J的驱动程序是com.mysql.jdbc.Driver。请查阅您的DBMS驱动程序的文档以获取实现java.sql.Driver接口的类的名称。
任何在您的类路径中找到的JDBC 4.0驱动程序都会被自动加载。(但是,在JDBC 4.0之前您必须手动加载任何驱动程序,可以使用方法Class.forName)。
在早期的JDBC版本中,要获取连接,首先需要调用Class.forName方法来初始化JDBC驱动程序。这个方法需要一个java.sql.Driver类型的对象。每个JDBC驱动程序都包含一个或多个实现java.sql.Driver接口的类。对于Java DB,驱动程序是org.apache.derby.jdbc.EmbeddedDriver和org.apache.derby.jdbc.ClientDriver;对于MySQL Connector / J,驱动程序是com.mysql.jdbc.Driver。要获取实现java.sql.Driver接口的类的名称,请参考DBMS驱动程序的手册。
在类路径中的JDBC 4.0驱动程序将自动加载。(然而,您仍需要使用Class.forName方法手动加载JDBC 4.0之前的驱动程序。)
-
- JDBC Basics Tutorial ~Establishing a Connection~より引用
-
- https://docs.oracle.com/javase/tutorial/jdbc/basics/connecting.html#drivermanager
-
- 参考:The PostgreSQL JDBC Interface ~Chapter 3. Initializing the Driver~
- https://jdbc.postgresql.org/documentation/head/load.html