Stored Procedure caller; simply execute stored procedure from java code.
Compatible with jdk >= 1.5, with only single dependency (slf4j-api)
Suppose you have 3 Stored Procedures to save customer to database, get customer by id and list all customer.
For example here's SP code using HSQL:
CREATE PROCEDURE create_customer(firstname VARCHAR(50), lastname VARCHAR(50), OUT custId INT,
OUT code SMALLINT, OUT msg VARCHAR(50))
MODIFIES SQL DATA DYNAMIC RESULT SETS 1
BEGIN ATOMIC
INSERT INTO CUSTOMERS VALUES (DEFAULT, firstname, lastname);
SET custId = IDENTITY();
SET code = 0 -- success;
END
CREATE PROCEDURE get_customer(IN custId INT, OUT firstname VARCHAR(50), OUT lastname VARCHAR(50),
OUT code SMALLINT, OUT msg VARCHAR(50))
READS SQL DATA
BEGIN ATOMIC
SELECT first_name, last_name INTO firstname, lastname FROM customers WHERE id = custId;
SET code = 0 -- success;
END
CREATE PROCEDURE list_customers(OUT code SMALLINT, OUT msg VARCHAR(50))
READS SQL DATA DYNAMIC RESULT SETS 1
BEGIN ATOMIC
DECLARE result CURSOR FOR SELECT id, first_name firstname, last_name lastname FROM CUSTOMERS;
OPEN result;
SET code = 0 -- success;
ENDNOTE: Every Stored Procedure by default need to have 2 additional Output Parameters at the end of its parameter list. One of type
SMALLINTand the other of typeVARCHARfor result code and message respectively, where result code0means success. You can override the0value or remove this default behviour at all, see the configuration wiki page.
public interface CustomerDAO {
@StoredProc("create_customer")
void createCustomer(@Param(VARCHAR) String firstName, @Param(VARCHAR) String lastName);
@StoredProc("get_customer")
Customer getCustomer(@Param(INTEGER) Integer id);
@StoredProc("list_customers")
List<Customer> listCustomers();
}Before start using the CustomerDAO interface, one last step is required, to map the result of the get_customer and list_customers stored procedures.
get_customerstored procs returns the result as Output Parameters, so you need to have a class to implementTypedOutputParamMapperinterface.list_customersstored proc returns the result as Result Set, so you need to have a class to implementResultSetMapperinterface.
Let's create Customer class to implement both interfaces (for getCustomer and listCustomers):
public class Customer implements TypedOutputParamMapper<Customer>, ResultSetMapper<Customer> {
private Integer id;
private String firstName, lastName;
public Customer() {
}
public Customer(Integer id, String firstName, String lastName) {
super();
this.id = id;
this.firstName = firstName;
this.lastName = lastName;
}
public Integer id() {
return id;
}
public String firstName() {
return firstName;
}
public String lastName() {
return lastName;
}
//You can acess result set columns/output parameters by name as well
@Override
public Customer map(Result<?> result) {
if (result.isResultSet()) {
return new Customer(result.getInt(1), result.getString(2), result.getString(3));
} else {
return new Customer(null, result.getString(1), result.getString(2));
}
}
// for TypedOutputParamMapper
@Override
public List<Integer> getTypes() {
return Arrays.asList(VARCHAR, VARCHAR);
}
}See more examples on spwrap-examples github project and read more about Mappers in the wiki.
NOTE: If your stored procedure returns a single output parameter with no result set, then you can use the
@Scalarannotation and you will not need to provide a Mapper class yourself, the mapping will done for you. see wiki page about scalars for more
NOTE: You can use
@AutoMappers to do the mapping for you instead of Mapping the Result object into your domain object yourself.
Now you can start using the interface to call the stored procedures:
DataSource dataSource = ...
DAO dao = new DAO.Builder(dataSource).build();
CustomerDAO customerDao = dao.create(CustomerDAO.class);
customerDao.createCustomer("Abdullah", "Muhammad");
Customer customer = customerDao.getCustomer1(1);
Assert.assertEquals("Abdullah", customer.firstName());Gradle:
compile group: 'com.github.mhewedy', name: 'spwrap', version: '0.0.20'Maven:
<dependency>
<groupId>com.github.mhewedy</groupId>
<artifactId>spwrap</artifactId>
<version>0.0.20</version>
</dependency>-
If you don't supply the stored procedure name to
@StoredProc, it will use the method name by default. -
@Paramannotation should used for ALL method parameters and accepts the SQL Type perjava.sql.Types. -
If you don't want to tie your Domain Object with
spwrapas of step 3 above, you can have another class to implement the Mapper interfaces (TypedOutputParamMapperandResultSetMapper) and pass it to the annotaion@Mapperlike:
@Mapper(CustomResultSetMapper.class)
@StoredProc("list_customers")
List<Customer> listCustomers();-
@Mapperannotation overrides the mapping specified by the return type object, i.e.spwrapextract Mapping infromation from the return type class, and then override it with the classes set by@Mapperannotation if found. -
Your Stored procedure can return output parameter as well as One Result set in one call, to achieve this use
Tuplereturn type:
@Mapper({MyResultSetMapper.class, MyOutputParameterMapper.class})
@StoredProc("list_customers_with_date")
Tuple<Customer, Date> listCustomersWithDate();-
spwrap doesn't support INOUT parameters.
-
spwrap doesn't support returning multi-result sets from the stored procedure.
-
When the Stored procedure have input and output parameters, input parameters should come first and then the output parameters.
Because spwrap is based on JDBC API, theoretically it should support any Database Management System with a JDBC Driver, However it is tested on HSQL, MySQL, SQL Server and Oracle with jdk 1.6, 1.7 and 1.8 (1.7 and 1.8 are remove to reduce build time). (Plan to test againest: Postgresql, Sybase, DB2)
See wiki page for more info and test cases/spwrap-examples for more usage scenarios.