相信几乎所有的程序猿们都知道数据库,也都知道数据库中有存储过程、函数等等其他的一些基本的知识,今天这里就主要讲一讲存储过程。
说到存储过程,相信很多一部分人都知道存储过程该怎么使用,但是如果真的被问到那么什么是存储过程呢?
楼主今天就碰到这一类问题,一个公司的小白拿来了一些题目过来问题,其中一个问题就是:什么是存储过程?怎么创建?用什么来调用?
当时就我就有点懵了,因为平时都是直接去调用就可以了,但是要真的讲原理,一时间也就真回答不上来,然后我果断的来了一句,这个嘛,你等下啊,我这里还有点事情没做完,等下跟你讲 -.-!!!
等他走开,就偷偷的开始百度。。。╭(╯^╰)╮,然后再结合实际应用,去告诉了他,强行装B,果然是最为致命,不过通过这一问题,也发现我自身存在的很多问题,下面就来介绍介绍存储过程。
学习三部曲:什么是...?为什么用...?怎么用...?
1、什么存储过程?
答:存储过程就是一组为完成特定功能的sql语句集,在数据库中编辑且储存在数据库中,经过首次编译后,就不需要再进行编辑,用户在需要用到时直接指定存储过程的名称来执行即可。
2、为什么要用存储过程?
a)方便维护:例如我们开发一个系统分别有不同的客户端(PC端、手机端),这个时候如果我们要去对一个表进行查询,使用普通sql那么我们就需要写两次sql语句,同时如果在开发过程中对数据库表进行了修改,那么相对应的查询语句也就可能受到影响需要修改,查询数据非常多的话就不利于维护,步骤太过繁琐,但是如果采用存储过程,那么我们仅仅只需要在数据库中修改存储过程中的代码即可。其它的地方都不需要变动,这也正好符合了我们面向对象的思想,利用存储过程将sql语句进行封装,然后外部只需要调用即可。
b)提高安全性:使用普通的sql语句来操作数据库会存在sql注入的危险,但是如果采用存储过程就可以帮我们解决这一问题,让sql语句与客户端测底的分离。
c)执行速度快:普通的sql语句都是需要经过编辑然后再执行,但是存储过程在创建后就已经编辑过了,只需要编译一次,后续只要调用就可以运行。
d)代码的复用,使用简单:使用存储过程非常简单,只需要调用就足够了。
3、怎么用存储过程?
这里我采用几个案例来演示存储过程的无参和有参,体验一下存储过程的强大之处,采用mybatis来完成与数据库的交互。
存储过程脚本在 3.8
3.1 准备工作:
* 准备一张用户表,并向表中添加一些数据,方便后续的查询操作。
3.2 创建mapper代理接口
package com.lxd.mysql.procedure; import java.util.List; import org.apache.ibatis.annotations.Param; /** * 使用mybatis来调用procedure存储过程 * @ClassName:MyBatisProcedureDemo * @author lxd * @date 2018年11月1日 * @version */ public interface MyBatisProcedureDemo { /** * 查询所有 * @Title: findAllUser * @return List<User> */ List<User> findAllUser(); /** * 根据分页查询 * @Title: getList * @param page 当前页 * @param total 每页数据数 * @return List<User> */ List<User> getList(@Param("page")Integer page, @Param("total")Integer total); }
3.3 编写mapper映射文件
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.lxd.mysql.procedure.MyBatisProcedureDemo"> <resultMap type="User" id="user_mapping"> <id property="id" column="id"/> <result property="username" column="username"/> <result property="userpass" column="userpass"/> </resultMap> <select id="findAllUser" resultMap="user_mapping"> CALL findAll_user() </select> <select id="getList" resultMap="user_mapping"> call findAll_limit(#{page},#{total}); </select> </mapper>
3.4 编写jdbc配置文件
jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql:///procedureDemo?characterEncoding=utf-8 jdbc.username=root jdbc.password=123456
3.4 编写mybatis核心配置文件
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <!-- 属性文件 先加载内部标签,再加载外部文件,属性名称一致时,会替换内容 --> <properties resource="jdbc.properties"></properties> <!-- 定义别名 --> <typeAliases> <!-- 别名包扫描器:别名是类的全称,不区分大小写 --> <package name="com.lxd.mysql.procedure"/> </typeAliases> <!-- 和spring整合后 environments配置将废除 --> <environments default="development"> <!-- 选择运行环境 --> <environment id="development"> <!-- 使用jdbc事务管理 --> <transactionManager type="JDBC" /> <!-- 数据库连接池 --> <dataSource type="POOLED"> <property name="driver" value="${jdbc.driver}" /> <property name="url" value="${jdbc.url}" /> <property name="username" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> </dataSource> </environment> </environments> <!-- 加载映射文件 --> <mappers> <!-- 映射文件包扫描,推荐方式 1:接口文件必须与映射文件同一目录下 2:接口文件的名称必须与映射文件名称一致 --> <package name="com.lxd.mysql.procedure"/> </mappers> </configuration>
3.5 引入mybatis和数据库的jar包
3.6 编写工具类
package com.lxd.mysql.procedure; import java.io.IOException; import java.io.InputStream; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; /** * session工厂工具类 * @ClassName:SqlSessionFactoryUtils * @author lxd * @date 2018年11月1日 * @version */ public class SqlSessionFactoryUtils { private static SqlSessionFactory sqlSessionFactory; static{ try { SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); InputStream inputStream = Resources.getResourceAsStream("sqlMapConfig.xml"); sqlSessionFactory = builder.build(inputStream); } catch (IOException e) { e.printStackTrace(); } } /** * 对外提供获取方法 * @Title: getSqlSessionFactory * @return SqlSessionFactory */ public static SqlSessionFactory getSqlSessionFactory(){ return sqlSessionFactory; } }
3.7 编写测试类
package com.lxd.mysql.procedure; import java.util.List; import org.apache.ibatis.session.SqlSession; import org.junit.Test; /** * 测试 * @ClassName:MyBatisProcedureTest * @author lxd * @date 2018年11月1日 * @version */ public class MyBatisProcedureTest { @Test public void testFindAllUser(){ // 调用工具类获取session工厂,并打开session SqlSession session = SqlSessionFactoryUtils.getSqlSessionFactory().openSession(true); // 通过session获取到mapper代理接口 MyBatisProcedureDemo demo = session.getMapper(MyBatisProcedureDemo.class); // 调用接口中的方法,得到结果 List<User> users = demo.findAllUser(); // 打印结果 System.out.println(users); } @Test public void testGetList(){ // 调用工具类获取session工厂,并打开session SqlSession session = SqlSessionFactoryUtils.getSqlSessionFactory().openSession(true); // 通过session获取到mapper代理接口 MyBatisProcedureDemo demo = session.getMapper(MyBatisProcedureDemo.class); // 调用接口中的方法,得到结果 List<User> users = demo.getList(2, 5); // 打印结果 for (User user : users) { System.out.println(user); } } }
3.8 附上存储过程脚本
-- 创建一个普通的查询所有的存储过程 DELIMITER// CREATE PROCEDURE findAll_user() BEGIN SELECT * FROM users; END // DELIMITER ; -- 创建带参的存储过程 DELIMITER // CREATE PROCEDURE findAll_limit(page INT, total INT) BEGIN DECLARE beginPage INT; DECLARE number INT; SET number = page; IF page = 0 THEN SET number = 1; END IF; SET beginPage = (number - 1) * total; SELECT * FROM users LIMIT beginPage,total; END // DELIMITER ;
3.9 查询结果
---------------------------------------------------------------------------------- 分隔线 -------------------------------------------------------------------------------------------
结尾:通过这一案例基本上可以大致的了解到存储过程的使用。本文主要就是大致的讲解下存储过程的概念及优点,和基本的使用。最主要就是帮我楼主记录所学知识,以便后续查阅,同时也是希望能够对那些存储过程存在疑问的给与一点薄弱的帮助。
学无止境,每天学一点,每天也同样的进步一点,不要轻言放弃。滴水穿石,终究是需要时间来积累的。