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 $$
BEGIN
INSERT 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 对象,代表调用存储过程的语句;设置输入参数后执行存储过程。
运行该程序输出以下内容:
调用存储过程成功!

1864

被折叠的 条评论
为什么被折叠?



