当前位置: 首页 > news >正文

JDBC接口开发指南

1.简介

JDBC(Java Data Base Connectivity,java数据库连接)是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口组成。JDBC提供了一种基准,据此可以构建更高级的工具和接口,使数据库开发人员能够编写数据库应用程序。

本文介绍如何通过 JDBC 连接瀚高数据库并执行各种数据操作。

2.数据库驱动

JDBC是对数据库操作的接口抽象,而不同数据库厂商的数据库驱动程序则对应JDBC接口实现,通过抽象出JDBC接口,应用程序和实际的数据库驱动即JDBC实现解耦。

在数据库安装目录 interfaces/jdbc 下,获得驱动jar包hgdb-jdbc-xxx.jar。该驱动包与PostgreSQL保持兼容,其中类名、类结构与 PostgreSQL 驱动完全一致,曾经运行于 PostgreSQL 的应用程序可以直接移植到当前系统使用。

画板

3.常用接口
3.1.Driver接口

Driver接口由数据库厂家提供,作为java开发人员,只需要使用Driver接口就可以了。在编程中要连接数据库,必须先装载特定厂商的数据库驱动程序,不同的数据库有不同的装载方法。如:

装载瀚高驱动:Class.forName(“org.postgresql.Driver”);

3.2.Connection接口

Connection与特定数据库的连接(会话),在连接上下文中执行sql语句并返回结果。

连接数据库:Connection conn = DriverManager.getConnection(“url”, “user”, “password”);

参数说明:

参数描述
url瀚高数据库连接URL支持的格式如下:
• jdbc:postgresql:database
• jdbc:postgresql://host/database
• jdbc:postgresql://host:port/database
• jdbc:postgresql://host:port/database?param1=value1&param2=value2
• jdbc:postgresql://host1:port1,host2:port2/database?param1=value1&param2=value2
说明:
• database 为要连接的数据库名称。
• host 为数据库服务器名称或IP地址。缺省情况下,连接服务器为localhost。
• port 为数据库服务器端口。缺省情况下,会尝试连接到5866端口的database。
• param 为参数名称,即数据库连接属性。参数可以配置在URL中,以“?”开始配置,以“=”给参数赋值,以“&”作为不同参数的间隔。
• value 为参数值,即数据库连接属性值。连接时需配置connectTimeout、socketTimeout,如果未配置,默认为0,即不会超时。
user数据库用户名
password数据库用户密码

常用方法:

createStatement():创建向数据库发送sql的statement对象。

prepareStatement(sql) :创建向数据库发送预编译sql的PrepareSatement对象。

prepareCall(sql):创建执行存储过程的callableStatement对象。

setAutoCommit(boolean autoCommit):设置事务是否自动提交。

commit() :在链接上提交事务。

rollback() :在此链接上回滚事务。

3.3.Statement接口

用于执行静态SQL语句并返回它所生成结果的对象。

三种Statement类:

  • Statement:由createStatement创建,用于发送简单的SQL语句(不带参数)。
  • PreparedStatement :继承自Statement接口,由preparedStatement创建,用于发送含有一个或多个参数的SQL语句。PreparedStatement对象比Statement对象的效率更高,并且可以防止SQL注入,所以我们一般都使用PreparedStatement。
  • CallableStatement:继承自PreparedStatement接口,由方法prepareCall创建,用于调用存储过程。

常用Statement方法:

  • execute(String sql):运行语句,返回是否有结果集
  • executeQuery(String sql):运行select语句,返回ResultSet结果集。
  • executeUpdate(String sql):运行insert/update/delete操作,返回更新的行数。
  • addBatch(String sql) :把多条sql语句放到一个批处理中。
  • executeBatch():向数据库发送一批sql语句执行。
3.4.ResultSet接口

ResultSet提供检索不同类型字段的方法,常用的有:

  • getString(int index)、getString(String columnName):获得在数据库里是varchar、char等类型的数据对象。
  • getFloat(int index)、getFloat(String columnName):获得在数据库里是Float类型的数据对象。
  • getDate(int index)、getDate(String columnName):获得在数据库里是Date类型的数据。
  • getBoolean(int index)、getBoolean(String columnName):获得在数据库里是Boolean类型的数据。
  • getObject(int index)、getObject(String columnName):获取在数据库里任意类型的数据。

ResultSet还提供了对结果集进行滚动的方法:

  • next():移动到下一行
  • Previous():移动到前一行
  • absolute(int row):移动到指定行
  • beforeFirst():移动resultSet的最前面。
  • afterLast() :移动到resultSet的最后面。

注意:使用后依次关闭对象及连接:ResultSet → Statement → Connection

4.使用JDBC步骤

加载JDBC驱动程序 → 建立数据库连接Connection → 创建执行SQL的语句Statement → 处理执行结果ResultSet → 释放资源

4.1.注册驱动
Class.forName("org.postgresql.Driver")
4.2.建立连接
Connection conn = DriverManager.getConnection(url, user, password); 
4.3.创建执行SQL语句的statement

statement

存在sql注入的危险,如果用户传入的id为“5 or 1=1”,那么将删除表中的所有记录。

String id = "5";
String sql = "delete from t where id=" + id;
Statement st = conn.createStatement();  
st.executeQuery(sql);  

PreparedStatement

有效的防止sql注入(SQL语句在程序运行前已经进行了预编译,当运行时动态地把参数传给PreprareStatement时,即使参数里有敏感字符如 or ‘1=1’ 数据库会作为一个参数一个字段的属性值来处理而不会作为一个SQL指令)

String sql = "insert into user (name,pwd) values(?,?)";
PreparedStatement ps = conn.preparedStatement(sql);
ps.setString(1, "col_value");  //占位符顺序从1开始
ps.setString(2, "123456"); //也可以使用setObject
ps.executeQuery();
4.4.处理执行结果(ResultSet)
ResultSet rs = ps.executeQuery();
While(rs.next()){rs.getString("col_name");rs.getInt(1);//…
}
4.5.释放资源

数据库连接(Connection)非常耗资源,尽量晚创建,尽量早的释放 。

都要加try catch 以防前面关闭出错,后面的就不执行了 。

try { if (rs != null) {rs.close();}
} catch (SQLException e) {e.printStackTrace();
} finally {try {if (st != null) {st.close();}} catch (SQLException e) {e.printStackTrace();} finally {try {if (conn != null) {conn.close();}} catch (SQLException e) {e.printStackTrace();}}
}
5.示例
5.1.连接数据库

通过 JDBC 连接瀚高数据库的过程如下:

  1. 使用 Class.forName() 方法显式地加载驱动类;
  2. 利用 DriverManager 类的 getConnection() 方法获取一个 Connection 连接对象。
private static final String JDBC_DRIVER = "org.postgresql.Driver";
private static final String JDBC_URL = "jdbc:postgresql://192.168.100.101:5866/highgo?escapeSyntaxCallMode=callIfNoReturn";
private static final String JDBC_USER = "highgo";
private static final String JDBC_PASSWORD = "111111";/*** 获取数据库连接* @return Connection 数据库连接对象* @throws SQLException,ClassNotFoundException*/
public static Connection getConnection() throws SQLException, ClassNotFoundException {//下面一行注册驱动代码可省略。Class.forName(JDBC_DRIVER);return DriverManager.getConnection(JDBC_URL,JDBC_USER,JDBC_PASSWORD);
}
  • JDBC_DRIVER 指定数据库驱动,从 JDBC 4.0 开始,驱动程序会通过 META-INF/services/java.sql.Driver 文件自动注册,因此不需要显式调用Class.forName();
  • JDBC_URL 中指定了数据库的 IP 地址、端口以及目标数据库;
  • JDBC_USER 和 JDBC_PASSWORD 指定数据库的用户和密码。

JDBC_URL 中 escapeSyntaxCallMode 是一个重要的配置参数,用于控制如何将 JDBC 转义调用语法(如 {call …} 或 {?= call …})转换为底层的 SQL 语句。这个参数对存储过程(PROCEDURE)和函数(FUNCTION)的调用行为有直接影响。

escapeSyntaxCallMode 的三种模式及行为:

  1. select 模式(默认)
  • 行为:JDBC 驱动会将所有 {call …} 或 {?= call …} 转换为 SELECT 语句。
  • 适用场景:
    • 仅适用于调用函数(FUNCTION),因为瀚高数据库的函数可以通过 SELECT 调用。
    • 不支持直接调用存储过程(PROCEDURE)。
  1. callIfNoReturn 模式
  • 行为:
    • 如果调用没有返回值(即没有 OUT 参数或返回结果集),JDBC 驱动会使用 CALL 语句。
    • 如果调用有返回值,则仍然使用 SELECT 语句。
  • 适用场景:
    • 适用于同时调用存储过程和函数的混合场景。
    • 存储过程通常不返回值,因此会使用 CALL。
    • 函数可能返回值,因此会使用 SELECT。
  1. call 模式
  • 行为:JDBC 驱动始终使用 CALL 语句,无论是否有返回值。
  • 适用场景:
    • 仅适用于调用 存储过程(PROCEDURE)。
    • 不支持调用函数(FUNCTION),因为瀚高数据库的函数无法通过 CALL 调用。

5.2.创建表

通过 JDBC 连接瀚高数据库并执行 DDL 语句的过程如下:

  1. 利用 DriverManager 类的 getConnection() 方法获取一个 Connection 连接对象;
  2. 使用连接对象的 createStatement() 方法创建一个 Statement 语句对象;
  3. 利用语句对象的 execute() 方法执行 SQL 语句;
  4. 释放 Statement 以及 Connection 对象资源。
/*** 创建表*/
public static void create(){Connection conn = null;Statement stmt = null;String sql = "create table users (" +"id serial primary key," +"name varchar(50) not null unique," +"create_time timestamp not null" +")";try {conn = getConnection(); //获取连接System.out.println("连接瀚高数据库成功!");stmt = conn.createStatement(); //创建statement对象stmt.execute(sql); //执行sqlSystem.out.println("成功创建 users 表!");} catch (Exception e) {e.printStackTrace();} finally { //释放资源try {if(stmt != null) stmt.close();} catch (Exception e) {e.printStackTrace();} finally {try {if(conn != null) conn.close();} catch (Exception e){e.printStackTrace();}}}
}
5.3.插入数据

通过 JDBC 连接瀚高数据库并执行插入操作的过程如下:

  1. 利用 DriverManager 类的 getConnection() 方法获取一个 Connection 连接对象;
  2. 使用连接对象的 createStatement() 方法创建一个 Statement 或者 PreparedStatement 语句对象;
  3. 利用语句对象的 execute() 或者 executeBatch() 方法执行 INSERT 语句;
  4. 释放 Statement 以及 Connection 对象资源。
/***插入数据*/
public static void insert(){Connection conn = null;PreparedStatement pstmt = null;String sql = "insert into users (name,create_time) values(?,?)";try {conn = getConnection();//获取连接pstmt = conn.prepareStatement(sql); //创建prepareStatement对象pstmt.setString(1,"John"); //绑定参数1pstmt.setTimestamp(2,new Timestamp(System.currentTimeMillis())); //绑定参数2pstmt.addBatch();pstmt.setString(1,"Robert"); //绑定参数1pstmt.setTimestamp(2,new Timestamp(System.currentTimeMillis())); //绑定参数2pstmt.addBatch();int[] rowsAffected = pstmt.executeBatch(); //执行sqlSystem.out.println("数据写入{" + rowsAffected.length + "}行!");} catch (Exception e) {e.printStackTrace();} finally { //释放资源try {if(pstmt != null) pstmt.close();} catch (Exception e) {e.printStackTrace();} finally {try {if(conn != null) conn.close();} catch (Exception e){e.printStackTrace();}}}
}
5.4.查询数据

通过 JDBC 连接瀚高数据库并执行查询语句的过程如下:

  1. 利用 DriverManager 类的 getConnection() 方法获取一个 Connection 连接对象;
  2. 使用连接对象的 createStatement() 方法创建一个 Statement 或者 PreparedStatement 语句对象;
  3. 利用语句对象的 executeQuery() 方法执行 SQL 语句或者存储过程,返回一个 ResultSet 结果集对象;
  4. 遍历结果集,获取并处理查询结果;
  5. 释放 ResultSet、Statement 以及 Connection 对象资源。
/***查询数据*/
private static void select(){Connection conn = null;PreparedStatement pstmt = null;ResultSet rs = null;String sql = "select * from users";try {conn = getConnection(); //获取连接pstmt = conn.prepareStatement(sql); //创建prepareStatement对象rs = pstmt.executeQuery(); //执行sqlwhile(rs.next()){ //处理结果集System.out.println(rs.getInt("id") + "\t" +rs.getString("name")  + "\t" +rs.getTimestamp("create_time"));}} catch (Exception e) {e.printStackTrace();} finally { //释放资源try {if(rs != null) rs.close();} catch (Exception e) {e.printStackTrace();} finally {try {if(pstmt != null) pstmt.close();} catch (Exception e) {e.printStackTrace();} finally {try {if(conn != null) conn.close();} catch (Exception e){e.printStackTrace();}}}}
}
5.5.修改数据

通过 JDBC 连接瀚高数据库并执行更新语句的过程如下:

  1. 利用 DriverManager 类的 getConnection() 方法获取一个 Connection 连接对象;
  2. 使用连接对象的 createStatement() 方法创建一个 Statement 或者 PreparedStatement 语句对象;
  3. 利用语句对象的 executeUpdate() 方法执行 UPDATE 语句;
  4. 释放 Statement 以及 Connection 对象资源。
/*** 修改数据*/
private static void update(){Connection conn = null;PreparedStatement pstmt = null;String sql = "update users set name=? where id=?";try {conn = getConnection(); //获取连接pstmt = conn.prepareStatement(sql);  //创建prepareStatement对象pstmt.setString(1,"Tom"); //绑定参数1pstmt.setInt(2,1); //绑定参数2int rowsAffected = pstmt.executeUpdate(); //执行sqlSystem.out.println("更新行数: {"+rowsAffected+"}");} catch (Exception e) {e.printStackTrace();} finally { //释放资源try {if(pstmt != null) pstmt.close();} catch (Exception e) {e.printStackTrace();} finally {try {if(conn != null) conn.close();} catch (Exception e){e.printStackTrace();}}}
}
5.6.删除数据

通过 JDBC 连接瀚高数据库并执行删除语句的过程如下:

  1. 利用 DriverManager 类的 getConnection() 方法获取一个 Connection 连接对象;
  2. 使用连接对象的 createStatement() 方法创建一个 Statement 或者 PreparedStatement 语句对象;
  3. 利用语句对象的 executeUpdate() 方法执行 DELETE 语句;
  4. 释放 Statement 以及 Connection 对象资源。
/*** 删除数据*/
private static void delete(){Connection conn = null;PreparedStatement pstmt = null;String sql = "delete from users where id=?";try {conn = getConnection(); //获取连接pstmt = conn.prepareStatement(sql); //创建prepareStatement对象pstmt.setInt(1,1); //绑定参数1int rowsAffected = pstmt.executeUpdate(); //执行sqlSystem.out.println("删除行数: {"+rowsAffected+"}");} catch (Exception e) {e.printStackTrace();} finally {//释放资源try {if(pstmt != null) pstmt.close();} catch (Exception e) {e.printStackTrace();} finally {try {if(conn != null) conn.close();} catch (Exception e){e.printStackTrace();}}}
}
5.7.处理事务

默认情况下,JDBC 连接瀚高数据库时使用自动提交模式,意味着每个 SQL 语句都会自动执行事务的提交操作。如果我们想要在一个事务中执行多条 SQL 语句,需要禁用连接对象的自动提交属性,并且手动执行 COMMIT 或者 ROLLBACK 操作。

创建连接之后,使用 setAutoCommit() 方法禁用自动提交;然后分别执行插入语句和更新语句,并提交事务;在异常处理中回滚事务并打印错误消息。

/*** 处理事务*/
private static void transaction(){Connection conn = null;PreparedStatement pstmt = null;PreparedStatement pstmt2= null;String sql = "insert into users (name,create_time) values(?,?)";String sql2 = "update users set name = ? where id = ?";try {conn = getConnection(); //获取连接conn.setAutoCommit(false); //设置手动提交pstmt = conn.prepareStatement(sql); //创建prepareStatement对象pstmt.setString(1,"James"); //绑定参数1pstmt.setTimestamp(2,new Timestamp(System.currentTimeMillis())); //绑定参数2pstmt.executeUpdate(); //执行sqlpstmt2 = conn.prepareStatement(sql2); //创建prepareStatement对象pstmt2.setString(1,"James"); //绑定参数1pstmt2.setInt(2,2); //绑定参数2pstmt2.executeUpdate(); //执行sqlconn.commit(); // 提交事务System.out.println("事务提交成功!");} catch (Exception e) {try {conn.rollback(); // 回滚事务System.out.println("事务回滚!");} catch (SQLException ex) {e.printStackTrace();}e.printStackTrace();} finally {try {if(pstmt != null) pstmt.close();if(pstmt2 != null) pstmt2.close();} catch (Exception e) {e.printStackTrace();} finally {try {if(conn != null) {conn.setAutoCommit(true); //设置自动提交conn.close();}} catch (Exception e){e.printStackTrace();}}}
}
5.8.调用函数

通过 JDBC 连接瀚高数据库并执行函数调用的过程如下:

  1. 利用 DriverManager 类的 getConnection() 方法获取一个 Connection 连接对象;
  2. 使用连接对象的 setAutoCommit() 方法禁用自动提交;
  3. 使用连接对象的 prepareCall() 方法创建一个 CallableStatement 语句对象;
  4. 利用语句对象的 execute() 方法执行函数调用,返回一个 ResultSet 结果集对象;
  5. 遍历结果集,获取并处理查询结果;
  6. 释放 ResultSet、CallableStatement 以及 Connection 对象资源。
CREATE OR REPLACE FUNCTION get_users_with_cursor_function() returns REFCURSOR AS $$
DECLAREref_cursor REFCURSOR;
BEGINOPEN ref_cursor FOR SELECT id, name, create_time FROM users;return ref_cursor;
END;
$$ LANGUAGE plpgsql;
/*** 调用函数*/
private static void callFunction(){Connection conn = null;CallableStatement cstmt = null;ResultSet rs = null;String callSQL = "{? = call get_users_with_cursor_function()}";try {conn = getConnection(); //获取连接conn.setAutoCommit(false); //设置手动提交cstmt = conn.prepareCall(callSQL); //创建prepareCall对象cstmt.registerOutParameter(1, Types.REF_CURSOR); //注册输出参数为游标类型cstmt.execute(); //执行存储过程rs = (ResultSet) cstmt.getObject(1); //获取返回的游标结果集// 遍历游标中的数据while (rs.next()) {System.out.println(rs.getInt("id") + "\t" +rs.getString("name")  + "\t" +rs.getTimestamp("create_time"));}conn.commit(); //提交事务} catch (Exception e) {try {conn.rollback(); // 回滚事务System.out.println("事务回滚!");} catch (SQLException ex) {e.printStackTrace();}e.printStackTrace();} finally {try {if(rs != null) rs.close();} catch (Exception e) {e.printStackTrace();} finally {try {if(cstmt != null) cstmt.close();} catch (Exception e) {e.printStackTrace();} finally {try {if(conn != null) {conn.setAutoCommit(true); //设置自动提交conn.close();}} catch (Exception e){e.printStackTrace();}}}}
}
5.9.调用存储过程

通过 JDBC 连接瀚高数据库并执行存储过程调用的过程如下:

  1. 利用 DriverManager 类的 getConnection() 方法获取一个 Connection 连接对象;
  2. 使用连接对象的 setAutoCommit() 方法禁用自动提交;
  3. 使用连接对象的 prepareCall() 方法创建一个 CallableStatement 语句对象;
  4. 利用语句对象的 execute() 方法执行存储过程调用,返回一个 ResultSet 结果集对象;
  5. 遍历结果集,获取并处理查询结果;
  6. 释放 ResultSet、CallableStatement 以及 Connection 对象资源。
CREATE OR REPLACE PROCEDURE get_users_with_cursor_procedure(OUT ref_cursor REFCURSOR) AS $$
BEGINOPEN ref_cursor FOR SELECT id, name, create_time FROM users;
END;
$$ LANGUAGE plpgsql;
/*** 调用存储过程*/
private static void callProcedure(){Connection conn = null;CallableStatement cstmt = null;ResultSet rs = null;String callSQL = "{ CALL get_users_with_cursor_procedure(?) }";try {conn = getConnection(); //获取连接conn.setAutoCommit(false); //设置手动提交cstmt = conn.prepareCall(callSQL); //创建prepareCall对象cstmt.registerOutParameter(1, Types.REF_CURSOR); //注册输出参数为游标类型cstmt.execute(); //执行存储过程rs = (ResultSet) cstmt.getObject(1); //获取返回的游标结果集// 遍历游标中的数据while (rs.next()) {System.out.println(rs.getInt("id") + "\t" +rs.getString("name")  + "\t" +rs.getTimestamp("create_time"));}conn.commit(); //提交事务} catch (Exception e) {try {conn.rollback(); // 回滚事务System.out.println("事务回滚!");} catch (SQLException ex) {e.printStackTrace();}e.printStackTrace();} finally {try {if(rs != null) rs.close();} catch (Exception e) {e.printStackTrace();} finally {try {if(cstmt != null) cstmt.close();} catch (Exception e) {e.printStackTrace();} finally {try {if(conn != null) {conn.setAutoCommit(true); //设置自动提交conn.close();}} catch (Exception e){e.printStackTrace();}}}}
}

相关文章:

  • 泛型的PECS原则
  • Docker 安装 Oracle 12C
  • React中修改 state 时必须返回一个新对象 (immutable update)
  • 基于数据库实现配置管理和定时任务启停
  • 常见Modbus协议面试问题
  • 强化微调技术与GRPO算法(1):简介
  • 农田实时监测与管理系统开发
  • map()函数
  • IteraJudge-增量多维评判框架解读
  • 第十节 高频代码题-类型推断题
  • NXP S32K146 T-Box 携手 SDNAND(贴片式 TF 卡):驱动汽车智能革新的黄金组合
  • 接口测试不再难:智能体自动生成 Postman 集合
  • 计算机系统(6)
  • 翻译核心词汇
  • 软考-计算机硬件组成
  • 微信小程序渗透测试指北(附案例)
  • 小结:Spring AOP 切点表达式
  • python-生日悖论
  • OpenCV——图像金字塔
  • std::make_shared简化智能指针 `std::shared_ptr` 的创建过程,并提高性能(减少内存分配次数,提高缓存命中率)
  • 专业做网站优化价格/手机网页设计
  • 郑州网站关键字优化/新网站应该怎么做seo
  • 网站建设管理概述/网站收录查询
  • 自定义wordpress标题的分隔符/seo网站推广如何做
  • 做建材外贸哪个网站比较好/永久免费的建站系统有哪些
  • 手机做网站服务器吗/网店代运营十大排名