Home>Article>Java> How to call stored procedure in Java

How to call stored procedure in Java

王林
王林 forward
2023-05-05 19:49:04 2262browse

Stored procedurerefers to a program that is saved in the database and executed on the database side. You can call stored procedures from Java classes using special syntax. When called, the name of the stored procedure and the specified parameters are sent to the DBMS through the JDBC connection, the stored procedure is executed and the results are returned through the connection (if any).

Using stored procedures has the same benefits as using an application server based on EJB or CORBA. The difference is that stored procedures are available for free from many popular DBMSs, while application servers are mostly very expensive. It's not just about license fees. The management and coding costs of using an application server, as well as the added complexity of client programs, can all be replaced by stored procedures in a DBMS.

You can write stored procedures in Java, Python, Perl, or C, but generally use the specific language specified by your DBMS. Oracle uses PL/SQL, PostgreSQL uses pl/pgsql, and DB2 uses Procedural SQL. These languages are all very similar. Migrating stored procedures between them is no more difficult than migrating Session Beans between different implementations of Sun's EJB specification. Moreover, stored procedures are designed for embedding SQL, which makes them a more friendly way to express the database mechanism than languages such as Java or C.

Because stored procedures run in the DBMS itself, this can help reduce waiting time in the application. Instead of executing 4 or 5 SQL statements in Java code, only 1 stored procedure needs to be executed on the server side. Reducing the number of data round-trips on the network can dramatically improve performance.

Using stored procedures

Simple old JDBC supports the invocation of stored procedures through the CallableStatement class. This class is actually a subclass of PreparedStatement. Suppose we have a poets database. There is a stored procedure in the database that sets the poet's death age. The following is the detailed code for calling old soak Dylan Thomas (old soak Dylan Thomas, do not specify whether it is related to allusions or culture, please criticize and correct. Translation):

try{ int age = 39; String poetName = "dylan thomas"; CallableStatement proc = connection.prepareCall("{ call set_death_age(?, ?) }"); proc.setString(1, poetName); proc.setInt(2, age); cs.execute(); }catch (SQLException e){ // ....}

The string passed to the prepareCall method is a stored procedure Writing convention for calls. It specifies the name of the stored procedure,? Represents the parameters you need to specify. Integration with JDBC is a great convenience for stored procedures: in order to call stored procedures from an application, no stub classes or configuration files are required, nothing is required except your DBMS's JDBC driver.

When this code is executed, the database's stored procedure is called. We did not get the result because the stored procedure does not return a result. Success or failure of execution will be known through exceptions. Failure may mean a failure in calling the stored procedure (such as supplying a parameter of an incorrect type), or an application failure (such as throwing an exception indicating that "Dylan Thomas" does not exist in the poems database)

Combining SQL operations with stored procedures

Mapping Java objects to rows in a SQL table is fairly simple, but usually requires executing several SQL statements; perhaps a SELECT to find the ID, and then An INSERT inserts data with a specified ID. In a highly normalized database schema, updates to multiple tables may be required, thus requiring more statements. Java code can grow quickly, and the network overhead of each statement can quickly increase.

Moving these SQL statements into a stored procedure will greatly simplify the code, involving only one network call. All associated SQL operations can occur inside the database. Also, stored procedure languages, such as PL/SQL, allow the use of SQL syntax, which is more natural than Java code. The following is our early stored procedure, written in Oracle's PL/SQL language:

create procedure set_death_age(poet VARCHAR2, poet_age NUMBER) poet_id NUMBER; begin SELECT id INTO poet_id FROM poets WHERE name = poet; INSERT INTO deaths (mort_id, age) VALUES (poet_id, poet_age); end set_death_age;

Is it unique? No. I bet you were expecting to see an UPDATE on the poets table. This also hints at how easy it is to implement using stored procedures. set_death_age is almost certainly a bad implementation. We should add a column to the poets table to store the death age. The Java code doesn't care how the database schema is implemented, because it only calls stored procedures. We can change the database schema later to improve performance, but we don't have to modify our code.

The following is the Java code that calls the above stored procedure:

public static void setDeathAge(Poet dyingBard, int age) throws SQLException{ Connection con = null; CallableStatement proc = null; try { con = connectionPool.getConnection(); proc = con.prepareCall("{ call set_death_age(?, ?) }"); proc.setString(1, dyingBard.getName()); proc.setInt(2, age); proc.execute(); } finally { try { proc.close(); } catch (SQLException e) {} con.close(); } }

In order to ensure maintainability, it is recommended to use a static method like here. This also concentrates the code that calls the stored procedure into a simple template code. If you use a lot of stored procedures, you'll find that you can create new methods by just copying and pasting. Because of the templating of the code, it is even possible to automatically generate code that calls stored procedures through scripts.

Functions

Stored procedures can have return values, so the CallableStatement class has methods like getResultSet to obtain the return value. When a stored procedure returns a value, you must use the registerOutParameter method to tell the JDBC driver what the SQL type of the value is. You must also adjust the stored procedure call to instruct the procedure to return a value.

The following follows the above example. This time we look up Dylan Thomas’s age at the time of his death. This time the stored procedure uses PostgreSQL’s pl/pgsql:

create function snuffed_it_when (VARCHAR) returns integer 'declare poet_id NUMBER; poet_age NUMBER; begin --first get the id associated with the poet. SELECT id INTO poet_id FROM poets WHERE name = $1; --get and return the age. SELECT age INTO poet_age FROM deaths WHERE mort_id = poet_id; return age; end;' language 'pl/pgsql';

另外,注意pl/pgsql参数名通过Unix和DOS脚本的$n语法引用。同时,也注意嵌入的注释,这是和Java代码相比的另一个优越性。在Java中写这样的注释当然是可以的,但是看起来很凌乱,并且和SQL语句脱节,必须嵌入到Java String中。

下面是调用这个存储过程的Java代码:

connection.setAutoCommit(false); CallableStatement proc = connection.prepareCall("{ ? = call snuffed_it_when(?) }"); proc.registerOutParameter(1, Types.INTEGER); proc.setString(2, poetName); cs.execute(); int age = proc.getInt(2);

如果指定了错误的返回值类型会怎样?那么,当调用存储过程时将抛出一个RuntimeException,正如你在ResultSet操作中使用了一个错误的类型所碰到的一样。

复杂的返回值

关于存储过程的知识,很多人好像就熟悉我们所讨论的这些。如果这是存储过程的全部功能,那么存储过程就不是其它远程执行机制的替换方案了。存储过程的功能比这强大得多。

当你执行一个SQL查询时,DBMS创建一个叫做cursor(游标)的数据库对象,用于在返回结果中迭代每一行。ResultSet是当前时间点的游标的一个表示。这就是为什么没有缓存或者特定数据库的支持,你只能在ResultSet中向前移动。

某些DBMS允许从存储过程中返回游标的一个引用。JDBC并不支持这个功能,但是Oracle、PostgreSQL和DB2的JDBC驱动器都支持在ResultSet上打开到游标的指针(pointer)。

设想列出所有没有活到退休年龄的诗人,下面是完成这个功能的存储过程,返回一个打开的游标,同样也使用PostgreSQL的pl/pgsql语言:

create procedure list_early_deaths () return refcursor as 'declare toesup refcursor; begin open toesup for SELECT poets.name, deaths.age FROM poets, deaths -- all entries in deaths are for poets. -- but the table might become generic. WHERE poets.id = deaths.mort_id AND deaths.age < 60; return toesup; end;' language 'plpgsql';

下面是调用该存储过程的Java方法,将结果输出到PrintWriter:

PrintWriter: static void sendEarlyDeaths(PrintWriter out){ Connection con = null; CallableStatement toesUp = null; try { con = ConnectionPool.getConnection(); // PostgreSQL needs a transaction to do this... con. setAutoCommit(false); // Setup the call. CallableStatement toesUp = connection.prepareCall("{ ? = call list_early_deaths () }"); toesUp.registerOutParameter(1, Types.OTHER); toesUp.execute(); ResultSet rs = (ResultSet) toesUp.getObject(1); while (rs.next()) { String name = rs.getString(1); int age = rs.getInt(2); out.println(name + " was " + age + " years old."); } rs.close(); } catch (SQLException e) { // We should protect these calls. toesUp.close(); con.close(); } }

因为JDBC并不直接支持从存储过程中返回游标,我们使用Types.OTHER来指示存储过程的返回类型,然后调用getObject()方法并对返回值进行强制类型转换。

这个调用存储过程的Java方法是mapping的一个好例子。Mapping是对一个集上的操作进行抽象的方法。不是在这个过程上返回一个集,我们可以把操作传送进去执行。本例中,操作就是把ResultSet打印到一个输出流。这是一个值得举例的很常用的例子,下面是调用同一个存储过程的另外一个方法实现:

public class ProcessPoetDeaths{ public abstract void sendDeath(String name, int age); } static void mapEarlyDeaths(ProcessPoetDeaths mapper){ Connection con = null; CallableStatement toesUp = null; try { con = ConnectionPool.getConnection(); con.setAutoCommit(false); CallableStatement toesUp = connection.prepareCall("{ ? = call list_early_deaths () }"); toesUp.registerOutParameter(1, Types.OTHER); toesUp.execute(); ResultSet rs = (ResultSet) toesUp.getObject(1); while (rs.next()) { String name = rs.getString(1); int age = rs.getInt(2); mapper.sendDeath(name, age); } rs.close(); } catch (SQLException e) { // We should protect these calls. toesUp.close(); con.close(); } }

这允许在ResultSet数据上执行任意的处理,而不需要改变或者复制获取ResultSet的方法:

static void sendEarlyDeaths(final PrintWriter out){ ProcessPoetDeaths myMapper = new ProcessPoetDeaths() { public void sendDeath(String name, int age) { out.println(name + " was " + age + " years old."); } }; mapEarlyDeaths(myMapper); }

这个方法使用ProcessPoetDeaths的一个匿名实例调用mapEarlyDeaths。该实例拥有sendDeath方法的一个实现,和我们上面的例子一样的方式把结果写入到输出流。当然,这个技巧并不是存储过程特有的,但是和存储过程中返回的ResultSet结合使用,是一个非常强大的工具。

The above is the detailed content of How to call stored procedure in Java. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:yisu.com. If there is any infringement, please contact admin@php.cn delete