7

我正在使用自定义标签创建登录页面,在下面的代码中,我想执行一个存储的 oracle 函数,该函数将采用 2 个参数(名称、密码)进行身份验证并返回一个数字。但是当我编译下面的代码时,它给出了一个错误说(找到: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;
4

5 回答 5

13

要执行一个函数,规范的方法是使用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像往常一样使用 a 来提取值:

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

}
于 2014-09-07T13:26:52.813 回答
4

首先,您说 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 语法。

于 2013-10-12T13:59:00.603 回答
1

其他人建议通过 select 语句运行查询,但是如果该函数执行任何 DML,这将引发异常。使用 CallableStatement 是最好的选择。

于 2016-06-24T03:35:18.027 回答
1

这是使用 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)
    }
}
于 2020-05-12T12:44:21.817 回答
0

executeUpdate()退货int,请参阅此处了解更多详细信息。我相信你期待一个ResultSet

更改以下行,

 rs=stmt.executeUpdate();

rs=stmt.executeQuery();

有关详细信息,请参阅executeQuery

于 2013-10-12T11:09:59.107 回答