Database package
Introduction
This package implements a simple framework to work with a database over JDBC. The idea of this simple framework is to write fast robust code.
Design
The DatabaseManager
This class supports an additional abstraction. The DatabaseManager
holds
an instance of the DataSource
. The idea of the the DatabaseManager
is to work with SQLProcessor
's.
A class which implements the SQLProcessor
interface defines a specific SQL statement which can be get with the method getStatement
. Each
SQLProcess
also implements the processing of the JDBC ResultSet
. After the
execution of a SQLProcessor
an Object
array is returned. The SQL parameters
can be set outside of the SQLProcessor
class with the method setStatmentValues
.
The sort order of the Object
array correspond to the SQL parameter order.
The control over a transaction with a SQLProcessor
is part of the DatabaseManager
which works together with a TransactionMonitor
(more details see in the
transaction chapter).
The class AbstractSQLProcessor
implements the main method of the SQLProcessor
interface. Each subclass of the class AbstractSelectSQLProcessor
has also to define the SQL
statment (by calling the method setSQLStatement
) and has to implement the method
process
which implements the processing of the data. The ResultSet
will
closed after process
method!
The sequence diagram below shows the connection between the database classes:
There is a simple a select example:
(IMPORTANT: SQLProcessor can be generated by the ProcessorGenerator class from a given SQL code)
public class TestSelectProcessor extends AbstractSelectSQLProcessor { /** * Constructor */ public TestSelectProcessor() { setSQLStatement( "select address from usertable where username like '?'" ); } /** * Returns the data * @return the read data */ protected Object[] process( ResultSet rs ) throws SQLException { List data = new ArrayList(); String message; while( rs.next() ) { message = rs.getString( 1 ); data.add( message ); } return data.toArray( new String[ data.size() ] ); } }
There is a simple insert example:
public class TestInsertProcessor extends AbstractUpdateSQLProcessor { /** * Constructor */ public TestInsertProcessor() { setSQLStatement( "insert into address (username) values (?)" ); } }
There next examples show the initialisation of the DatabaseManager
and the
the use of it:
Initialisation of the
DatabaseManager
with theDatabasePoolManager
:... FileManager fileManager = new BootManager( new PropertiesManager() ); config = new DatabaseConfig( (Properties)fileManager.getFile("databasetest.properties") ); DatabaseManager dbManager = new DatabaseManager( new DatabasePoolManager( config ) ); ... Object[] param = new Object[1]; param[0] = new String( "myName" ); dbManager.executeQuery( new TestInsertProcessor(), null ); ...
Initialisation of the
DatabaseManager
with aDataSource
:... String dataSourceName = "..."; Context ctx = new InitialContext(); DataSource dataSource = (DataSource)ctx.lookup( dataSourceName ); DatabaseManager dbManager = new DatabaseManager( dataSource ); ... Object[] param = new Object[1]; param[0] = new String( "myName" ); dbManager.executeQuery( new TestInsertProcessor(), null ); ...
Initialisation of the
DatabaseManager
with aDataSource
. The lookup works with theServiceLocator
:... String dataSourceName = "..."; ServiceLocator localtor = new ServiceLocator(); DataSource dataSource = localtor.getDataSource( dataSourceName ); DatabaseManager dbManager = new DatabaseManager( dataSource ); ... Object[] param = new Object[1]; param[0] = new String( "myName" ); dbManager.executeQuery( new TestInsertProcessor(), null ); ...
The BatchProcessor
The class BatchProcessor
implements a processor which contains multiple processors which
can executed in one transaction context (more details see in the transaction chapter).
The return value contains a list with the result of each processor (a list with
Object arrays!). If one processor fails then the connection will rollback.
The method addSQLProcessor
adds a new SQLProcessor
with the execution
values (null if the statement has no values). The execution order of the processors is the same they are added
with the method addSQLProcessor
.
There is an example:
... String createTestTable = "create table jptoolsTest( name varchar(10), theDate date )"; String insertNameToTestTable = "insert into jptoolsTest( NAME ) values( ? )"; BatchSQLProcessor batch = new BatchSQLProcessor( "Batch Execution", null ); batch.addSQLProcessor( new TestSQLProcessor( createTestTable ), null ); batch.addSQLProcessor( new TestInsertSQLProcessor( insertNameToTestTable ), new Object[] { "jptools1" } ); batch.addSQLProcessor( new TestInsertSQLProcessor( insertNameToTestTable ), new Object[] { "jptools2" } ); batch.addSQLProcessor( new TestInsertSQLProcessor( insertNameToTestTable ), new Object[] { "jptools3" } ); List result = manager.executeBatch( batch ); ...
Transactions
The DatabaseManager
use a TransactionMonitor
to control a transaction which starts
and close a transaction. Each processor defines the result values of the execution. If the defined values
do not match with the result of the execution of the processor a defined error message will logged and a rollback
will done. Only if the expected result values match the data processing will commited.
The method setExpectedResult
of a processor defines the expected result values and the error message
if the values do not match. The default value is set to null
which informs the
DatabaseManager
to not control the result values of the processor.
The framework currently implements the following transaction monitors:
jptools.database.SimpleTransactionMonitor
jptools.j2ee.database.BMTransactionMonitor
jptools.j2ee.database.CMTransactionMonitor
The DatabaseManager
class use as default the SimpleTransactionMonitor
except an other the
transaction monitor is set in the constructor. An other possibility to use a different transaction monitor
is to hand over a transaction monitor by each executeQuery
or executeBatch
method call.
There is an example:
... String createTestTable = "create table jptoolsTest( name varchar(10), theDate date )"; String insertNameToTestTable = "insert into jptoolsTest( NAME ) values( ? )"; BatchSQLProcessor batch = new BatchSQLProcessor( "Batch Execution", null ); batch.addSQLProcessor( new TestSQLProcessor( createTestTable ), null ); batch.addSQLProcessor( new TestInsertSQLProcessor( insertNameToTestTable ), new Object[] { "jptools1" } ); batch.addSQLProcessor( new TestInsertSQLProcessor( insertNameToTestTable ), new Object[] { "jptools2" } ); batch.addSQLProcessor( new TestInsertSQLProcessor( insertNameToTestTable ), new Object[] { "jptools3" } ); UserTransaction ut = context.getUserTransaction(); // context = SessionContext List result = manager.executeBatch( new BMTransactionMonitor( ut ), batch ); ...
The DataSource
DatabasePoolManager
This class implements a simple JDBC connection pooling. It implements the DataSource
interface. Each call of the method
getConnection
returns a valid JDBC Connection
. The class
Connection
extends the SQL Connection
. Itself holds a
real Connection
to the database. After calling close
on the
connection the connection will not real closed. The Connection
will pushed
back to the ConnectionStack
which is under control of the
DatabasePoolManager
.
Configuration
The class DatabaseConfig
defines the database configuration like the database
url to connect, the user, the password. In the table below the key and default values are described.
There are some example configuration:
- Oracle (over SQL*Net) (
classes12.zip
or 9.2 and greaterojdbc14.jar
)database.driver = oracle.jdbc.driver.OracleDriver database.url = jdbc:oracle:oci8:/@SID
- Oracle (Type 4 driver) (
classes12.zip
or 9.2 and greaterojdbc14.jar
)database.driver = oracle.jdbc.driver.OracleDriver database.url = jdbc:oracle:thin:@server:1521:SID database.username = myUser database.password = myPassword
- MySql
database.driver = com.mysql.jdbc.Driver database.url = jdbc:mysql://server/databaseName database.username = myUser database.password = myPassword
- DB2 (
db2jcc.jar
anddb2jcc_license_cu.jar
)database.driver = com.ibm.db2.jcc.DB2Driver database.url = jdbc:db2://server:50000/databaseName database.username = myUser database.password = myPassword
- Microsoft SQL Server (
msbase.jar
,mssqlserver.jar
andmsutil.jar
)database.driver = com.microsoft.jdbc.sqlserver.SQLServerDriver database.url = jdbc:microsoft:sqlserver://server:1433;DatabaseName=databaseName;SelectMethod=Cursor database.username = myUser database.password = myPassword
- Microsoft Access
database.driver = sun.jdbc.odbc.JdbcOdbcDriver database.url = jdbc:odbc:Driver={Microsoft Access Driver (*.mdb)};DBQ=directory\\filename.mdb;}
Key |
Default value |
Description |
||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
The jdbc driver of the database. |
|||||||||||||||
|
The jdbc url. |
|||||||||||||||
|
The username of the database to connect to. |
|||||||||||||||
|
The password of the database user. |
|||||||||||||||
|
|
This timeout defines the interval how long the pool should wait of a retry if the creation of a connection was failed. |
||||||||||||||
|
|
The min. connections to the database. After initializing the
|
||||||||||||||
|
|
The max. connections to the database. If this number of connection is
reached and a |
||||||||||||||
|
|
This defines the timeout of a free |
||||||||||||||
|
|
Defines the interval to cleanup the connections in the pool. |
||||||||||||||
|
|
Defines the behavior to shrink the connections in the pool. The following
keys are valid:
|
||||||||||||||
|
|
Switch to log database statistics when something in the connection pool changes. |
||||||||||||||
|
|
Switch to log the database configuration by initializing the DatabasePoolManager. |
||||||||||||||
|
|
Sets the verbose mode. |