[MySQL] MySQL存储过程与存储函数

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_14852397/article/details/48547877

存储过程

        存储过程(Stored Procedure)是在大型数据库系统中,一组为了完成特定功能的SQL 语句集,存储在数据库中,经过第一次编译后再次调用不需要再次编译,用户通过指定存储过程的名字并给出参数(如果该存储过程带有参数)来执行它。存储过程是数据库中的一个重要对象,任何一个设计良好的数据库应用程序都应该用到存储过程。

优点

①重复使用。存储过程可以重复使用,从而可以减少数据库开发人员的工作量。
②提高性能。存储过程在创建的时候在进行了编译,将来使用的时候不再重新翻译。一般的SQL语句每执行一次就需要编译一次,所以使用存储过程提高了效率。
③减少网络流量。存储过程位于服务器上,调用的时候只需要传递存储过程的名称以及参数就可以了,因此降低了网络传输的数据量。
④安全性。参数化的存储过程可以防止SQL注入式攻击,而且可以将Grant、Deny以及Revoke权限应用于存储过程。
简单讲:
1.存储过程只在创造时进行编译,以后每次执行存储过程都不需再重新编译,而一般SQL语句每执行一次就编译一次,所以使用存储过程可提高数据库执行速度。
2.当对数据库进行复杂操作时(如对多个表进行Update,Insert,Query,Delete时),可将此复杂操作用存储过程封装起来与数据库提供的事务处理结合一起使用。
3.存储过程可以重复使用,可减少数据库开发人员的工作量
4.安全性高,可设定只有某些用户才具有对指定存储过程的使用权
有一点需要注意的是,一些网上盛传的所谓的存储过程要比sql语句执行更快的说法,实际上是个误解,并没有根据,包括微软内部的人也不认可这一点,所以不能作为正式的优点,希望大家能够认识到这一点。
# 创建存储过程
delimiter //
CREATE PROCEDURE GET_DSRXX(IN id VARCHAR(50))
BEGIN
	# 获取当事人信息[存储过程] Mysql对变量名大小写不敏感,所以变量名尽量不要一致;
	# 案件类型
	DECLARE ajlx VARCHAR(20);
	# 审判程序
	DECLARE cx VARCHAR(20);
	# 字典项代码
	DECLARE zdlx VARCHAR(20);
	# 查询案件信息
	SELECT AJLB, SPCX INTO ajlx, cx FROM TD_AJJBXX WHERE AJID = id;
	CASE ajlx
		WHEN '1' THEN
			CASE cx
				WHEN '1' THEN SET zdlx = 'DIC_XSYS_DSRSSDW';
				WHEN '2' THEN SET zdlx = 'DIC_XSES_DSRSSDW';
				WHEN '4' THEN SET zdlx = 'DIC_XSZS_DSRSSDW';
			END CASE;
		WHEN '2' THEN
			CASE cx
				WHEN '1' THEN SET zdlx = 'DIC_MSYS_DSRSSDW';
				WHEN '2' THEN SET zdlx = 'DIC_MSES_DSRSSDW';
				WHEN '4' THEN SET zdlx = 'DIC_MSZS_DSRSSDW';
			END CASE;
		WHEN '6' THEN
			CASE cx
				WHEN '1' THEN SET zdlx = 'DIC_XZYS_DSRSSDW';
				WHEN '2' THEN SET zdlx = 'DIC_XZES_DSRSSDW';
				WHEN '4' THEN SET zdlx = 'DIC_XZZS_DSRSSDW';
			END CASE;
		WHEN '7' THEN SET zdlx = 'DIC_PC_DSRSSDW';
		WHEN '8' THEN SET zdlx = 'DIC_ZX_DSRSSDW';
	END CASE;
	# 查询当事人信息/字典项名称
	SELECT (SELECT ZDXMC FROM TD_ZDX WHERE ZDLXDM = zdlx AND ZDXDM = SSDW) AS SSDW, GROUP_CONCAT(DSRMC) AS DSRMC FROM TD_DSR WHERE AJID = id GROUP BY SSDW;
END //
delimiter;

# 执行存储过程
CALL GET_DSRXX('1442541348467');

缺点

1:调试麻烦,但是用 PL/SQL Developer 调试很方便!弥补这个缺点。
2:移植问题,数据库端代码当然是与数据库相关的。但是如果是做工程型项目,基本不存在移植问题。
3:重新编译问题,因为后端代码是运行前编译的,如果带有引用关系的对象发生改变时,受影响的存储过程、包将需要重新编译(不过也可以设置成运行时刻自动编译)。
4: 如果在一个程序系统中大量的使用存储过程,到程序交付使用的时候随着用户需求的增加会导致数据结构的变化,接着就是系统的相关问题了,最后如果用户想维护该系统可以说是很难很难、而且代价是空前的,维护起来更麻烦。

自定义存储函数

            自定义存储函数是非常特殊的存储过程。

存储过程与函数区别:
       函数区别与存储过程的唯一的特点是:函数必须有返回值;
        存储函数的参数类型类似于IN参数;
        存储过程的参数类型有三种、IN参数、OUT参数、INOUT参数;

分隔符声明:
     DELIMITER是分割符的意思,因为MySQL默认以";"为分隔符,如果我们没有声明分割符,那么编译器会把存储过程当成SQL语句进行处理,则存储过程的编译过程会报错,所以要事先用DELIMITER关键字申明当前段分隔符,这样MySQL才会将";"当做存储过程中的代码,不会执行这些代码,用完了之后要把分隔符还原。$,$$,//


实例操作

MySql存储过程:

<span style="font-size:12px;color:#000000;">delimiter //
# 创建存储过程
CREATE PROCEDURE GET_DSRXX(IN id VARCHAR(50))
BEGIN
	# 获取当事人信息[存储过程] Mysql对变量名大小写不敏感,所以变量名尽量不要一致;
	# 案件类型
	DECLARE ajlx VARCHAR(20);
	# 审判程序
	DECLARE cx VARCHAR(20);
	# 字典项代码
	DECLARE zdlx VARCHAR(20);
	# 查询案件信息
	SELECT AJLB, SPCX INTO ajlx, cx FROM TD_AJJBXX WHERE AJID = id;
	CASE ajlx
		WHEN '1' THEN
			CASE cx
				WHEN '1' THEN SET zdlx = 'DIC_XSYS_DSRSSDW';
				WHEN '2' THEN SET zdlx = 'DIC_XSES_DSRSSDW';
				WHEN '4' THEN SET zdlx = 'DIC_XSZS_DSRSSDW';
			END CASE;
		WHEN '2' THEN
			CASE cx
				WHEN '1' THEN SET zdlx = 'DIC_MSYS_DSRSSDW';
				WHEN '2' THEN SET zdlx = 'DIC_MSES_DSRSSDW';
				WHEN '4' THEN SET zdlx = 'DIC_MSZS_DSRSSDW';
			END CASE;
		WHEN '6' THEN
			CASE cx
				WHEN '1' THEN SET zdlx = 'DIC_XZYS_DSRSSDW';
				WHEN '2' THEN SET zdlx = 'DIC_XZES_DSRSSDW';
				WHEN '4' THEN SET zdlx = 'DIC_XZZS_DSRSSDW';
			END CASE;
		WHEN '7' THEN SET zdlx = 'DIC_PC_DSRSSDW';
		WHEN '8' THEN SET zdlx = 'DIC_ZX_DSRSSDW';
	END CASE;
	# 查询当事人信息/字典项名称
	SELECT (SELECT ZDXMC FROM TD_ZDX WHERE ZDLXDM = zdlx AND ZDXDM = SSDW) AS SSDW, GROUP_CONCAT(DSRMC) AS DSRMC FROM TD_DSR WHERE AJID = id GROUP BY SSDW;
END //
delimiter;

# 执行存储过程
CALL GET_DSRXX('1442541348467');</span>

MySql存储函数:
<span style="font-size:12px;color:#000000;">DELIMITER //
# 创建存储函数
CREATE FUNCTION GET_DSRXX_FUN(id VARCHAR(50))
	RETURNS VARCHAR(100)
BEGIN
	DECLARE dsrxx VARCHAR(100);
	# 获取当事人信息[存储过程] Mysql对变量名大小写不敏感,所以变量名尽量不要一致;
	# 案件类型
	DECLARE ajlx VARCHAR(20);
	# 审判程序
	DECLARE cx VARCHAR(20);
	# 字典项代码
	DECLARE zdlx VARCHAR(20);
	# 查询案件信息
	SELECT AJLB, SPCX INTO ajlx, cx FROM TD_AJJBXX WHERE AJID = id;
	CASE ajlx
		WHEN '1' THEN
			CASE cx
				WHEN '1' THEN SET zdlx = 'DIC_XSYS_DSRSSDW';
				WHEN '2' THEN SET zdlx = 'DIC_XSES_DSRSSDW';
				WHEN '4' THEN SET zdlx = 'DIC_XSZS_DSRSSDW';
			END CASE;
		WHEN '2' THEN
			CASE cx
				WHEN '1' THEN SET zdlx = 'DIC_MSYS_DSRSSDW';
				WHEN '2' THEN SET zdlx = 'DIC_MSES_DSRSSDW';
				WHEN '4' THEN SET zdlx = 'DIC_MSZS_DSRSSDW';
			END CASE;
		WHEN '6' THEN
			CASE cx
				WHEN '1' THEN SET zdlx = 'DIC_XZYS_DSRSSDW';
				WHEN '2' THEN SET zdlx = 'DIC_XZES_DSRSSDW';
				WHEN '4' THEN SET zdlx = 'DIC_XZZS_DSRSSDW';
			END CASE;
		WHEN '7' THEN SET zdlx = 'DIC_PC_DSRSSDW';
		WHEN '8' THEN SET zdlx = 'DIC_ZX_DSRSSDW';
	END CASE;
	# 查询当事人信息/字典项名称
	SELECT GROUP_CONCAT(SSDW, ": ", DSRMC SEPARATOR  "; ") AS DSRXXS INTO dsrxx FROM ((SELECT (SELECT ZDXMC FROM TD_ZDX WHERE ZDLXDM = zdlx AND ZDXDM = SSDW) AS SSDW, GROUP_CONCAT(DSRMC) AS DSRMC FROM TD_DSR WHERE AJID = id GROUP BY SSDW) A);
	RETURN dsrxx;
END //
DELIMITER;

# 执行存储函数
SELECT GET_DSRXX_FUN('1442541348467') AS DSR;
</span>

MySql存储过程[多参数]:

delimiter //
# 多参数存储过程
CREATE PROCEDURE GET_KTXX(IN id VARCHAR(50), OUT strTszt VARCHAR(20), OUT strAjlx VARCHAR(50), OUT strCbr VARCHAR(50), OUT strSjy VARCHAR(50), OUT strKtsj VARCHAR(50))
BEGIN
	SELECT 
	(SELECT TSZT FROM TD_KT WHERE AJID = A.AJID) AS TSZT, 
	(SELECT ZDXMC FROM TD_ZDX WHERE ZDXDM = A.AJLB AND ZDLXDM = 'DIC_AJLX') AS AJLX, 
	(SELECT YHXM FROM TD_RYXX WHERE ZYBM = A.CBR) AS CBR, 
	(SELECT YHXM FROM TD_RYXX WHERE ZYBM = A.SJY) AS SJY, 
	(SELECT TSKSSJ FROM TD_KT WHERE AJID = A.AJID) AS KTSJ INTO strTszt, strAjlx, strCbr, strSjy, strKtsj
	FROM TD_AJJBXX AS A WHERE AJID = id;
END //
delimiter;
# 执行
CALL GET_KTXX('1442643584344', @a, @b, @c, @d, @e);
SELECT @a, @b, @c, @d, @e;

Java 实例:
package com.szft.test;

import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Types;
import com.cwnb.db.ConnectionDatabase;
import com.cwnb.db.ConnectionTool;

/**
 * @功能描述 存储函数调用
 * @author 吥 悔
 * @QQ 379839355
 * @时间 2015年9月16日 下午4:07:01
 */
public class SqlProceduresAndFunctionTest {
	public static void main(String[] args) {
		Connection conn = null;
		CallableStatement ps = null;
		ResultSet rs = null;
		try {
			// 获得连接
			conn = ConnectionDatabase.getConnection();
			// 存储过程
			ps = conn.prepareCall("{Call GET_DSRXX(?)}");
			ps.setString(1, "1442541348467");
			ps.execute();
			rs = ps.executeQuery();
			while (rs.next()) {
				System.out.println(rs.getString("SSDW") + " : " + rs.getString("DSRMC"));
			}
			System.out.println("---------------------- 分割线 ----------------------");
			// 存储函数
			ps = conn.prepareCall("SELECT GET_DSRXX_FUN(?) AS DSR");
			ps.setString(1, "1442541348467");
			ps.execute();
			rs = ps.executeQuery();
			if (rs.next()) {
				System.out.println(rs.getObject(1));
			}
			System.out.println("---------------------- 分割线 ----------------------");
			// 多参数
			ps = conn.prepareCall("{Call GET_KTXX(?, ?, ?, ?, ?, ?)}");
			ps.setString(1, "1442643584344");
			ps.registerOutParameter(2, Types.VARCHAR);
			ps.registerOutParameter(3, Types.VARCHAR);
			ps.registerOutParameter(4, Types.VARCHAR);
			ps.registerOutParameter(5, Types.VARCHAR);
			ps.registerOutParameter(6, Types.VARCHAR);
			ps.execute();
			System.out.println(ps.getString(2) + " - " + ps.getString(3) + " - " + ps.getString(4) + " - " + ps.getString(5) + " - " + ps.getString(6));
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			ConnectionTool.closeConn(conn, ps, rs);
		}
	}
}

执行结果:


猜你喜欢

转载自blog.csdn.net/qq_14852397/article/details/48547877