[英]how to call a stored function from jdbc?
我正在使用自定義標簽創建登錄頁面,在下面的代碼中,我想執行一個存儲的 oracle 函數,該函數將采用 2 個參數(名稱、密碼)進行身份驗證並返回一個數字。 但是當我編譯下面的代碼時,它給出了一個錯誤,說 ( found: int) 不兼容的類型。 請告訴我我哪里錯了? 我是否正確調用了該函數?
package pack.java;
import pack.java.MyModel;
import java.io.*;
import java.lang.*;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;
import javax.servlet.jsp.tagext.*;
import java.sql.*;
public class MyController extends TagSupport
{
HttpServletRequest request;
HttpServletResponse response;
public int doStartTag()throws JspException
{
request = (HttpServletRequest)pageContext.getRequest();
response = (HttpServletResponse)pageContext.getResponse();
return EVAL_PAGE;
}
public void check()
{
HttpSession mysession = request.getSession();
Connection con;
CallableStatement stmt;
JspWriter out = pageContext.getOut();
try {
Class.forName("oracle.jdbc.driver.OracleDriver");
}
catch(ClassNotFoundException ex) {}
try {
String aa = (String)MyModel.name.trim();
String bb = (String)MyModel.pass.trim();
con = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:XE","gaurav","oracle");
stmt = con.prepareCall("select usercheck1(?,?) from dual");
stmt.setString(1, aa);
stmt.setString(2, bb);
rs = stmt.executeQuery();
try {
while (rs.next()) {
String empid = rs.getString (1);
mysession.setAttribute("user", empid);
if (empid != null) {
response.sendRedirect("/Myjsp/selectaction.jsp");
}
else
out.println("InValid User");
}
}
catch(Exception ex) {}
}
catch(SQLException ex) {}
}
public int doEndTag() throws JspException {
check();
return EVAL_PAGE;
}
}
下面是存儲的函數
create or replace function usercheck1
(uname varchar2, upass varchar2)
return number
as
numb number;
begin
select (employe_id)
into numb
from record
where name = uname
and password = upass;
return numb;
end usercheck1;
/
使用以下語句執行函數
select usercheck1 ('ghg','aa') from dual;
要執行函數,規范的方法是使用CallableStatement
。 這是PreparedStatement
一個特例(子類)。
此外,您必須使用registerOutParameter
方法之一指定正確的輸出參數類型。 一旦調用完成 ( execute
),您就可以從語句本身中提取輸出值。 不是通過ResultSet
。
所有這些都會導致類似的事情:
CallableStatement stmt = con.prepareCall("{? = call usercheck1(?, ?)}");
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
# Prepare a `call`
stmt.registerOutParameter(1, Types.INTEGER);
# Setup out parameter type ^^^^^^^^^^^^^
stmt.setString(2,aa);
stmt.setString(3,bb);
stmt.execute();
# ^^^^^^^
# execute the statement
int output = stmt.getInt(1);
# ^^^^^^^^^^^
# Extract the result from the statement itself
一種完全不同的做法是實際使用SELECT
查詢來調用該函數。 這是 OP 在問題中提出的建議。 這樣,您可以像往常一樣使用ResultSet
來提取值:
PreparedStatement stmt = con.prepareStatement("SELECT usercheck1(?, ?) FROM DUAL");
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
# Prepare a statement
stmt.setString(2,aa);
stmt.setString(3,bb);
ResultSet rs = stmt.executeQuery();
# ^^^^^^^^^^^^
# execute the query
while(rs.next()) {
int output = rs.getInt(1);
# ^^^^^^^^^
# Extract the result from the `ResultSet`
# ...
# do whatever you want with the data
}
首先,您說 proc 返回一個數字,但您的代碼期望返回一個字符串的結果集? 無論如何,假設您的 proc 返回一個 int。 更改這些行
stmt=con.prepareCall("call usercheck1(?,?)");
stmt.setString(1,aa);
stmt.setString(2,bb);
rs=stmt.executeUpdate();
到
stmt=con.prepareCall ("{? = call usercheck1(?, ?)}");
stmt.registerOutParameter (1, Types.INTEGER);
stmt.setString(2,aa);
stmt.setString(3,bb);
stmt.execute();
int output =stmt.getInt (1);
如果您實際上期望來自 proc 的結果是一個字符串,則更改為
stmt=con.prepareCall ("{? = call usercheck1(?, ?)}");
stmt.registerOutParameter (1, Types.VARCHAR2);
stmt.setString(2,aa);
stmt.setString(3,bb);
stmt.execute();
String output =stmt.getString (1);
ResultSets 用於游標,並且需要您指定您的輸出參數。 希望有幫助。
http://docs.oracle.com/cd/A84870_01/doc/java.816/a81354/samapp2.htm
如果您使用的是較新版本的 oracle >= 9i,您可能需要使用 begin end 語法。
其他人建議通過 select 語句運行查詢,但如果該函數執行任何 DML,這將引發異常。 使用 CallableStatement 是最好的選擇。
executeUpdate()
返回int
,有關更多詳細信息,請參見此處。 我相信你期待一個ResultSet
,
更改以下行,
rs=stmt.executeUpdate();
到
rs=stmt.executeQuery();
有關更多信息,請參閱executeQuery 。
這是使用 JPA ( javax.persistence.EntityManager
) 的更現代的解決方案:
@PersistenceContext
private EntityManager entityManager;
. . .
final int myResult;
Session session = entityManager.unwrap(Session.class);
session.doWork(connection -> {
try (CallableStatement function =
connection.prepareCall("{ ? = call usercheck1(?, ?) }")) {
function.registerOutParameter(1, Types.INTEGER);
function.setString(2, aa);
function.setString(3, bb);
function.execute();
myResult = function.getInt(1);
}
} );
這些是指示解決方案適用的 lib 版本的主要依賴項:
compile 'com.oracle:ojdbc6:11.2.0.4.0'
compile 'org.hibernate:hibernate-core:5.4.7.Final'
compile 'org.hibernate.javax.persistence:hibernate-jpa-2.1-api:1.0.2.Final'
作為doWork()
的替代方法並使用getXxx(1)
分配存儲的函數結果,您可以使用doReturningWork()
。
這是 Kotlin 中的解決方案(並使用doReturningWork
):
@PersistenceContext
lateinit var entityManager: EntityManager
. . .
val session : Session = entityManager.unwrap(Session::class.java)
var myResult = session.doReturningWork { connection: Connection ->
connection.prepareCall("{ ? = call usercheck1(?, ?) }").use { function ->
function.registerOutParameter(1, Types.INTEGER)
function.setString(2, aa)
function.setString(3, bb)
function.execute()
return@doReturningWork function.getInt(1)
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.