本篇讲述如何使用JDBC来调用MySQL数据库中的存储过程。建议在学习如何使用JDBC调用存储过程前,请先了解如何在数据库中使用存储过程。
存储过程是指在数据库系统中,一组为了完成特定功能的SQL语句集,存储在数据库中,经过第一次编译后以后再调用任意次都不需要重新编译了。说白了就是一堆SQL语句的合并,中间加了点逻辑控制,俗称为数据库中的函数。在一些金融等大型企业中,基本都是由内部人员编写好存储过程,然后由外部程序员调用存储过程,因为内部数据逻辑处理方式涉及商业机密等等。
也就是说我们现在有两种方式来处理数据库中的数据,一是通过JDBC从数据库中取出数据然后通过业务层编写处理数据的逻辑代码;二是在数据库中定义数据的存储过程,在这个存储过程中完成对数据的逻辑操作,就好比数据库中的函数,而我们在Java程序中只要调用数据库中的这个存储过程即可。
操作:
在MySQL数据库中确定要调用哪个存储过程,包括确定该存储过程的参数列表为哪些SQL类型。
在JDBC中通过链接Connection对象,调用prepareCall(…)方法,在prepareCall方法中的参数为字符串,内容应该为”{call 存储过程名(?(占位符,个数根据存储过程参数来定)...)}”,调用这个方法后返回CallableStatement对象。
通过返回的CallableStatement对象对于传入类型的参数(IN),如PreparedStatement对象一样设置占位符的替代参数,而对于占位符对应的参数是输出类型(INOUT),则调用CallableStatement对象的registerOutParameter(…)方法,该方法第一个参数指明替代第几个占位符,第二个参数指明该存储过程的输出参数在数据库中的SQL类型,在Java程序中可以使用Types类的字段指定。
最后通过CallableStatement对象的execute()方法执行存储过程,即可通过getXXX方法获取prepareCall方法参数中占位符类型为输出的参数值。
下面通过一个例子来说明。
例:
我们现在数据库中自定义一个存储过程,这个存储过程的功能是在我们传入的每一个字符串参数面前加上一段字符串,即将两端字符串连接,最后返回:
delimiter //
create procedure addPrefix(in inputParam varchar(255),inout inOutParam varchar(255))
begin
select concat('long live sd...',inputParam) into inOutParam;
end //
delimiter ;
分析:第一行我们将MySQL中的分隔符先定义为“//”,因为等会在存储过程的逻辑代码中会使用到“;”,不先定义别的分隔符的话逻辑代码还没写完数据库就执行了。第二行定义存储过程的名称,同时在参数列表中定义参数输入输出类型(IN,OUT,INOUT),参数名称,参数类型(SQL数据类型)。第三行开始以关键字“BEGIN”开始,以“END”和刚才定义的分隔符结束,在这两个中间就是平常的SQL语句了,也就是在这个部分编写我们处理参数的逻辑。最后,我们将MySQL数据库的分隔符重新定义回分号“;”。
注:在数据库中定义存储过程时,应先选择使用的库,这里我使用jdbcdemo库。
这里顺便一说在MySQL中如何使用SQL命令来调用存储过程,对于我们上面刚刚创建的存储过程,可以使用如下SQL命令语句来调用和查看结果:
set @inputParam = 'LRR'; call addPrefix(@inputParam,@result); select @result;
因为我们使用到了输入参数,因此在调用存储过程之前需要先设置好输入类型In的参数,在MySQL中,使用“@”代表该参数是一个用户变量,而对于输出类型out或inout也需要一个自定义用户变量,最后由select将结果显示,结果如下图所示:
(注:用户变量在退出MySQL命令行窗口后会自动释放资源)
下面开始介绍在Java中如何调用数据库中的存储过程。
创建Java工程,在工程中导入数据库连接驱动的jar包。在【src】目录下新建一个database.properties文件,内容如下:
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/jdbcdemo
username=root
password=root
构建JDBC的工具类,包括注册驱动,获取连接,释放资源和连接等,这部分同《JDBC操作数据库的学习(2)》中相同,此处略。
接着,我们将使用JDBC来调用上面刚刚定义的存储过程:
1 public void callableTest() throws SQLException {
2 Connection conn = null;
3 CallableStatement st = null;
4 ResultSet rs = null;
5 try{
6 conn = JdbcUtils.getConnection();
7 st = conn.prepareCall("{call addPrefix(?,?)}");
8 st.setString(1, "love LRR");
9 st.registerOutParameter(2, Types.VARCHAR);
10 st.execute();
11 String contactPrefix = st.getString(2);
12 System.out.println(contactPrefix);
13
14 }finally{
15 JdbcUtils.release(conn, st, rs);
16 }
17 }
观察程序运行结果:
CallableStatement对象是Statement对象的子类,因此在调用JdbcUtils.release方法时使用了多态。在prepareCall方法中的参数是指定调用哪个存储过程的字符串,同时使用到了占位符,那么通过CallableStatement对象对传入类型的参数设置要替代占位符的数据,而对于输出类型的参数则调用registerOutParameter方法替代占位符并指定SQL类型。在Java中Types类封装了各种SQL类型的字段。
以上就是如何使用JDBC调用MySQL数据库中的存储过程的步骤。