sql

JDBC CallableStatement with Oracle Stored Procedure Example Tutorial

In this Article We will learn how to use JDBC CallableStatement along with Stored Procedures, Cursors, STRUCT etc. The CallableStatement interface used to execute SQL stored procedures. The JDBC API provides a stored procedure SQL escape syntax that allows stored procedures to be called in a standard way for all RDBMSs. For this Example we have used Oracle Database. We will start by using CallableStatement with IN and OUT parameters. Later on we will look into Oracle specific STRUCT and Cursor examples.
 
 
 
 
 

1. Stored Procedure With IN, OUT Parameters

Stored Procedures are group of statements that we compile in the database for some task. Stored procedures are beneficial when we are dealing with multiple tables with complex scenario and rather than sending multiple queries to the database, we can send required data to the stored procedure and have the logic executed in the database server itself.

1.1 Table and Stored Procedure

So let us start by creating the table in Oracle:

CREATE TABLE STUDENT (
SID NUMBER(3,0) PRIMARY KEY,
FNAME VARCHAR2(10) NOT NULL,
LNAME VARCHAR2(10),
DEPT VARCHAR2(10) DEFAULT 'N/A',
year number(1,0),
email varchar2(30)
);

It is a simple table to store students’s data in a college or university. I have also used a stored procedure to insert data into this table.

insert_proc.sql:

CREATE OR REPLACE PROCEDURE insertStudent(fname in varchar2,lname in varchar2,dept in varchar2,year in number,email in varchar2,sid out number)
AS
max_id NUMBER(3);
new_id NUMBER(3);
BEGIN

SELECT NVL(MAX(SID),0) INTO max_id FROM STUDENT;
new_id:=max_id+1;

INSERT INTO STUDENT VALUES(new_id,fname,lname,dept,year,email);
sid:=new_id;
commit;

EXCEPTION
  WHEN OTHERS THEN
  NEW_ID:=-1;
  ROLLBACK;
END;
/

This Stored Procedure will receive all Student data except SID(Student ID) as the parameters and insert them to the table while creating the SID itself. Then it will return the ID.

1.2 Using Through Java

To establish the connection between Java & Oracle you have to copy the ojdbc Jar file from the oracle server directory to your project library or add it to the build path.

StoredProc.java:

package CallableStatementExample;

import java.sql.*;
import java.util.Scanner;

import oracle.jdbc.*;

public class StoredProc {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Scanner sc=new Scanner(System.in);
		Connection cn=null;
		CallableStatement cst=null;
		int id=0,yr;
		String fname,lname,email,dept;
		try{
			DriverManager.registerDriver(new OracleDriver());
			cn=DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:xe", "hr", "hr");
			
			cst=cn.prepareCall("{call insertStudent(?,?,?,?,?,?)}");
			System.out.println("Enter Student's First Name: ");
			fname=sc.nextLine();
			System.out.println("Enter Student's Last Name: ");
			lname=sc.nextLine();
			System.out.println("Enter Student's Email: ");
			email=sc.nextLine();
			System.out.println("Enter Student's Year: ");
			yr=Integer.parseInt(sc.nextLine());
			System.out.println("Enter Student's Dept: ");
			dept=sc.nextLine();
			
			cst.setString(1, fname);
			cst.setString(2,lname);
			cst.setString(3,dept);
			cst.setInt(4, yr);
			cst.setString(5, email);
			
			 cst.registerOutParameter(6, java.sql.Types.DECIMAL);
			
			int r=cst.executeUpdate();
			if(r>0)
				id=cst.getInt(6);
			
			if(id>0)
				System.out.println("Details Inserted. SID: "+id);
			
		}catch(Exception e)
		{
			e.printStackTrace();
		}
		finally{
			try{
				if(cst!=null)
					cst.close();
				
				if(cn!=null)
					cn.close();
			}catch(Exception e){}
		}
	}

}

Output

Enter Student's First Name: 
Esha
Enter Student's Last Name: 
Chkty
Enter Student's Email: 
esha.chk
Enter Student's Year: 
2
Enter Student's Dept: 
CST
Details Inserted. SID: 3

1.3 Explanation

In the above example we have read user inputs, then we assigned that to the CallableStatement input parameters using setString() and setInt() methods as applicable.

We have registered the out parameter by the registerOutParameter() method. This method registers the OUT parameter in ordinal position parameterIndex to the JDBC type sqlType. All OUT parameters must be registered before a stored procedure is executed.

The JDBC type specified by sqlType for an OUT parameter determines the Java type that must be used in the get method to read the value of that parameter. If the JDBC type expected to be returned to this output parameter is specific to this particular database, sqlType should be java.sql.Types.OTHER. The method getObject(int) retrieves the value.

2.CallableStatement with Stored Procedure Oracle CURSOR

What if we use an Oracle cursor to retrieve and manipulate the data and then we return the cursor it self rather than the values separately!! The JDBC CallableStatement also provides a solution for such problem.

Here we will retrieve the records stored in a table using Oracle Cursor, Stored Procedure & JDBC CallableStatement.

cursr_proc.sql:

CREATE OR REPLACE PROCEDURE studenyByDept(dpt in varchar2,data out SYS_REFCURSOR)
AS
BEGIN
OPEN data FOR SELECT SID,FNAME,LNAME,DEPT,YEAR,EMAIL FROM STUDENT WHERE DEPT=dpt;
END;
/

StoredProcCursr.java:

package CallableStatementExample;

import java.sql.*;
import java.util.Scanner;

import oracle.jdbc.*;

public class StoredProc {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Scanner sc=new Scanner(System.in);
		Connection cn=null;
		CallableStatement cst=null;
		int id=0,yr;
		String fname,lname,email,dept;
		try{
			DriverManager.registerDriver(new OracleDriver());
			cn=DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:xe", "hr", "hr");
			
			cst=cn.prepareCall("{call insertStudent(?,?,?,?,?,?)}");
			System.out.println("Enter Student's First Name: ");
			fname=sc.nextLine();
			System.out.println("Enter Student's Last Name: ");
			lname=sc.nextLine();
			System.out.println("Enter Student's Email: ");
			email=sc.nextLine();
			System.out.println("Enter Student's Year: ");
			yr=Integer.parseInt(sc.nextLine());
			System.out.println("Enter Student's Dept: ");
			dept=sc.nextLine();
			
			cst.setString(1, fname);
			cst.setString(2,lname);
			cst.setString(3,dept);
			cst.setInt(4, yr);
			cst.setString(5, email);
			
			 cst.registerOutParameter(6, java.sql.Types.DECIMAL);
			
			int r=cst.executeUpdate();
			if(r>0)
				id=cst.getInt(6);
			
			if(id>0)
				System.out.println("Details Inserted. SID: "+id);
			
		}catch(Exception e)
		{
			e.printStackTrace();
		}
		finally{
			try{
				if(cst!=null)
					cst.close();
				
				if(cn!=null)
					cn.close();
			}catch(Exception e){}
		}
	}

}

Output

Enter Department Name to Search : 
Comp. Sc.
Student ID: 1 Name : Esha Dey Dept: Comp. Sc. Year:3 EMail: esha.dey
Student ID: 2 Name : Rivu Chk Dept: Comp. Sc. Year:4 EMail: rivuchk@jcg
Student ID: 4 Name : Ilias Tsagkills Dept: Comp. Sc. Year:4 EMail: ilias@jcg
Student ID: 5 Name : Byron Kiourtzogl Dept: Comp. Sc. Year:4 EMail: byron@jcg
Student ID: 6 Name : Nikos Maravitsas Dept: Comp. Sc. Year:4 EMail: nikos@jcg

3. Using Oracle DB Objects

Have you ever wondered that if we use Oracle DB Objects in our database (which is very common) then how to retrieve those records in our java program!! Well we have a solution for that too. Oracle DB Objects can be easily fetched using STRUCT. We will fist create an Object for address, then we will redesign the table to store the students address.

3.1 Create Oracle DB Object and Redesign the Table

Creating Object:

cr_obj.sql:

CREATE TYPE ADDRESS_OB AS OBJECT(STREET VARCHAR2(50),CITY VARCHAR2(25),STATE VARCHAR2(25),COUNTRY VARCHAR2(25));
/

Adding Column to store Student’s Address:

alter_table.sql:

ALTER TABLE STUDENT ADD(ADDRESS ADDRESS_OB);
/

3.2 Inserting from Java using Object

Rewriting the insert_proc.sql stored procedure to store the students address.

insert_proc.sql:

CREATE OR REPLACE PROCEDURE insertStudent(fname in varchar2,lname in varchar2,dept in varchar2,year in number,email in varchar2,address in address_ob,sid out number)
AS
max_id NUMBER(3);
new_id NUMBER(3);
BEGIN

SELECT NVL(MAX(SID),0) INTO max_id FROM STUDENT;
new_id:=max_id+1;

INSERT INTO STUDENT VALUES(new_id,fname,lname,dept,year,email,address);
sid:=new_id;
commit;
EXCEPTION
  WHEN OTHERS THEN
  NEW_ID:=-1;
  ROLLBACK;
END;
/

StoredProcStruct.java:

package callableStatementExample;

import java.sql.*;
import java.util.Scanner;

import oracle.jdbc.*;
import oracle.sql.STRUCT;
import oracle.sql.StructDescriptor;


public class StoredProcStruct {
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Scanner sc=new Scanner(System.in);
		Connection cn=null;
		OracleCallableStatement cst=null;
		int id=0,yr;
		String fname,lname,email,dept;
		String[] addressObj=new String[4];
		try{
			DriverManager.registerDriver(new OracleDriver());
			cn=DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:xe", "hr", "hr");
			
			
			System.out.println("Enter Student's First Name: ");
			fname=sc.nextLine();
			System.out.println("Enter Student's Last Name: ");
			lname=sc.nextLine();
			System.out.println("Enter Student's Email: ");
			email=sc.nextLine();
			System.out.println("Enter Student's Year: ");
			yr=Integer.parseInt(sc.nextLine());
			System.out.println("Enter Student's Dept: ");
			dept=sc.nextLine();
			System.out.println("Enter Address:");
			System.out.println("Enter Street Name:");
			addressObj[0]=sc.nextLine();
			System.out.println("Enter City:");
			addressObj[1]=sc.nextLine();
			System.out.println("Enter State:");
			addressObj[2]=sc.nextLine();
			System.out.println("Enter Country:");
			addressObj[3]=sc.nextLine();
			
			//Creating StructDescriptor
			StructDescriptor addressSD=StructDescriptor.createDescriptor("ADDRESS_OB", cn);
			STRUCT addrSTRUCT=new STRUCT(addressSD,cn,addressObj);
			
			cst=(OracleCallableStatement)cn.prepareCall("{call insertStudentObj(?,?,?,?,?,?,?)}");
			
			cst.setString(1, fname);
			cst.setString(2,lname);
			cst.setString(3,dept);
			cst.setInt(4, yr);
			cst.setString(5, email);
			cst.setSTRUCT(6, addrSTRUCT);
			
			 cst.registerOutParameter(7, java.sql.Types.DECIMAL);
			
			int r=cst.executeUpdate();
			if(r>0)
				id=cst.getInt(7);
			
			if(id>0)
				System.out.println("Details Inserted. SID: "+id);
			
		}catch(Exception e)
		{
			e.printStackTrace();
		}
		finally{
			try{
				if(cst!=null)
					cst.close();
				
				if(cn!=null)
					cn.close();
			}catch(Exception e){}
		}
	}

}

Output

Enter Student's First Name: 
Nandan
Enter Student's Last Name: 
Banerjee
Enter Student's Email: 
hellonandan
Enter Student's Year: 
4
Enter Student's Dept: 
Comp. Sc.
Enter Address:
Enter Street Name:
Amta
Enter City:
Howrah
Enter State:
WB
Enter Country:
India
Details Inserted. SID: 7

3.3 Explanation

First of all we are creating an String array of same length as the ADDRESS_OB database object. Then we are setting values according to the ADDRESS_OB object variables. This is very important otherwise the data will get inserted into wrong columns.

Then we are creating oracle.sql.STRUCT object with the help of oracle.sql.StructDescriptor and our Object array. Once the STRUCT object is created, we are setting it as IN parameter for the stored procedure, register the OUT parameter and executing it. This code is tightly couple with OJDBC API and will not work for other databases.

Here we used the OracleCallableStatement instead of CallableStatement to deal the STRUCT as CallableStatement does not support STRUCT but OracleCallableStatement does.

3.4 Using Struct to Fetch Row

SQL File to Read Table Data:

struct_cursr_proc.sql:

CREATE OR REPLACE PROCEDURE studentsAllwithAddress(data out SYS_REFCURSOR)
AS
BEGIN
OPEN data FOR SELECT SID,FNAME,LNAME,DEPT,YEAR,EMAIL,ADDRESS FROM STUDENT WHERE ADDRESS IS NOT NULL;
END;
/

FetchStruct.java:

package callableStatementExample;


import java.sql.*;
import java.util.Scanner;

import oracle.jdbc.*;
import oracle.sql.STRUCT;
import oracle.sql.StructDescriptor;

public class FetchStruct {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Scanner sc=new Scanner(System.in);
		Connection cn=null;
		OracleCallableStatement cst=null;
		OracleResultSet rs=null;
		int id=0,yr;
		String fname,lname,email,dept;
		try{
			DriverManager.registerDriver(new OracleDriver());
			cn=DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:xe", "hr", "hr");
			
			cst=(OracleCallableStatement)cn.prepareCall("{call studentsAllwithAddress(?)}");
									
			cst.registerOutParameter(1, OracleTypes.CURSOR);
			
			cst.execute();
			rs=(OracleResultSet)cst.getObject(1);
			
			while(rs.next())
			{
				System.out.println("Student ID: "+rs.getInt("SID")+" Name : "+rs.getString("FNAME")+" "+rs.getString("LNAME")+" Dept: "+rs.getString("DEPT")+" Year:"+rs.getInt("YEAR")+" EMail: "+rs.getString("EMAIL"));
				STRUCT addr=rs.getSTRUCT("ADDRESS");
				Object[] address=addr.getAttributes();
				System.out.println("Address:");
				for(Object adr:address)
				{
					System.out.print(adr.toString());
				}
			}			
			
		}catch(Exception e)
		{
			e.printStackTrace();
		}
		finally{
			try{
				if(rs!=null)
					rs.close();
				if(cst!=null)
					cst.close();
				
				if(cn!=null)
					cn.close();
			}catch(Exception e){}
		}
	}

}

Output

Student ID: 6 Name : Rajdeep Samanta Dept: Commerce Year:2 EMail: rajEgmail
Address:
Andul RoadHowrahWBIndiaStudent ID: 7 Name : Nandan Banerjee Dept: Comp. Sc. Year:4 EMail: hellonandan
Address:
AmtaHowrahWBIndia

3.5 Explanation

Here we fetched the row using Cursor then Retrieved it to the OracleResultSet object to fetch the STRUCT.

4. Download

This was an example of JDBC Callable Statement with Stored Procedure IN OUT, OracleCallableStatement with Struct & OracleResultSet.

Download
You can download the full source code of this example here : JDBCStoredProcedure.zip

Rivu Chakraborty

Rivu Chakraborty is a Google Certified Android Developer, Sr. Tech Member of Institute of Engineers (India), he also have certifications on Scrum. He is also an author of multiple books on Kotlin, Reactive Programming, Functional Programming and Android Development, published by renowned publication houses. Having total 5+ years of experience he is presently working as a Sr. Software Engineer (Android) at Indus Net Technologies Pvt. Ltd. Rivu Chakraborty considers himself a Kotlin and Android enthusiast and a Kotlin evangelist. He has been using Kotlin since December 2015, so he has around 2 years' experience in Kotlin. As part of his mission to expand the use and knowledge of the Kotlin Language as much as possible, he created the KotlinKolkata User Group, one of the most active Kotlin user groups throughout the world and he is a Founder Organizer of KotlinKolkata. He is also an active member of GDG Kolkata and gives talks at GDG Kolkata Meetups.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments
Back to top button