Java基础系列12:使用CallableStatement接口调用数据库中的存储过程

前言:以下内容均以MySQL中的存储过程举例说明

一 存储过程简介

我们常用的操作数据库语言SQL语句在执行的时候需要要先编译,然后执行,而存储过程(Stored Procedure)是一组为了完成特定功能的SQL语句集,经编译后存储在数据库中,用户通过指定存储过程的名字并给定参数(如果该存储过程带有参数)来调用执行它。

一个存储过程是一个可编程的函数,它在数据库中创建并保存。它可以有SQL语句和一些特殊的控制结构组成。当希望在不同的应用程序或平台上执行相同的函数,或者封装特定功能时,存储过程是非常有用的。数据库中的存储过程可以看做是对编程中面向对象方法的模拟。它允许控制数据的访问方式。

存储过程通常有以下优点: 
i)存储过程增强了SQL语言的功能和灵活性。存储过程可以用流控制语句编写,有很强的灵活性,可以完成复杂的判断和较复杂的运算。 
ii)存储过程允许标准组件是编程。存储过程被创建后,可以在程序中被多次调用,而不必重新编写该存储过程的SQL语句。而且数据库专业人员可以随时对存储过程进行修改,对应用程序源代码毫无影响。 
iii)存储过程能实现较快的执行速度。如果某一操作包含大量的Transaction-SQL代码或分别被多次执行,那么存储过程要比批处理的执行速度快很多。因为存储过程是预编译的。在首次运行一个存储过程时查询,优化器对其进行分析优化,并且给出最终被存储在系统表中的执行计划。而批处理的Transaction-SQL语句在每次运行时都要进行编译和优化,速度相对要慢一些。 
iv)存储过程能过减少网络流量。针对同一个数据库对象的操作(如查询、修改),如果这一操作所涉及的Transaction-SQL语句被组织程存储过程,那么当在客户计算机上调用该存储过程时,网络中传送的只是该调用语句,从而大大增加了网络流量并降低了网络负载。 
v)存储过程可被作为一种安全机制来充分利用。系统管理员通过执行某一存储过程的权限进行限制,能够实现对相应的数据的访问权限的限制,避免了非授权用户对数据的访问,保证了数据的安全。

(PS:以上简介参考至:http://www.jb51.net/article/30825.htm

二 存储过程的简单使用

(1)格式:

MySQL存储过程创建的格式:CREATE PROCEDURE 过程名 ([过程参数[,…]]) 
[特性 …] 过程体

(2)创建一个存储过程myproc并进行测试:

mysql> DELIMITER // 
CREATE PROCEDURE myproc(IN p1 int,INOUT p2 int,OUT p3 int)
BEGIN
 SELECT p1,p2,p3;
 SET p1 = 10;
 SET p2 = 20; 
 SET p3 = 30;
END
//
Query OK, 0 rows affected

mysql> SET @P1 = 11//
Query OK, 0 rows affected

mysql> SET @P2 = 22//
Query OK, 0 rows affected

mysql> CALL myproc(@P1,@P2,@P3)//
+----+----+------+
| p1 | p2 | p3   |
+----+----+------+
| 11 | 22 | NULL |
+----+----+------+
1 row in set

Query OK, 0 rows affected

mysql> SELECT @P1,@P2,@P3//
+-----+-----+-----+
| @P1 | @P2 | @P3 |
+-----+-----+-----+
|  11 |  20 |  30 |
+-----+-----+-----+
1 row in set

mysql>

注:

i):MySQL中默认的语句结束符为分号(;),存储过程中的SQL语句也需要需要分号来结束。因此为了避免冲突,首先用”DELIMITER // “将MySQL的结束符设置为“//”

ii)在上面的存储过程“myproc”中定义了三个变量,分别使用了IN、INOUT和OUT这三种类型来申明,它们表示的含义分别是:

IN 输入参数:表示该参数的值必须在调用存储过程时指定,在存储过程中修改该参数的值不能被返回,为默认值

OUT 输出参数:该值可在存储过程内部被改变,并可返回

INOUT 输入输出参数:调用时指定,并且可被改变和返回 
iii)“SET @P1 = 11” 这种形式表示定义了一个名为“@P1”的用户变量,同时“SELECT p1,p2,p3; ”表示输出p1、p2、p3的值。执行“CALL myproc(@P1,@P2,@P3)”后p3的值为空,因为在输出时p3还没有被赋值;执行完“SELECT @P1,@P2,@P3;”后,可以发现@P1的值没有发生改变,因为IN类型只是将值传递到存储过程中去,@P2和@P3的值发生改变是因为在存储过程中已经被重新赋值了

三 使用CallableStatement接口操作存储过程

CallableStatement主要是调用数据库中的存储过程,在使用CallableStatement时可以接收过程的返回值,示例代码如下:

package javase.jdbc;

import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Types;

public class ProcDemo {
	/**
	 * JDBC调用MySQL存储过程示例
	 * */
	public static void main(String[] args) {
		/**
		 * DELIMITER // 
		   CREATE PROCEDURE myproc(IN p1 int,INOUT p2 int,OUT p3 int)
		   BEGIN
		   	SELECT p1,p2,p3;
		   	SET p1 = 10;
		   	SET p2 = 20;
		   	SET p3 = 30;
		   END
		   //
		 * 
		 * */
		String sql = "{CALL myproc(?,?,?)}";  //调用存储过程myproc
		Connection connection = JDBCConnection.getConnection();
		try {
			CallableStatement cStatement = connection.prepareCall(sql);
			cStatement.setInt(1, 11);
			cStatement.setInt(2, 22);
			cStatement.registerOutParameter(2, Types.INTEGER);  //设置返回值类型
			cStatement.registerOutParameter(3, Types.INTEGER);  //设置返回值类型
			cStatement.execute();  //执行存储过程

			System.out.println("INOUT的返回值: " + cStatement.getInt("p2"));
			System.out.println("OUT的返回值: " + cStatement.getInt("p3"));

			cStatement.close();
			connection.close();
		} catch (SQLException e) {
			e.printStackTrace();
		}

	}

}

输出:

INOUT的返回值: 20
OUT的返回值: 30
时间: 2024-10-20 22:19:29

Java基础系列12:使用CallableStatement接口调用数据库中的存储过程的相关文章

java中调用数据库中的存储过程和函数

public static void main(String[] args) {         Connection conn =getConnection(url,user, pwd);         System.out.println("数据连接成功");         CallableStatement cs=null;         try         {    //调用数据库中的存储过程              cs = conn.prepareCall(&q

Java基础系列 - 子类继承父类,调用父类的构造函数

package com.test7; public class test7 { public static void main(String[] args) { Son son = new Son(1000, "张三"); /** * 打印显示 Father的构造函数1000 张三 Son的构造函数1000 张三 */ } } class Father { private int userId; private String userName; public Father(int us

使用Kettle调用数据库中的存储过程

使用kettle调用存储过程,传入参数传出参数. 存储过程的内容如下,主要是传入一个表名字和一个数字类型的返回值. 那么能得到表的行数. CreateOr Replace Procedure p_Emp_Cnt(t In Varchar2, Num Out Number) Is   v_Sql Varchar2(600);   Lv_Cnt Number; Begin   Select Count(*)     Into Lv_Cnt     From User_Tables    Where 

夯实Java基础系列6:一文搞懂抽象类和接口,从基础到面试题,揭秘其本质区别!

目录 抽象类介绍 为什么要用抽象类 一个抽象类小故事 一个抽象类小游戏 接口介绍 接口与类相似点: 接口与类的区别: 接口特性 抽象类和接口的区别 接口的使用: 接口最佳实践:设计模式中的工厂模式 接口与抽象类的本质区别是什么? 基本语法区别 设计思想区别 如何回答面试题:接口和抽象类的区别? 参考文章 微信公众号 Java技术江湖 个人公众号:黄小斜 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl

Spring基础系列12 -- Spring AOP AspectJ

Spring基础系列12 -- Spring AOP AspectJ 转载:http://www.cnblogs.com/leiOOlei/p/3613352.html 本文讲述使用AspectJ框架实现Spring AOP. 再重复一下Spring AOP中的三个概念, Advice:向程序内部注入的代码. Pointcut:注入Advice的位置,切入点,一般为某方法. Advisor:Advice和Pointcut的结合单元,以便将Advice和Pointcut分开实现灵活配置. Aspe

《Java 基础系列》初步整理

<Java 基础系列>初步整理大概有 12 篇,主要内容为.: 抽象类和接口内部类修饰符装箱拆箱注解反射泛型异常集合IO字符串其他第一篇我们来聊聊抽象类和接口. "抽象类和接口"听起来是非常普遍的东西,有些朋友会觉得:这个太基础了吧,有啥好说的,你又来糊弄我. 这里写图片描述 事实上我在面试中不仅一次被问到相关的问题: 抽象类和接口之间的区别?什么时候创建抽象类?什么时候创建接口?设计框架时该如何选择?我比较喜欢这样的问题,答案可深可浅,体现了我们对日常工作的思考. 我们什

夯实Java基础系列9:深入理解Class类和Object类

目录 Java中Class类及用法 Class类原理 如何获得一个Class类对象 使用Class类的对象来生成目标类的实例 Object类 类构造器public Object(); registerNatives()方法; Clone()方法实现浅拷贝 getClass()方法 equals()方法 hashCode()方法; toString()方法 wait() notify() notifAll() finalize()方法 CLass类和Object类的关系 参考文章 微信公众号 Ja

使用CallableStatement接口调用存储过程

直接上下代码: 1 package com.learn.jdbc.chap07; 2 3 import java.sql.CallableStatement; 4 import java.sql.Connection; 5 import java.sql.Types; 6 7 import com.learn.jdbc.util.DbUtil; 8 9 /** 10 * 使用CallableStatement接口调用存储过程 11 * @author Administrator 12 * 13

夯实Java基础系列4:一文了解final关键字的特性、使用方法,以及实现原理

目录 final使用 final变量 final修饰基本数据类型变量和引用 final类 final关键字的知识点 final关键字的最佳实践 final的用法 关于空白final final内存分配 使用final修饰方法会提高速度和效率吗 使用final修饰变量会让变量的值不能被改变吗: 如何保证数组内部不被修改 final方法的三条规则 final 和 jvm的关系 写 final 域的重排序规则 读 final 域的重排序规则 如果 final 域是引用类型 参考文章 微信公众号 Jav