|
|||||||||||
PREV CLASS NEXT CLASS | FRAMES NO FRAMES | ||||||||||
SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |
java.lang.Object com.finalist.tools.database.StatementExecutor
java.sql.SQLConnection
as
well as a com.finalist.util.database.RowMapper
object. The RowMapper
object
does the binding of objects into PreparedStatements as well as the unbinding of ResultSets back
into Java objects. Since this is rather database specific stuff, every database requires it's
own extension of the abstract RowMapper
.Connection
conn to be there. An
OracleRowMapper
is used:
StatementExecutor s = new StatementExecutor(conn, new OracleRowMapper()); //use the Oracle RowMapper
s.prepareStatement("SELECT * FROM EMP WHERE MGR=:MANAGERNO AND SAL> :SALARY");
s.setBindVar("MANAGERNO", new Integer(1343));
s.setBindVar("SALARY", new Short(2000));
The first thing that should be noted is the notation of the bind variable in the SQL statement. Rather than
using the "?" as in traditional JDBC programming, StatementExecutor
requires the bindvariables
to be explicitly named using a colon as prefix. setBindVar(String bindName, Object bindVar)
binds an Integer object using
the name MANAGERNO into the prepared statement. The code that does the actual binding into the JDBC
prepared statement can be found in the RowMapper object. setBindVars(HashMap bindVars)
method:
HashMap binds = new HashMap();
binds.put("MANAGERNO",new Integer(1343));
binds.put("SALARY", new Short((short)2000));
s.prepareStatement("SELECT * SALARY FROM EMP WHERE MGR=:MANAGERNO AND SAL> :SALARY");
s.setBindVars(binds);
Finally, the bindvariables can be set in the form of a Java Bean. Assume a bean Employee
to be there with the properties name, telephoneNumber and department and the
associated getter
and setter
methods:
Employee emp = new Employee();
emp.setName("Peter");
emp.setTelephoneNumber(31104047395)
emp.setDepartment("Development");
s.prepareStatement("INSERT INTO EMP (NAME,TELNO,DEPT) VALUES(:NAME, :TELEPHONENUMBER, :DEPARTMENT)");
s.setBindVar(emp);
The method setBindBean(Object bean)
derives the properties from the bean (using reflection) and
binds them at the appropriate places into the prepared statement. The mapping between the property names and
the bindvariables is case-insensitive. Furthermore, if the used RowMapper supports this, it does not matter
whether the properties are primitives or Objects. Employee
object emp as well as the HashMap
binds:
s.prepareStatement("INSERT INTO EMP (NAME,TELNO,DEPT,SAL,MGR,STARTDATE) "
+ "VALUES(:NAME, :TELEPHONENUMBE, :DEPARTMENT)");
s.setBindVars(emp);
s.setBindVars(binds);
s.setBindVar("STARTDATE", new java.util.Date());
setBindVar(String name, Object object)
and setBindVars(HashMap bind)
overwrite
each other, so the most recently set bind variable takes precedence.
executeDML()
that returns an int value identifying
the amount of rows that were affected. A sequel of the previous code example could, for example, be:
int nrOfRowsAffected = s.executeDML();
Preconditions for this method to work are a valid SQL statement and the appropriate bind variables being set.
s.prepareStatement("CREATE TABLE TEST (KOLOM1 NUMBER(10))");
s.executeDML();
s.prepareStatement("SELECT * FROM EMP");
ArrayList results = s.executeIntoHashMap();
After this piece of code is executed, an ArrayList is created that contains a HashMap for every row that is returned by
the query. The HashMap is filled with keys of type String that are equivalent to the columnames of the queried table or
to the column labels of the query, if specified. The values of the HashMap are the values returned by the query.
The conversion of database data types to Java Objects is handled by the RowMapper. The reader is referred to
RowMapper for details on the conversion.
s.prepareStatement("SELECT NAME Name, TELNO TelephoneNumber, DEPTNO Department FROM EMP");
ArrayList results = s.executeIntoBean(Employee.class);
As a result, there will be an ArrayList containing a bean for every queried row with the properties set
to the queried values. The conversion between the database datatypes returned by the query and the Java object and/or
primitive attributes of the bean is done by the RowMapper.
ExecutionException
. This exception
extends from RuntimeException so it does not have to be explicitly caught. It is thrown upon three kind of
error situations: executeDML()
method, or when there
are not enough bindvariables set. getMessage()
method of ExecutionException returns an elaborate error message containing a detailed
report of the internal settings of the StatementExecutor. Too that, it tries to reconstruct the query string that
is executed against the database for debugging purposes.
enablePreparedStatementCaching()
. Running in this mode, StatementExecutor will cache all the prepared
statements, which dramatically speeds up re-execution. In this mode, the developer has to explicitly call the
close()
method when finished, in order to close the prepared statements in the cache.
StatementExecutor s = new StatementExecutor(conn, new OracleRowMapper());
//do a sequence query first
s.preparesStatement("SELECT SEQUENCE.NEXTVAL ID FROM DUAL");
Employee newEmp = (Employee)(s.executeQueryIntoBean(Employee.class).get(0));
//enrich the employee with some more details
newEmp.setName("Peter");
newEmp.setTelephoneNumber(31104047395)
newEmp.setDepartment("Development");
System.out.println("New Employee ID :" + newEmp.getId());
//and create a record in the database
s.setBindBean(newEmp);
s.prepareStatement("INSERT INTO EMP (ID,NAME,TELNO,DEPT) VALUES(:ID,:NAME,:TELEPHONENUMBER,:DEPARTMENT)");
null
to e.g. Oracle's NULL
is done without pain if the RowMapper is correctly implemented.
They can be bound using setVindar(bindName,null);
, through a bind HashMap or having an null reference
in a Object property of the bind bean. A property of primitive type, however will be assigned
a value, most probably 0 or 0.0, upon instantiation of the bean, before being inserted. Consequently, querying
NULL database values into Object properties of a bean will result in the null reference being
assigned to this property.
//query those employees that have manager Ids stored in ArrayList mgrIds,
//update their salaries and so on.
ArrayList emps = new ArrayList();
StatementExecutor s = new StatementExecutor(conn, new OracleRowMapper());
s.enablePreparedStatementCaching();
//instead of using the IN clause...
s.prepareStatement("SELECT * FROM EMP WHERE MGR_ID = :MGR_ID");
for( Iterator i = mgrIds.iterator() ; i.hasNext(); ) {
s.setBindVar("MGR_ID",i.next()); //let StatementExecutor do the typemapping
emps.addCollection(s.executeQueryIntoBean(Employee.class));
}
//set fixed bindvars
s.setBindVar("SAL",null);
s.setBindVar("ENDDATE",java.util.Date());
//ignore the property values of the bean by using different bind names in the statement
s.prepareStatement("UPDATE EMP SET SAL = :SAL, END_EMPLOYMENT_DATE = :ENDDATE, NAME = :NAME WHERE ID = :ID");
for( Iterator j = emps.iterator(); j.hasNext(); ) {
Employee curEmp = (Employee)j.next();
curEmp.setName(curEmp.getName+"*");
s.setBindBean(curEmp);
s.executeDML();
}
s.disablePreparedStatementCaching(); //close the cache
generateBeanFromQuery()
method using a query that returns at least one row.
Another option might be the generation of SQL statemenst and a CREATE TABLE statement
taking Java Beans as an input. Generation of a BMP Entity Bean that relies on StatementExecutor for its database
communication also belongs to the possibilities.
Field Summary | |
protected java.lang.Object |
bindBean
|
protected java.util.Map |
bindVars
|
protected java.sql.Connection |
conn
|
protected Query |
query
|
Constructor Summary | |
StatementExecutor()
Empty Constructor. |
|
StatementExecutor(java.sql.Connection conn,
RowMapper rowMapper)
Constructor. |
Method Summary | |
void |
clearBindVars()
This method wipes out any bindvariables that have been set before. |
void |
close()
Closes cached prepared statements. |
void |
disablePreparedStatementCaching()
Turn Prepared Statement Caching off and implcitly close the Prepared Statement Cachne |
void |
enablePreparedStatementCaching()
Turns on Prepared Statement Caching. |
int |
executeDML()
Executes DML statements and returns the amount of rows that are affected. |
java.util.ArrayList |
executeQueryIntoBean(java.lang.Class templateBean)
Executes the previously set statement and returns the results as an ArrayList of Beans of which the type is specified by templateClass. |
PartialResult |
executeQueryIntoBean(java.lang.Class templateBean,
int startIndex,
int maxLength)
Scrollable result set enabled version of executeQueryIntoBean(Class) , useful
for dealing with large result sets.
|
java.util.ArrayList |
executeQueryIntoBean(java.lang.Object templateBean)
Executes the previously set statement and returns the results as an ArrayList of Beans of which the type is specified by one input bean. |
PartialResult |
executeQueryIntoBean(java.lang.Object templateBean,
int startIndex,
int maxLength)
Scrollable result set enabled version of executeQueryIntoBean(Object) , useful
for dealing with large result sets.
|
java.util.ArrayList |
executeQueryIntoHashMap()
Executes the previously set statement and returns the results as an ArrayList of HashMaps |
PartialResult |
executeQueryIntoHashMap(int startIndex,
int maxLength)
Scrollable result set enabled version of executeQueryIntoHashMap() , useful
for dealing with large result sets. |
java.lang.String |
generateBeanFromQuery(java.lang.String name,
java.lang.String packageName,
java.lang.String queryDefinition)
This method generates the code of a Value (DTO) Bean using the outputformat of a query. |
java.sql.Connection |
getConnection()
This method returns the Connection that has been given in the constructor |
void |
prepareStatement(java.lang.String queryDefinition)
Sets the statement definition. |
void |
setBindVar(java.lang.String name,
java.lang.Object bindVar)
Define one bindvariable. |
void |
setBindVars(java.util.HashMap binds)
Define the bindvariables a HashMap containing keys as bindvariable names and values as the actual bindVars |
void |
setBindVars(java.lang.Object bindBean)
Define the bindvariables as properties of a bean |
void |
setConnection(java.sql.Connection conn)
Setter for property conn. |
void |
setRowMapper(RowMapper rowMapper)
Setter for property rowMapper. |
Methods inherited from class java.lang.Object |
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait |
Field Detail |
protected java.sql.Connection conn
protected final java.util.Map bindVars
protected java.lang.Object bindBean
protected Query query
Constructor Detail |
public StatementExecutor()
public StatementExecutor(java.sql.Connection conn, RowMapper rowMapper)
conn
- Connection connection used to execute the statements.rowMapper
- RowMapper object that contains the binding and unbinding functionality. Differs
per database type.Method Detail |
public void enablePreparedStatementCaching()
close()
method when done StatementExecutor to close the Prepared Statements or
call disablePreparedStatementCaching()
.
public void disablePreparedStatementCaching()
public void close()
public void prepareStatement(java.lang.String queryDefinition)
queryDefinition
- The definition of the query. Use colons to identiy bind variables by name.public void setBindVar(java.lang.String name, java.lang.Object bindVar)
name
- the name of the bindvarbindVar
- the object that is boundpublic void setBindVars(java.util.HashMap binds)
binds
- public void setBindVars(java.lang.Object bindBean)
bindBean
- the bean of which the properties should be used.public int executeDML()
public java.util.ArrayList executeQueryIntoHashMap()
public PartialResult executeQueryIntoHashMap(int startIndex, int maxLength)
executeQueryIntoHashMap()
, useful
for dealing with large result sets.
startIndex
- the place within the results to start from, where 0 is the first record.
If startIndex is specified larger than the number of results in the result set, this method
will return an empty result. A negative startIndex will be treated as 0.maxLength
- the maximum number of results required. Negative values are treated as zero.
public java.util.ArrayList executeQueryIntoBean(java.lang.Object templateBean)
templateBean
- Bean that serves as a template to fit the results in.
public java.util.ArrayList executeQueryIntoBean(java.lang.Class templateBean)
templateBean
- Class that serves as a template to fit the results in.
public PartialResult executeQueryIntoBean(java.lang.Object templateBean, int startIndex, int maxLength)
executeQueryIntoBean(Object)
, useful
for dealing with large result sets.
Use this method to generate a partial result set by specifying a 'start index' and a 'maximum length'.
templateBean
- Bean that serves as a template to fit the results in.startIndex
- the place within the results to start from, where 0 is the first record.
If startIndex is specified larger than the number of results in the result set, this method
will return an empty result. A negative startIndex will be treated as 0.maxLength
- the maximum number of results required. Negative values are treated as zero.
public PartialResult executeQueryIntoBean(java.lang.Class templateBean, int startIndex, int maxLength)
executeQueryIntoBean(Class)
, useful
for dealing with large result sets.
Use this method to generate a partial result set by specifying a 'start index' and a 'maximum length'.
templateBean
- Class that serves as a template to fit the results in.startIndex
- the place within the results to start from, where 0 is the first record.
If startIndex is specified larger than the number of results in the result set, this method
will return an empty result. A negative startIndex will be treated as 0.maxLength
- the maximum number of results required. Negative values are treated as zero.
public void clearBindVars()
public java.lang.String generateBeanFromQuery(java.lang.String name, java.lang.String packageName, java.lang.String queryDefinition)
name
- the name of the beanpackageName
- the package name it should be inqueryDefinition
- the definition of the query that defines the object
public java.sql.Connection getConnection()
public void setRowMapper(RowMapper rowMapper)
rowMapper
- New value of property rowMapper.public void setConnection(java.sql.Connection conn)
conn
- New value of property conn.
|
|||||||||||
PREV CLASS NEXT CLASS | FRAMES NO FRAMES | ||||||||||
SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |