PostgreSQL15——Java访问PostgreSQL
Java访问PostgreSQL
- 一、连接数据库
- 二、创建和删除表
- 三、插入数据
- 四、查询数据
- 五、修改数据
- 六、删除数据
- 七、处理事务
- 八、调用存储过程
JDBC (Java Database Connectivity)是 Java 语言中用于访问数据库的应用程序接口(API)。JDBC 提供了操作关系数据库的标准方法,属于 Java Standard Edition 平台的一部分。以下是 Java应用程序通过JDBC 访问数据库的示意图:
其中各个模块的作用如下:
- Java 应用程序由开发人员编码完成,用于实现业务处理的逻辑和流程;
- JDBC API 提供了统一的接口和驱动管理,实现了应用程序和 JDBC 驱动的隔离。同一套应用代码只需要切换驱动程序就可以支持不同的数据库;
- JDBC 驱动实现了JDBC API 中定义的接口,用于与不同的数据库进行交互;
- 数据库提供数据的存储管理和访问控制。
一、连接数据库
Maven依赖:
<dependency><groupId>org.postgresql</groupId><artifactId>postgresql</artifactId><version>42.2.14</version>
</dependency>
在项目目录中创建一个数据库的连接配置文件 db.properties,内容如下:
url=jdbc:postgresql://192.168.56.104:3306/hrdb
user=tony
password=123456
package demo;import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Properties;public class App {public static void main(String[] args) {String url = null;String user = null;String password = null;//读取数据库连接配置文件//加载properties文件try (InputStream input = App.class.getClassLoader().getResourceAsStream("db.properties")) {if (input == null) {System.out.println("未找到配置文件");return;}// 加载属性列表从输入流Properties pros = new Properties();pros.load(input);url = pros.getProperty("url");user = pros.getProperty("user");password = pros.getProperty("password");} catch (IOException e) {System.out.println(e.getMessage());}//建立数据库连接try (Connection conn = DriverManager.getConnection(url, user, password)){System.out.println("连接PostgreSQL数据库成功!");} catch (SQLException e) {System.out.println(e.getMessage());}}
}
首先,通过一个FileInputStream 对象读取数据库的连接配置文件;然后使用try-with-resources方式建立数据库连接,打印信息。运行该程序的结果如下:
连接PostgreSQL数据库成功!
二、创建和删除表
- 通过JDBC 连接数据库并执行 DDL 语句的过程如下:
- 利用 DriverManager 类的 getConnection()方法获取一个 Connection 连接对象;
- 使用连接对象的 createStatement()方法创建一个Statement 语句对象;
- 利用语句对象的 execute()方法执行 SQ 语句;
释放 Statement 以及 Connection 对象资源。
package demo;import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;public class PostgreSQLDDL {public static void main(String[] args) {String url = null;String user = null;String password = null;String sql_str = "create table users (" +" id serial primary key," +" name character varying(10) not null unique," +" created_at timestamp not null" +")";//读取数据库连接配置文件//加载properties文件try (InputStream input = App.class.getClassLoader().getResourceAsStream("db.properties")) {if (input == null) {System.out.println("未找到配置文件");return;}// 加载属性列表从输入流Properties pros = new Properties();pros.load(input);url = pros.getProperty("url");user = pros.getProperty("user");password = pros.getProperty("password");} catch (IOException e) {System.out.println(e.getMessage());}//建立数据库连接,创建查询语句,并且执行语句try (Connection conn = DriverManager.getConnection(url, user, password)){System.out.println("连接PostgreSQL数据库成功!");Statement ps = conn.createStatement();//执行SQL语句ps.execute(sql_str);System.out.println("成功创建users表!");} catch (SQLException e) {System.out.println(e.getMessage());}}
}
首先,通过一个 FileInputStream 对象读取数据库的连接配置文件;然后使用try-with-resources方式建立数据库连接,创建查询语句,并且执行语句创建 users 表。运行该程序的结果如下:
连接PostgreSQL数据库成功!
成功创建users表!
如果users 表已经存在,将会提示以下错误:
ERROR: relation "users" already exists
此时可以将 sql_str 的内容修改 drop table users 删除并重新创建 users 表。
三、插入数据
通过JDBC 连接数据库并执行插入操作的过程如下:
- 利用 DriverManager 类的 getConnection()方法获取一个 Connection 连接对象;
- 使用连接对象的 createStatement()方法创建一个 Statement 或者PreparedStatement 语句对
象; - 利用语句对象的 execute()或者executeBatch()方法执行 INSERT 语句;
- 释放 Statement 以及 Connection 对象资源。
package demo;import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;public class PostgreSQLInsert {public static void main(String[] args) {String url = null;String user = null;String password = null;String sql_str = "insert into users(name, created_at)" +" values(?, ?)";//读取数据库连接配置文件//加载properties文件try (InputStream input = App.class.getClassLoader().getResourceAsStream("db.properties")) {if (input == null) {System.out.println("未找到配置文件");return;}// 加载属性列表从输入流Properties pros = new Properties();pros.load(input);url = pros.getProperty("url");user = pros.getProperty("user");password = pros.getProperty("password");} catch (IOException e) {System.out.println(e.getMessage());}//建立数据库连接,并且执行语句try (Connection conn = DriverManager.getConnection(url, user, password)){System.out.println("连接PostgreSQL数据库成功!");PreparedStatement ps = conn.prepareStatement(sql_str);//设置输入参数ps.setString(1, "tony");ps.setTimestamp(2, new Timestamp(System.currentTimeMillis()));ps.addBatch();ps.setString(1, "david");ps.setTimestamp(2, new Timestamp(System.currentTimeMillis()));ps.addBatch();//执行批量插入操作ps.executeBatch();System.out.println("插入数据成功!");} catch (SQLException e) {System.out.println(e.getMessage());}}
}
其中,sql_str 中的两个问号(?)表示两个占位符,它们的值会在运行时进行替换;然后使用 prepareStatement()方法创建了一个预编译的 SQL 语句,在执行该语句之前使用 setString()和 setTimestamp() 方法替换占位符的值,并且使用 addBatch() 添加批量操作;最后执行
executeBatch()方法进行批量插入操作。
该程序的执行结果如下:
连接PostgreSQL数据库成功!
插入数据成功!
四、查询数据
通过JDBC 连接数据库并执行查询语句的过程如下:
- 利用 DriverManager 类的 getConnection()方法获取一个 Connection 连接对象;
- 使用连接对象的 createStatement()方法创建一个 Statement 或者PreparedStatement 语句对象;
- 利用语句对象的 executeQuery()方法执行 SQL 语句或者存储过程,返回一个 ResultSet 结果集对象;
- 遍历结果集,获取并处理查询结果;
- 释放 ResultSet、Statement 以及 Connection 对象资源。
package demo;import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;public class PostgreSQLQUery {public static void main(String[] args) {String url = null;String user = null;String password = null;String sql_str = "select id, name, created_at" +" from users";//读取数据库连接配置文件//加载properties文件try (InputStream input = App.class.getClassLoader().getResourceAsStream("db.properties")) {if (input == null) {System.out.println("未找到配置文件");return;}// 加载属性列表从输入流Properties pros = new Properties();pros.load(input);url = pros.getProperty("url");user = pros.getProperty("user");password = pros.getProperty("password");} catch (IOException e) {System.out.println(e.getMessage());}//建立数据库连接,创建查询语句,并且执行语句try (Connection conn = DriverManager.getConnection(url, user, password)){System.out.println("连接PostgreSQL数据库成功!");Statement stmt = conn.createStatement();ResultSet rs = stmt.executeQuery(sql_str);//处理查询结果while (rs.next()) {System.out.println(rs.getInt("id") + "\t" +rs.getString("name") + "\t" +rs.getTimestamp("created_at"));}} catch (SQLException e) {System.out.println(e.getMessage());}}
}
首先,通过一个 FileInputStream 对象读取数据库的连接配置文件;然后使用try-with-resources方式建立数据库连接,创建查询语句,并且执行该语句;最后使用一个 while 循环获取查询结果集,rs.next()获取结果中的下一条记录;rs.getInt()、rs.getString()和 rs.getTimestamp()分别用于获取记录中的整数、字符串以及时间戳字段。
该程序的输出结果如下:
连接PostgreSQL数据库成功!
1 tony 2025-09-10 22:46:38.075
2 david 2025-09-10 22:46:38.076
五、修改数据
我们可以通过PreparedStatement 语句对象 executeUpdate()方法执行更新语句。创建一个新的
源文件 PostgreSQLUpdate.java:
package demo;import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;public class PostgreSQLUpdate {public static void main(String[] args) {String url = null;String user = null;String password = null;String sql_str = "update users " +"set name = ? " +"where id = ?";//读取数据库连接配置文件//加载properties文件try (InputStream input = App.class.getClassLoader().getResourceAsStream("db.properties")) {if (input == null) {System.out.println("未找到配置文件");return;}// 加载属性列表从输入流Properties pros = new Properties();pros.load(input);url = pros.getProperty("url");user = pros.getProperty("user");password = pros.getProperty("password");} catch (IOException e) {System.out.println(e.getMessage());}//建立数据库连接,创建查询语句,并且执行语句try (Connection conn = DriverManager.getConnection(url, user, password)){System.out.println("连接PostgreSQL数据库成功!");PreparedStatement ps = conn.prepareStatement(sql_str);//设置输入参数ps.setString(1, "tom");ps.setInt(2, 1);//执行更新操作int affectedrows = ps.executeUpdate();System.out.println(String.format("更新行数: %d", affectedrows));} catch (SQLException e) {System.out.println(e.getMessage());}}
}
其中,sql_str 中的两个问号(?)表示两个占位符,它们的值会在运行时进行替换;然后使用 prepareStatement()方法创建了一个 PreparedStatement 预编译的 SQL 语句,在执行该语句之前使用 setInt()和setString()方法替换占位符的值;最后执行 executeBatch()方法进行更新操作,返回
被更新的行数。
运行以上程序的输出结果如下:
连接PostgreSQL数据库成功!
更新行数: 1
六、删除数据
删除操作和插入、更新操作类似,只需要将 SQL 语句替换成 DELETE 即可。我们创建一个新的 Java 文件 PostgreSQLDelete.java:
package demo;import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Properties;public class PostgreSQLDelete {public static void main(String[] args) {String url = null;String user = null;String password = null;String sql_str = "delete from users " +"where id = ?";//读取数据库连接配置文件//加载properties文件try (InputStream input = App.class.getClassLoader().getResourceAsStream("db.properties")) {if (input == null) {System.out.println("未找到配置文件");return;}// 加载属性列表从输入流Properties pros = new Properties();pros.load(input);url = pros.getProperty("url");user = pros.getProperty("user");password = pros.getProperty("password");} catch (IOException e) {System.out.println(e.getMessage());}//建立数据库连接,创建查询语句,并且执行语句try (Connection conn = DriverManager.getConnection(url, user, password)){System.out.println("连接PostgreSQL数据库成功!");PreparedStatement ps = conn.prepareStatement(sql_str);//设置输入参数ps.setInt(1, 1);//执行int affectedros = ps.executeUpdate();System.out.println(String.format("删除行数: %d", affectedros));} catch (SQLException e) {System.out.println(e.getMessage());}}
}
执行该程序输出的结果如下:
连接PostgreSQL数据库成功!
删除行数: 1
七、处理事务
默认情况下,JDBC 连接PostgreSQL 时使用自动提交模式,意味着每个 SQL 语句都会自动执行事务的提交操作。如果我们想要在一个事务中执行多条 SQL 语句,需要禁用连接对象的自动提交属性,并且手动执行 COMMIT 或者ROLLBACK 操作。
package demo;import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;public class PostgreSQLTransaction {public static void main(String[] args) {String url = null;String user = null;String password = null;String sql_str = "insert into users(name, created_at) " +"values(?, ?)";String sql_str2 = "update users set name = ? " +"where id = ?";//读取数据库连接配置文件//加载properties文件try (InputStream input = App.class.getClassLoader().getResourceAsStream("db.properties")) {if (input == null) {System.out.println("未找到配置文件");return;}// 加载属性列表从输入流Properties pros = new Properties();pros.load(input);url = pros.getProperty("url");user = pros.getProperty("user");password = pros.getProperty("password");} catch (IOException e) {System.out.println(e.getMessage());}//建立数据库连接,创建查询语句,并且执行语句try (Connection conn = DriverManager.getConnection(url, user, password)){System.out.println("连接PostgreSQL数据库成功!");//设置手动提交conn.setAutoCommit(false);try (PreparedStatement ps = conn.prepareStatement(sql_str);PreparedStatement ps2 = conn.prepareStatement(sql_str2)){//设置输入参数并执行语句ps.setString(1, "anne");ps.setTimestamp(2, new Timestamp(System.currentTimeMillis()));ps.executeUpdate();ps2.setString(1, "anne");ps2.setInt(2, 2);ps2.executeUpdate();//提交事务conn.commit();System.out.println("事务提交成功!");} catch (SQLException e) {//回滚事务conn.rollback();System.out.println(e.getMessage());System.out.println("回滚事务!");}} catch (SQLException e) {System.out.println(e.getMessage());}}
}
创建连接之后,使用 setAutoCommit()方法禁用自动提交;然后分别执行插入语句和更新语句,并提交事务;在异常处理中回滚事务并打印错误消息。
由于更新语句将 name 设置为重复值,因此该程序返回以下错误:
连接PostgreSQL数据库成功!
ERROR: duplicate key value violates unique constraint "users_name_key"详细:Key (name)=(anne) already exists.
回滚事务!
此时,插入语句也会被回滚;所以并不会创建 anne。
八、调用存储过程
利用 JDBC 中的 CallableStatement 对象可以调用 PostgreSQL 存储过程和函数。首先创建一个存储过程 add_user:
CREATE OR REPLACE PROCEDURE add_user(pv_name varchar, pd_created_at timestamp)
AS $$
BEGININSERT INTO users(name, created_at)VALUES (pv_name, pd_created_at);
END; $$
LANGUAGE plpgsql;
CallableStatement 对象默认只支持存储函数调用;为了支持存储过程,需要将连接属性escapeSyntaxCallMode 设置为 callIfNoReturn。我们将db.properties 文件修改如下:
url=jdbc:postgresql://192.168.56.104:5432/hrdb?escapeSyntaxCallMode=callI
fNoReturn
user=tony
password=tony
package demo;import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;public class PostgreSQLSP {public static void main(String[] args) {String url = null;String user = null;String password = null;//读取数据库连接配置文件//加载properties文件try (InputStream input = App.class.getClassLoader().getResourceAsStream("db.properties")) {if (input == null) {System.out.println("未找到配置文件");return;}// 加载属性列表从输入流Properties pros = new Properties();pros.load(input);url = pros.getProperty("url");user = pros.getProperty("user");password = pros.getProperty("password");} catch (IOException e) {System.out.println(e.getMessage());}//建立数据库连接,调用存储过程try (Connection conn = DriverManager.getConnection(url, user, password);CallableStatement stmt = conn.prepareCall("{call add_user(?, ?)}")){stmt.setString(1, "anne");stmt.setTimestamp(2, new Timestamp(System.currentTimeMillis()));stmt.execute();System.out.println("调用存储过程成功!");} catch (SQLException e) {System.out.println(e.getMessage());}}
}
其中, **{ call add_user( ?, ? ) }**中的问号是占位符,表示一个输入参数;prepareCall()方法返回一个 CallableStatement 对象,代表调用存储过程的语句;设置输入参数后执行存储过程。
运行该程序输出以下内容:
调用存储过程成功!