我们知道:存储过程是预先写好的一组SQL语句。
创建存储过程的使用CREAT PROCEDURE语句,语法如下:
CREATE PROCEDURE procedure_name
参数定义
AS
存储过程主体SQL语句
在调用时,存储过程的名称及指定的参数通过JDBC连接发送给DBMS,执行存储过程并通过连接(如果有)返回结果。
使用存储过程拥有和使用基于EJB或CORBA这样的应用服务器一样的好处。区别是存储过程可以从很多流行的DBMS中免费使用,而应用服务器大都非常昂贵。这并不只是许可证费用的问题。使用应用服务器所需要花费的管理、编写代码的费用,以及客户程序所增加的复杂性,都可以通过DBMS中的存储过程所整个地替代。
你可以使用Java,Python,Perl或C编写存储过程,但是通常使用你的DBMS所指定的特定语言。Oracle使用PL/SQL,PostgreSQL使用pl/pgsql,DB2使用Procedural SQL。这些语言都非常相似。并且,存储过程是为嵌入SQL所设计,这使得它们比Java或C等语言更加友好地方式表达数据库的机制。
存储过程保存在数据库中,以后可以反复调用,并可单独修改维护。因为存储过程运行在DBMS自身,这可以帮助减少应用程序中的等待时间。不是在Java代码中执行5个或8个SQL语句,而只需要在服务器端执行1个存储过程,这样能减少网络流量。
JDBC通过CallableStatement类支持存储过程的调用。该类实际上是PreparedStatement的一个子类。
假设我们数据库里面有张表叫users,定义如下:
CREATE TABLE users (
userid int IDENTITY (1, 1) NOT NULL PRIMARY KEY,
username varchar (20) NOT NULL ,
userage tinyint NOT NULL,
CHECK (userage > 1 and userage < 100)
)
该数据库中有一个插入记录的存储过程:insertUserProcedure:
CREATE PROCEDURE insertUserProcedure
@userid int output,
@username varchar(20),
@userage tinyint
As Set NOCOUNT ON
If Exists (select userid from users Where username =@username) RETURN 0
ELSE
Begin
INSERT INTO users (username,userage) VALUES(@username,@userage) SET @userid=@@IDENTITY RETURN 1
End
GO
调用代码如下:
Class.forName("com.microsoft.jdbc.sqlserver.SQLServerDriver").newInstance();
String url="jdbc:sqlserver://localhost:1433;databaseName=test;user=alex;password=Abcd1234";
Connection conn = null;
CallableStatement cstmt = null;
try
{
conn = DriverManager.getConnection(url);
cstmt = conn.prepareCall("{? = call insertUserProcedure(?,?,?)}");
cstmt.registerOutParameter(1,Types.TINYINT);
cstmt.setString(2,"alex"); //插入新记录的时候修改这里,因为在存储过程约束了username的唯一性。
cstmt.setInt(3,50);
cstmt.registerOutParameter(4,Types.INTEGER);
cstmt.execute();
int returnValue =cstmt.getInt(1);
int userid = cstmt.getInt(4);
if(returnValue == 1)
{
out.println("Insert Success!");
out.println("UserID = " + userid);
out.println("returnValue = " + returnValue);
}
else
{
out.println("Insert Failure!");
}
}
catch(Exception ex)
{
out.print("=== "+ex.getLocalizedMessage());
}
finally
{
try
{
if(cstmt != null)
{
cstmt.close();
cstmt = null;
}
if(conn != null)
{
conn.close();
conn = null;
}
}
catch(Exception e)
{
e.printStackTrace();
}
}
如果指定了错误的返回值类型会怎样?那么,当调用存储过程时将抛出一个RuntimeException,正如你在ResultSet操作中使用了一个错误的类型所碰到的一样。
如果返回的是集合,则把返回结果转化为ResultSet,然后通过循环遍历集合:
ResultSet rs = (ResultSet) cstmt.getObject(1);
while (rs.next()) {
String username = rs.getString("username");
int userage = rs.getInt("userage");
out.println(username + " is " + userage+ "years old");
}