Java中调用数据库存储过程的示例代码

2025-06-27 17:50

本文主要是介绍Java中调用数据库存储过程的示例代码,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

《Java中调用数据库存储过程的示例代码》本文介绍Java通过JDBC调用数据库存储过程的方法,涵盖参数类型、执行步骤及数据库差异,需注意异常处理与资源管理,以优化性能并实现复杂业务逻辑,感兴趣的朋友...

存储过程(Stored Procedure)是一组为了完成特定功能的SQL语句集,经编译后存储在数据库中。Java应用程序可以通过JDBC调用这些存储过程,实现复杂的业务逻辑。本文将详细介绍如何在Java中调用数据库的存储过程,包括传递参数和获取返回结果,并提供丰富的示例代码。

一、存储过程概述

存储过程具有以下优点:

  1. 提高性能:存储过程只需要编译一次,以后每次执行都不需要重新编译,提高了执行效率。
  2. 减少网络流量:存储过程在数据库服务器上执行,只需要将结果返回给客户端,减少了网络传输的数据量。
  3. 增强安全:可以通过存储过程控制对数据库的访问,只允许用户执行特定的存储过程,而不是直接访问表。
  4. 复用性强:存储过程可以被多个应用程序共享和复用。

存储过程的参数类型有三种:

  • IN参数:输入参数,用于向存储过程传递值。
  • OUT参数:输出参数,用于从存储过程返回值。
  • INOUT参数:输入输出参数,既可以传递值给存储过程,也可以从存储过程返回值。

二、Java调用存储过程的基本步骤

在Java中调用存储过程主要通过CallableStatement接口实现,基本步骤如下:

  1. 获取数据库连接:通过DriverManager.getConnection()方法获取数据库连接。
  2. 准备调用存储过程的SQL语句:使用{call 存储过程名(参数1, 参数2, ...)}格式。
  3. 创建CallableStatement对象:通过Connection.prepareCall()方法创建。
  4. 设置输入参数:如果存储过程有输入参数,使用setXxx()方法设置。
  5. 注册输出参数:如果存储过程有输出参数,使用registerOutParameter()方法注册。
  6. 执行存储过程:使用execute()executeQuery()executeUpdate()方法执行。
  7. 获取输出参数的值:如果存储过程有输出参数,使用getXxx()方法获取。
  8. 处理结果集:如果存储过程返回结果集,遍历结果集获取数据。
  9. 关闭资源:关闭CallableStatementConnection

三、Java调用存储过程示例

下面通过具体示例演示如何在Java中调用不同类型的存储过程。

1. 无参数存储过程

存储过程定义(MySQL)

DELIMITER $$
CREATE PROCEDURE GetAllEmployees()
BEGIN
    SELECT * FROM employees;
END$$
DELIMITER ;

Java调用代码

import java.sql.*;
public class CallStoredProcedureNoParams {
    public static void main(String[] args) {
        String url = "jdbc:mysql://localhost:3306/company";
        String username = "root";
        String password = "password";
        try (Connection conn = DriverManager.getConnection(url, username, password);
             // 创建调用存储过程的语句
             CallableStatement cstmt = conn.prepareCall("{call GetAllEmployees()}")) {
            // 执行存储过程
            ResultSet rs = cstmt.executeQuery();
            // 处理结果集
            while (rs.next()) {
                System.out.println("ID: " + rs.getInt("id") + 
                                   ", Name: " + rs.getString("name") + 
                                   ", Department: " + rs.getString("department"));
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

2. 带IN参数的存储过程

存储过程定义(MySQL)

DELIMITER $$
CREATE PROCEDURE GetEmployeeByDepartment(IN dept VARCHAR(50))
BEGIN
    SELECT * FROM employees WHERE department = dept;
END$$
DELIMITER ;

Java调用代码

import java.sql.*;
public class CallStoredProcedureWithINParam {
    public static void main(String[] args) {
        String url = "jdbc:mysql://localhost:3306/company";
        String username = "root";
        String password = "password";
        try (Connection conn = DriverManager.getConnection(url, username, password);
             // 创建调用存储过程的语句
             CallableStatement cstmt = conn.prepareCall("{call GetEmployeeByDepartment(?)}")) {
            // 设置输入参数
            cstmt.setString(1, "IT");
            // 执行存储过程
            ResultSet rs = cstmt.executeQuery();
            // 处理结果集
            while (rs.next()) {
                System.out.println("ID: " + rs.getInt("id") + 
                                   ", Name: " + rs.getString("name") + 
                                   ", Department: " + rs.getString("department"));
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

3. 带OUT参数的存储过程

存储过程定义(MySQL)

DELIMITER $$
CREATE PROCEDURE GetEmployeeCount(OUT count INT)
BEGIN
    SELECT COUNT(*) INTO count FROM employees;
END$$
DELIMITER ;

Java调用代码

import java.sql.*;
public class CallStoredProcedureWithOUTParam {
    public static void main(String[] args) {
        String url = "jdbc:mysql://localhost:3306/company";
        String username = "root";
        String password = "password";
        try (Connection conn = DriverManager.getConnection(url, username, password);
             // 创建调用存储过程的语句
             CallableStatement cstmt = conn.prepareCall("{call GetEmployeeCount(?)}")) {
            // 注册输出参数
            cstmt.registerOutParameter(1, Types.INTEGER);
            // 执行存储过程
            cstmt.execute();
            // 获取输出参数的值
            int count = cstmt.getInt(1);
            System.out.println("员工总数: " + count);
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

4. 带INOUT参数的存储过程

存储过程定义(MySQL)

DELIMITER $$
CREATE PROCEDURE IncrementSalary(INOUT salary DOUBLE, IN percentage INT)
BEGIN
    SET salary = salary * (1 + percentage/100.0);
END$$
DELIMITER ;

Java调用代码

import java.sql.*;
public class CallStoredProcedureWithINOUTParam {
    public static void main(String[] args) {
        String url = "jdbc:mysql://localhost:3306/company";
        String username = "root";
        String password = "password";
        try (Connection conn = DriverManager.getConnection(url, username, password);
             // 创建调用存储过程的语句
             CallableStatement cstmt = conn.prepareCall("{call IncrementSalary(?, ?)}")) {
            // 设置输入参数
            cstmt.setDouble(1, 5000.0);  // 初始工资
            cstmt.setInt(2, 10);        // 加薪百分比
            // 注册输出参数
            cstmt.registerOutParameter(1, Types.DOUBLE);
            // 执行存储过程
            cstmt.execute();
            // 获取输出参数的值
            double newSalary = cstmt.getDouble(1);
            System.out.println("加薪后的工资: " + newSalary);
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

5. 带返回结果集和输出参数的存储过程

存储过程定义(MySQL)

DELIMITER $$
CREATE PROCEDURE GetEmployeesAndCount(OUT count INT)
BEGIN
    SELECT * FROM employees;
    SELECT COUNT(*) INTO count FROM employees;
END$$
DELIMITER ;

Java调用代码

import java.sql.*;
pubwww.chinasem.cnlic clajavascriptss CallStoredProcedureWithResultSetAndOUTParam {
    public static void main(String[] args) {
        String url = "jdbc:mysql://localhost:3306/company";
        String username = "root";
        String password = "password";
        try (Connection conn = DriverManager.getConnection(url, username, password);
             // 创建调用存储过程的语句
             CallableStatement cstmt = conn.prepareCall("{call GetEmployeesAndCount(?)}")) {
            // 注册输出参数
            cstmt.registerOutParameter(1, Types.INTEGER);
            // 执行存储过程
            boolean hasResultSet = cstmt.execute();
            // 处理结果集
            if (hasResultSet) {
                try (ResultSet rs = cstmt.getResultSet()) {
                    System.out.println("员工列表:");
                    while (rs.next()) {
                        System.out.println("ID: " + rs.getInt("id") + 
                                           ", Name: " + rs.getString("name") + 
                                           ", Department: " + rs.getString("department"));
                    }
                }
            }
            // 移动到下一个结果(输出参数)
            while (cstmt.getMoreResults()) {
                // 处理可能的其他结果集
            }
            // 获取输出参数的值
            int count = cstmt.getInt(1);
            System.out.printChina编程ln("员工总数: " + count);
        } catch (SQLException e) {
            e.printStackTrace();
 python       }
    }
}

四、不同数据库的存储过程调用差异

虽然JDBC提供了统一的API来调用存储过程,但不同数据库的存储过程语法和调用方式可能存在差异。

1. MySQL

MySQL使用CREATE PROCEDURE语句创建存储过程,调用时使用{call 存储过程名(参数)}语法。

2. Oracle

Oracle使用CREATE OR REPLACE PROCEDURE语句创建存储过程,调用时语法与MySQL类似,但参数类型可能不同。

Oracle存储过程示例

CREATE OR REPLACE PROCEDURE GetEmployeeCount(emp_count OUT NUMBER)
IS
BEGIN
    SELECT COUNT(*) INTO emp_count FROM employees;
END;

Java调用Oracle存储过程

try (Connection conn = DriverManager.getConnection(url, username, password);
     CallableStatement cstmt = conn.prepareCall("{call GetEmployeeCount(?)}")) {
    // 注册输出参数(Oracle使用Types.NUMERIC)
    cstmt.registerOutParameter(1, Types.NUMERIC);
    // 执行存储过程
    cstmt.execute();
    // 获取输出参数的值
    int count = cstmt.getInt(1);
    System.out.println("员工总数: " + count);
} catch (SQLException e) {
    e.printStackTrace();
}

3. SQL Server

SQL Server使用CREATE PROCEDURE语句创建存储过程,调用时可以使用EXEC 存储过程名 参数语法,也可以使用标准的JDBC语法。

SQL Server存储过程示例

CREATE PROCEDURE GetEmployeeByDepartment
    @dept VARCHAR(50)
AS
BEGIN
    SELECT * FROM employees WHERE department = @dept;
END

Java调用SQL Server存储过程

try (Connection conn = DriverManager.getConnection(url, username, password);
     CallableStatement cstmt = conn.prepareCall("{call GetEmployeeByDepartment(?)}")) {
    // 设置输入参数
    cstmt.setString(1, "IT");
    // 执行存储过程
    ResultSet rs = cstmt.executeQuery();
    // 处理结果集
    while (rs.next()) {
        System.out.println("ID: " + rs.getInt("id") + 
                           ", Name: " + rs.getString("name") + 
                           ", Department: " + rs.getString("department"));
    }
} catch (SQLException e) {
    e.printStackTrace();
}

五、异常处理和资源管理

在调用存储过程时,需要注意异常处理和资源管理,避免资源泄漏。

Connection conn = null;
CallableStatement cstmt = null;
ResultSet rs = null;
try {
    // 获取数据库连接
    conn = DriverManager.getConnection(url, username, password);
    // 创建调用存储过程的语句
    cstmt = conn.prepareCall("{call 存储过程名(参数)}");
    // 设置参数和执行存储过程
    // ...
} catch (SQLException e) {
    e.printStackTrace();
} finally {
    // 关闭资源,注意顺序
    try {
        if (rs != null) rs.close();
        if (cstmt != null) cstmt.close();
        if (conn != null) conn.close();
    } catch (SQLException e) {
        e.printStackTrace();
    }
}

或者使用Java 7引入的try-with-resources语句自动关闭资源:

try (Connection conn = DriverManager.getConnection(url, username, password);
     CallableStatement cstmt = conn.prepareCall("{call 存储过程名(参数)}")) {
    // 设置参数和执行存储过程
    // ...
} catch (SQLException e) {
    e.printStackTrace();
}

六、存储过程调用的性能考虑

  1. 缓存存储过程:大多数JDBC驱动会自动缓存存储过程的执行计划,可以通过设置连接参数来控制缓存大小。

  2. 批量操作:如果需要多次调用同一个存储过程,可以考虑使用批量操作来提高性能。

  3. 避免过度使用存储过程:虽然存储过程有很多优点,但并不是所有情况都适合使用。对于简单的查询,直接使用SQL可能更高效。

  4. 优化存储过程:确保存储过程本身已经经过优化,避免在存储过程中执行复杂的逻辑。

七、总结

通过JDBC调用数据库存储过程是Java与数据库交互的重要方式,它允许我们利用数据库的强大功能来实现复杂的业务逻辑。本文介绍了Java调用存储过程的基本步骤和示例,包括无参数、带IN参数、带OUT参数、带INOUT参数以及带结果集和输出参数的存储过程调用方法。

主要关键点:

  1. 使用CallableStatement接口调用存储过程
  2. 使用setXxx()方法设置输入参数
  3. 使用registerOutParameter()方法注册输出参数
  4. 使用getXxx()方法获取输出参数的值
  5. 处理存储过程返回的结果集
  6. 注意不同数据库的存储过程语法差异
  7. 做好异常处理和资源管理

在实际项目中,可以根据业务需求选择合适的存储过程调用方式,并结合数据库特性进行优化,以提高应用程序的性能和可维护性。

到此这篇关于Java中调用数据库存储过程的文章就介绍到这了,更多相关java调用存储过程内容请搜索China编程(www.chinasem.cn)以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程China编程(www.chinasem.cn)!

这篇关于Java中调用数据库存储过程的示例代码的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1155236

相关文章

Spring Boot项目如何使用外部application.yml配置文件启动JAR包

《SpringBoot项目如何使用外部application.yml配置文件启动JAR包》文章介绍了SpringBoot项目通过指定外部application.yml配置文件启动JAR包的方法,包括... 目录Spring Boot项目中使用外部application.yml配置文件启动JAR包一、基本原理

SpringBoot加载profile全面解析

《SpringBoot加载profile全面解析》SpringBoot的Profile机制通过多配置文件和注解实现环境隔离,支持开发、测试、生产等不同环境的灵活配置切换,无需修改代码,关键点包括配置文... 目录题目详细答案什么是 Profile配置 Profile使用application-{profil

Java中InputStream重复使用问题的几种解决方案

《Java中InputStream重复使用问题的几种解决方案》在Java开发中,InputStream是用于读取字节流的类,在许多场景下,我们可能需要重复读取InputStream中的数据,这篇文章主... 目录前言1. 使用mark()和reset()方法(适用于支持标记的流)2. 将流内容缓存到字节数组

Java慢查询排查与性能调优完整实战指南

《Java慢查询排查与性能调优完整实战指南》Java调优是一个广泛的话题,它涵盖了代码优化、内存管理、并发处理等多个方面,:本文主要介绍Java慢查询排查与性能调优的相关资料,文中通过代码介绍的非... 目录1. 事故全景:从告警到定位1.1 事故时间线1.2 关键指标异常1.3 排查工具链2. 深度剖析:

Springboot项目登录校验功能实现

《Springboot项目登录校验功能实现》本文介绍了Web登录校验的重要性,对比了Cookie、Session和JWT三种会话技术,分析其优缺点,并讲解了过滤器与拦截器的统一拦截方案,推荐使用JWT... 目录引言一、登录校验的基本概念二、HTTP协议的无状态性三、会话跟android踪技术1. Cook

C++归并排序代码实现示例代码

《C++归并排序代码实现示例代码》归并排序将待排序数组分成两个子数组,分别对这两个子数组进行排序,然后将排序好的子数组合并,得到排序后的数组,:本文主要介绍C++归并排序代码实现的相关资料,需要的... 目录1 算法核心思想2 代码实现3 算法时间复杂度1 算法核心思想归并排序是一种高效的排序方式,需要用

MybatisPlus中removeById删除数据库未变解决方案

《MybatisPlus中removeById删除数据库未变解决方案》MyBatisPlus中,removeById需实体类标注@TableId注解以识别数据库主键,若字段名不一致,应通过value属... 目录MyBATisPlus中removeBypythonId删除数据库未变removeById(Se

通过配置nginx访问服务器静态资源的过程

《通过配置nginx访问服务器静态资源的过程》文章介绍了图片存储路径设置、Nginx服务器配置及通过http://192.168.206.170:8007/a.png访问图片的方法,涵盖图片管理与服务... 目录1.图片存储路径2.nginx配置3.访问图片方式总结1.图片存储路径2.nginx配置

MySQL ORDER BY 语句常见用法、示例详解

《MySQLORDERBY语句常见用法、示例详解》ORDERBY是结构化查询语言(SQL)中的关键字,隶属于SELECT语句的子句结构,用于对查询结果集按指定列进行排序,本文给大家介绍MySQL... 目录mysql ORDER BY 语句详细说明1.基本语法2.排序方向详解3.多列排序4.常见用法示例5.

java实现多数据源切换方式

《java实现多数据源切换方式》本文介绍实现多数据源切换的四步方法:导入依赖、配置文件、启动类注解、使用@DS标记mapper和服务层,通过注解实现数据源动态切换,适用于实际开发中的多数据源场景... 目录一、导入依赖二、配置文件三、在启动类上配置四、在需要切换数据源的类上、方法上使用@DS注解结论一、导入