PostgreSQL15——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数据库成功!

二、创建和删除表

  1. 通过JDBC 连接数据库并执行 DDL 语句的过程如下:
  2. 利用 DriverManager 类的 getConnection()方法获取一个 Connection 连接对象;
  3. 使用连接对象的 createStatement()方法创建一个Statement 语句对象;
  4. 利用语句对象的 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 连接数据库并执行插入操作的过程如下:

  1. 利用 DriverManager 类的 getConnection()方法获取一个 Connection 连接对象;
  2. 使用连接对象的 createStatement()方法创建一个 Statement 或者PreparedStatement 语句对
    象;
  3. 利用语句对象的 execute()或者executeBatch()方法执行 INSERT 语句;
  4. 释放 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 连接数据库并执行查询语句的过程如下:

  1. 利用 DriverManager 类的 getConnection()方法获取一个 Connection 连接对象;
  2. 使用连接对象的 createStatement()方法创建一个 Statement 或者PreparedStatement 语句对象;
  3. 利用语句对象的 executeQuery()方法执行 SQL 语句或者存储过程,返回一个 ResultSet 结果集对象;
  4. 遍历结果集,获取并处理查询结果;
  5. 释放 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 对象,代表调用存储过程的语句;设置输入参数后执行存储过程。

运行该程序输出以下内容:

调用存储过程成功!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值