public class GenericDAO<B> extends Object
B.
Many implementations are possible. Included with this package is an
implementation that uses the MySQL database.
The JavaBean must either have a public, no-argument constructor
JavaBeans are declared in the usual way with getter and setter methods for
the properties. The GenericDAO uses the Java reflection classes
to inspect the bean. The GenericDAO will only store and retrieve
properties that have matching a getter/setter pair. Java capitalization rules
must be followed. The getter must have a signature of
public <type> get<Name>()
and the setter must have a signature of
public void set<Name>(<type> newValue)
The properties that comprise the primary key (for the table that backs the
beans) must be specified with the @PrimaryKey annotation.
Here is an example of a simple bean representing a user and its password:
@PrimaryKey("userName")
public class User {
private String userName;
private String password = null;
public String getUserName() {
return userName;
}
public String getPassword() {
return password;
}
public void setUserName(String s) {
userName = s;
}
public void setPassword(String s) {
password = s;
}
}
JavaBean properties can be any of the following Java types:
boolean, byte[], double,
float, int, long,
java.lang.String, java.sql.Date,
java.sql.Time, and java.util.Date.
Arrays of the above types (except for arrays of byte[]) are also
supported. Multi-dimensional arrays are not allowed. Also, arrays cannot be
used as primary keys. In some implementations (such a relational database
implementations) auxiliary tables are used for backing arrays.
Each table that backs a bean will be indexed by a primary key. The primary key must correspond to one or more of the JavaBean's properties. Primary key properties can be of any of the above types, except for arrays.
The GenericDAO will create the table in the database. If the
table already exists (presumably because the GenericDAO
previously created it), the GenericDAO will compare the table's
fields with the bean's properties. If the do not match, an exception is
thrown. (See the constructors.) The simplest fix for a table that does not
match the bean is to drop the existing table. The GenericDAO
will create a new table next time it is instantiated. (Mismatch usually
occurs either because there is some old table with the same name that happens
to exist or because you've changed the bean since the GenericDAO
last created the table. If the latter is the case, you can preserve the old
data by using the old version of the bean to read in the old values and the
new version of the bean to write them out into a new table.)
GenericDAO methods can be invoked from within an enclosing
Transaction which will enforce the ACID properties. Specific
ACID guarantees provided are particular to the GenericDAO
implementation, but typically are just what is implemented by the underlying
database. To have the ACID properties of a transaction work across multiple
DAOs, you need to be using the same connection pool in each DAO.
All GenericDAO calls may be made outside a transaction. In all
cases this is equivalent to making the same call from within a transaction
and then immediately committing it. However, in many implementations of
GenericDAO this done more efficiently. For example, a call
outside a transaction to dao.read(userName) is equivalent to:
Transaction.begin(); User u = dao.read(userName); Transaction.commit(); return u;
All GenericDAO methods (except the constructor methods) throw
RollbackException in case of failure. No other exceptions are
thrown from GenericDAO methods (other than constructor methods).
Any internally thrown exceptions are caught and a
RollbackException is thrown with the internal exception as the
RollbackException's cause. Any enclosing transaction is rolled back
in the process of throwing RollbackException.
All transactions should be committed or rolled back before awaiting user
input. If transactions are left running, locks may be held in the underlying
database causing new transactions to timeout. To guard against accidentally
not committing or rolling back a transaction (perhaps because of a
programming bug or an unexpected exception in non-GenericDAO code)
you should always put the transaction in a try /
catch statement with a finally clause that commits
or rolls back the transaction. For example:
try {
Transaction.begin();
...
Transaction.commit();
} catch (RollbackException e) {
...
} finally {
if (Transaction.isActive()) Transaction.rollback();
}
When debugging, it may be helpful to see the SQL that is being generated.
This feature is enabled via the ConnectionPool so that it will apply
to all DAOs and transactions that may be working together. For example:
ConnectionPool cp = new ConnectionPool(...);
cp.setDebugOutput(System.out);
Transaction,
ConnectionPool| Constructor and Description |
|---|
GenericDAO(Class<B> beanClass,
String tableName,
ConnectionPool connectionPool)
Instantiates a new
GenericDAO object. |
| Modifier and Type | Method and Description |
|---|---|
String |
computeDigest(B bean)
Computes a message digest (a one-way hash) of all the properties for the
given bean.
|
void |
create(B bean)
Creates a new row in the table using the values provided the contents of
the
bean. |
void |
delete(Object... primaryKeyValues)
Deletes from the table the row with the given primary key.
|
int |
getCount()
Returns the number of rows in the table.
|
B[] |
match(MatchArg... constraints)
Searches the table for rows matching the given constraints.
|
B |
read(Object... primaryKeyValues)
Returns the row in the table with the given primary key.
|
void |
update(B bean)
Updates the row in the table with the primary key specified by the values
in the
bean passed in as a parameter. |
public GenericDAO(Class<B> beanClass, String tableName, ConnectionPool connectionPool) throws DAOException
GenericDAO object.
The constructor will (1) analyze your bean (to make sure it has all the
parts it needs to read and write it), (2) create the table in MySQL (if
it's not there already), (3) compare the table to the bean (if it already
there).beanClass - the class description of the bean.tableName - the name of the table in the database used to store instance
of the bean.connectionPool - the connection pool to use to manage connections to the
database.DAOException - if there are any problems, including problems accessing the
database, problems with the bean class, etc.public String computeDigest(B bean) throws RollbackException
Digest strings returned from this method are not meant for long-term storage. Future releases of the BeanFactory may compute the digest and/or encode the digest into a string using different algorithms. The current implementation uses the SHA1 algorithm to compute the digest and returns it as a hex string.
The primary use of this method is to easily compute a digest for a bean so as to detect that some other thread/user has changed the bean between this thread/user's transactions.
bean - the bean from which to extract values for the digest.RollbackException - if the digest cannot be computed for any one of a number of
reasons, including errors accessing the bean, etc. Any
enclosing transaction is rolled back in the process of
throwing this exception.public void create(B bean) throws RollbackException
bean.
If the primary key for B is either of type
int or long (and not a composite key),
the primary key field will be auto-increment. Side-effect Warning:
In the auto-increment case, the primary key value generated by the database
is stored in the bean. (The original value is not read, just
overwritten.)
If a transaction is active for the current thread when this method is
called, the row will be created as part of that existing transaction. (If
no transaction is active, this method may create an internal transaction
to do the work but will commit that internal transaction before
returning.)bean - an instance of type B that contains the values to
store in the table.RollbackException - if the work cannot be completed for any one of a number of
reasons, including SQLExceptions, deadlocks, errors accessing
the bean, etc. Any enclosing transaction is rolled back in
the process of throwing this exception.DuplicateKeyException - if the bean specifies the creation of a new row with
a primary key value that is already in use. This is a
(subclass of) RollbackException, so any enclosing
transaction is rolled back in the process of throwing this
exception.public void delete(Object... primaryKeyValues) throws RollbackException
primaryKeyValues - the values of the properties that comprise the primary key for
bean being deleted.RollbackException - if there are errors in the types of the arguments, or if
there is no bean in the table with this primary key, or if
there is an error accessing the database, including
IOException or deadlock. (To avoid getting a
RollbackException deleting a bean that doesn't exist in the
table, first check to see if it's there using the
read() method, inside a transaction.)public int getCount()
throws RollbackException
RollbackException - if there is an error accessing the database, including
SQLException or deadlock.public B[] match(MatchArg... constraints) throws RollbackException
MatchArgs which limit properties to
values or ranges, such as equals, less-than or greater-than a given
value. Operators on strings also include starts-with, ends-with, and
contains. A bean is instantiated and returned to hold the values for each
row that matches the constraints.
If no constraints are specified, all the rows in the table are returned.
If there is an enclosing transaction active on this thread when this
method is called, the rows in the table that match be locked by the
transaction preventing other transactions from reading or writing these
rows until the enclosing transaction is committed or rolled back.constraints - zero or more constraints, all of which must be
true for each bean returned by this call.null.)RollbackException - if there are errors in the types of the arguments, or if
there is an error accessing the database, including
SQLException or deadlock.public B read(Object... primaryKeyValues) throws RollbackException
primaryKeyValues - the values of the properties that comprise the primary key for
bean being looked up.B with the given
primary key and values populated from the table. If there is no
such row, then null is returned.RollbackException - if there are errors in the types of the arguments, or if
there is an error accessing the database, including
SQLException or deadlock.public void update(B bean) throws RollbackException
bean passed in as a parameter. The fields in the row
(other than the primary key fields) are set to the values specified in
the bean.
If a transaction is active for the current thread when this method is
called, the row will be updated as part of that existing transaction. (If
no transaction is active, this method may create an internal transaction
to do the work but will commit that internal transaction before
returning.)bean - an instance of type B that contains the values to
store in the table.RollbackException - if there is an error accessing the database, including
SQLException or deadlock.Copyright © 2012-2016 Jeffrey L. Eppinger. All rights reserved. Permission granted for educational use only.