Moved the id field into DBBean instead of the sub class
This commit is contained in:
parent
0cc2f253e3
commit
b8bf1946d5
2 changed files with 207 additions and 92 deletions
|
|
@ -14,8 +14,10 @@ import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.NoSuchElementException;
|
import java.util.NoSuchElementException;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import zutil.db.DBConnection;
|
import zutil.db.DBConnection;
|
||||||
|
import zutil.log.LogUtil;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <XMP>
|
* <XMP>
|
||||||
|
|
@ -38,6 +40,10 @@ import zutil.db.DBConnection;
|
||||||
* @author Ziver
|
* @author Ziver
|
||||||
*/
|
*/
|
||||||
public abstract class DBBean {
|
public abstract class DBBean {
|
||||||
|
public static final Logger logger = LogUtil.getLogger();
|
||||||
|
|
||||||
|
/** The id of the bean **/
|
||||||
|
private Long id;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the name of the table in the database
|
* Sets the name of the table in the database
|
||||||
|
|
@ -45,9 +51,9 @@ public abstract class DBBean {
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
@Target(ElementType.TYPE)
|
@Target(ElementType.TYPE)
|
||||||
public @interface DBTable {
|
public @interface DBTable {
|
||||||
String value();
|
String value();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the name of the table that links different DBBeans together
|
* Sets the name of the table that links different DBBeans together
|
||||||
*/
|
*/
|
||||||
|
|
@ -55,17 +61,20 @@ public abstract class DBBean {
|
||||||
@Target(ElementType.FIELD)
|
@Target(ElementType.FIELD)
|
||||||
public @interface DBLinkTable {
|
public @interface DBLinkTable {
|
||||||
/** The name of the Link table */
|
/** The name of the Link table */
|
||||||
String name();
|
String name();
|
||||||
/** The name of the column that contains this objects id */
|
/** The class of the linked bean */
|
||||||
String column() default "";
|
Class<? extends DBBean> beanClass();
|
||||||
|
/** The name of the column that contains this objects id */
|
||||||
|
String column() default "";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the field as the id column in the table
|
* Sets the field as the id column in the table
|
||||||
*/
|
*/
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
/*@Retention(RetentionPolicy.RUNTIME)
|
||||||
@Target(ElementType.FIELD)
|
@Target(ElementType.FIELD)
|
||||||
public @interface DBTableID {}
|
public @interface DBTableID {}
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A Class that contains information about a bean
|
* A Class that contains information about a bean
|
||||||
|
|
@ -77,23 +86,23 @@ public abstract class DBBean {
|
||||||
protected Field id_field;
|
protected Field id_field;
|
||||||
/** All the fields in the bean */
|
/** All the fields in the bean */
|
||||||
protected ArrayList<Field> fields;
|
protected ArrayList<Field> fields;
|
||||||
|
|
||||||
protected DBBeanConfig(){
|
protected DBBeanConfig(){
|
||||||
fields = new ArrayList<Field>();
|
fields = new ArrayList<Field>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** This is a cache of all the initialized beans */
|
/** This is a cache of all the initialized beans */
|
||||||
private static HashMap<Class<? extends DBBean>,DBBeanConfig> beanConfigs = new HashMap<Class<? extends DBBean>,DBBeanConfig>();
|
private static HashMap<Class<? extends DBBean>,DBBeanConfig> beanConfigs = new HashMap<Class<? extends DBBean>,DBBeanConfig>();
|
||||||
/** This value is for preventing recursive loops */
|
/** This value is for preventing recursive loops */
|
||||||
private boolean processing;
|
private boolean processing;
|
||||||
|
|
||||||
protected DBBean(){
|
protected DBBean(){
|
||||||
if( !beanConfigs.containsKey( this.getClass() ) )
|
if( !beanConfigs.containsKey( this.getClass() ) )
|
||||||
initBeanConfig( this.getClass() );
|
initBeanConfig( this.getClass() );
|
||||||
processing = false;
|
processing = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the ID field of the bean or null if there is non
|
* @return the ID field of the bean or null if there is non
|
||||||
*/
|
*/
|
||||||
|
|
@ -102,7 +111,7 @@ public abstract class DBBean {
|
||||||
initBeanConfig( c );
|
initBeanConfig( c );
|
||||||
return beanConfigs.get( c ).id_field;
|
return beanConfigs.get( c ).id_field;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return all the fields except the ID field
|
* @return all the fields except the ID field
|
||||||
*/
|
*/
|
||||||
|
|
@ -111,7 +120,7 @@ public abstract class DBBean {
|
||||||
initBeanConfig( c );
|
initBeanConfig( c );
|
||||||
return beanConfigs.get( c ).fields;
|
return beanConfigs.get( c ).fields;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the configuration object for the specified class
|
* @return the configuration object for the specified class
|
||||||
*/
|
*/
|
||||||
|
|
@ -120,7 +129,7 @@ public abstract class DBBean {
|
||||||
initBeanConfig( c );
|
initBeanConfig( c );
|
||||||
return beanConfigs.get( c );
|
return beanConfigs.get( c );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Caches the fields
|
* Caches the fields
|
||||||
*/
|
*/
|
||||||
|
|
@ -129,113 +138,149 @@ public abstract class DBBean {
|
||||||
DBBeanConfig config = new DBBeanConfig();
|
DBBeanConfig config = new DBBeanConfig();
|
||||||
// Find the table name
|
// Find the table name
|
||||||
if( c.getAnnotation(DBTable.class) != null )
|
if( c.getAnnotation(DBTable.class) != null )
|
||||||
config.tableName = c.getAnnotation(DBTable.class).value().replace('\"', ' ');
|
config.tableName = c.getAnnotation(DBTable.class).value().replace('\"', ' ');
|
||||||
// Add the fields in the bean
|
// Add the fields in the bean
|
||||||
for( Field field : fields ){
|
for( Field field : fields ){
|
||||||
if( !Modifier.isTransient(field.getModifiers()) ){
|
int mod = field.getModifiers();
|
||||||
if(field.getAnnotation(DBBean.DBTableID.class) != null)
|
if( !Modifier.isTransient( mod ) &&
|
||||||
config.id_field = field;
|
!Modifier.isAbstract( mod ) &&
|
||||||
|
!Modifier.isFinal( mod ) &&
|
||||||
|
!Modifier.isStatic( mod ) &&
|
||||||
|
!Modifier.isInterface( mod ) &&
|
||||||
|
!Modifier.isNative( mod )){
|
||||||
|
//if(field.getAnnotation(DBBean.DBTableID.class) != null)
|
||||||
|
// config.id_field = field;
|
||||||
config.fields.add( field );
|
config.fields.add( field );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
try {
|
||||||
|
config.id_field = DBBean.class.getDeclaredField("id");
|
||||||
|
config.id_field.setAccessible(true);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
beanConfigs.put(c, config);
|
beanConfigs.put(c, config);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Saves the Object to the DB
|
* Saves the Object to the DB
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public void save(DBConnection sql) throws SQLException{
|
public void save(DBConnection db) throws SQLException{
|
||||||
if(processing)
|
if(processing)
|
||||||
return;
|
return;
|
||||||
processing = true;
|
processing = true;
|
||||||
Class<? extends DBBean> c = this.getClass();
|
Class<? extends DBBean> c = this.getClass();
|
||||||
DBBeanConfig config = beanConfigs.get(c);
|
DBBeanConfig config = beanConfigs.get(c);
|
||||||
try {
|
try {
|
||||||
|
Object id = getFieldValue( config.id_field );
|
||||||
// Generate the SQL
|
// Generate the SQL
|
||||||
StringBuilder query = new StringBuilder();
|
StringBuilder query = new StringBuilder();
|
||||||
query.append("REPLACE INTO ? ");
|
if( id == null )
|
||||||
|
query.append("INSERT INTO ");
|
||||||
|
else query.append("UPDATE ");
|
||||||
|
query.append( config.tableName );
|
||||||
|
|
||||||
|
StringBuilder params = new StringBuilder();
|
||||||
for( Field field : config.fields ){
|
for( Field field : config.fields ){
|
||||||
query.append(" ");
|
if( !List.class.isAssignableFrom(field.getType()) ){
|
||||||
query.append(field.getName());
|
params.append(" ");
|
||||||
query.append("=?, ");
|
params.append(field.getName());
|
||||||
|
params.append("=?,");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
query.delete( query.length()-2, query.length());
|
if( params.length() > 0 ){
|
||||||
PreparedStatement stmt = sql.getPreparedStatement( sql.toString() );
|
params.delete( params.length()-1, params.length());
|
||||||
// add the table name
|
query.append( " SET" );
|
||||||
stmt.setObject(1, config.tableName);
|
query.append( params );
|
||||||
|
if( id != null )
|
||||||
|
query.append( " id=?" );
|
||||||
|
}
|
||||||
|
logger.fine("Save query: "+query.toString());
|
||||||
|
PreparedStatement stmt = db.getPreparedStatement( query.toString() );
|
||||||
// Put in the variables in the SQL
|
// Put in the variables in the SQL
|
||||||
for(int i=0; i<config.fields.size() ;++i ){
|
for(int i=0; i<config.fields.size() ;++i ){
|
||||||
Field field = config.fields.get(i);
|
Field field = config.fields.get(i);
|
||||||
|
|
||||||
// Another DBBean class
|
// Another DBBean class
|
||||||
if( DBBean.class.isAssignableFrom( field.getType() )){
|
if( DBBean.class.isAssignableFrom( field.getType() )){
|
||||||
DBBean subobj = (DBBean)field.get(this);
|
DBBean subobj = (DBBean)getFieldValue(field);
|
||||||
subobj.save(sql);
|
if(subobj != null){
|
||||||
stmt.setObject(i+2, getBeanConfig(subobj.getClass()) );
|
subobj.save(db);
|
||||||
|
DBBeanConfig subconfig = getBeanConfig(subobj.getClass());
|
||||||
|
stmt.setObject(i+1, subobj.getFieldValue(subconfig.id_field) );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
stmt.setObject(i+1, null);
|
||||||
}
|
}
|
||||||
// A list of DBBeans
|
// A list of DBBeans
|
||||||
else if( List.class.isAssignableFrom( field.getType() ) &&
|
else if( List.class.isAssignableFrom( field.getType() ) &&
|
||||||
field.getAnnotation( DBLinkTable.class ) != null){
|
field.getAnnotation( DBLinkTable.class ) != null){
|
||||||
List<DBBean> list = (List<DBBean>)field.get(this);
|
List<DBBean> list = (List<DBBean>)getFieldValue(field);
|
||||||
DBLinkTable linkTable = field.getAnnotation( DBLinkTable.class );
|
if( list != null ){
|
||||||
String subtable = linkTable.name();
|
DBLinkTable linkTable = field.getAnnotation( DBLinkTable.class );
|
||||||
String idcol = (linkTable.column().isEmpty() ? config.tableName : linkTable.column() );
|
String subtable = linkTable.name();
|
||||||
|
String idcol = (linkTable.column().isEmpty() ? config.tableName : linkTable.column() );
|
||||||
DBBeanConfig subConfig = null;
|
|
||||||
for(DBBean subobj : list){
|
DBBeanConfig subConfig = null;
|
||||||
if(subConfig == null)
|
for(DBBean subobj : list){
|
||||||
subConfig = beanConfigs.get( subobj.getClass() );
|
if(subConfig == null)
|
||||||
// Save links in link table
|
subConfig = beanConfigs.get( subobj.getClass() );
|
||||||
PreparedStatement subStmt = sql.getPreparedStatement("REPLACE INTO ? ?=? ?=?");
|
// Save links in link table
|
||||||
subStmt.setString(1, subtable);
|
PreparedStatement subStmt = db.getPreparedStatement("REPLACE INTO "+subtable+" SET ?=? ?=?");
|
||||||
subStmt.setString(2, idcol);
|
subStmt.setString(1, idcol);
|
||||||
subStmt.setObject(3, config.id_field);
|
subStmt.setObject(2, config.id_field);
|
||||||
subStmt.setString(4, subConfig.tableName);
|
subStmt.setString(3, subConfig.tableName);
|
||||||
subStmt.setObject(5, subConfig.id_field.get(subobj));
|
subStmt.setObject(4, subobj.getFieldValue(subConfig.id_field) );
|
||||||
DBConnection.exec(subStmt);
|
DBConnection.exec(subStmt);
|
||||||
// Save the sub bean
|
// Save the sub bean
|
||||||
subobj.save(sql);
|
subobj.save(db);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Normal field
|
// Normal field
|
||||||
else
|
else{
|
||||||
stmt.setObject(i+2, field.get(this));
|
Object value = getFieldValue(field);
|
||||||
|
stmt.setObject(i+1, value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
if( id != null )
|
||||||
|
stmt.setObject(config.fields.size(), id);
|
||||||
|
|
||||||
// Execute the SQL
|
// Execute the SQL
|
||||||
DBConnection.exec(stmt);
|
DBConnection.exec(stmt);
|
||||||
|
setFieldValue( config.id_field, db.getLastInsertID() );
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
throw e;
|
throw e;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new SQLException(e);
|
throw new SQLException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deletes the object from the DB, WARNING will not delete sub beans
|
* Deletes the object from the DB, WARNING will not delete sub beans
|
||||||
*/
|
*/
|
||||||
public void delete(DBConnection sql){
|
public void delete(DBConnection db){
|
||||||
Class<? extends DBBean> c = this.getClass();
|
Class<? extends DBBean> c = this.getClass();
|
||||||
DBBeanConfig config = beanConfigs.get(c);
|
DBBeanConfig config = beanConfigs.get(c);
|
||||||
if( config.id_field == null )
|
if( config.id_field == null )
|
||||||
throw new NoSuchElementException("DBTableID annotation missing in bean!");
|
throw new NoSuchElementException("DBTableID annotation missing in bean!");
|
||||||
try {
|
try {
|
||||||
PreparedStatement stmt = sql.getPreparedStatement(
|
String sql = "DELETE FROM "+config.tableName+" WHERE "+ config.id_field +"=?";
|
||||||
"DELETE FROM ? WHERE "+ config.id_field +"=?");
|
logger.fine("Load query: "+sql);
|
||||||
// Put in the variables in the SQL
|
PreparedStatement stmt = db.getPreparedStatement( sql );
|
||||||
stmt.setObject(1, config.tableName );
|
// Put in the variables in the SQL
|
||||||
stmt.setObject(2, config.id_field.get(this) );
|
logger.fine("Delete query: "+sql);
|
||||||
|
stmt.setObject(1, getFieldValue(config.id_field) );
|
||||||
|
|
||||||
// Execute the SQL
|
// Execute the SQL
|
||||||
DBConnection.exec(stmt);
|
DBConnection.exec(stmt);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads all the rows in the table into a LinkedList
|
* Loads all the rows in the table into a LinkedList
|
||||||
*
|
*
|
||||||
|
|
@ -249,13 +294,14 @@ public abstract class DBBean {
|
||||||
initBeanConfig( c );
|
initBeanConfig( c );
|
||||||
DBBeanConfig config = beanConfigs.get(c);
|
DBBeanConfig config = beanConfigs.get(c);
|
||||||
// Generate query
|
// Generate query
|
||||||
PreparedStatement stmt = db.getPreparedStatement( "SELECT * FROM ?" );
|
String sql = "SELECT * FROM "+config.tableName;
|
||||||
stmt.setString(1, config.tableName);
|
logger.fine("Load query: "+sql);
|
||||||
|
PreparedStatement stmt = db.getPreparedStatement( sql );
|
||||||
// Run query
|
// Run query
|
||||||
List<T> list = DBConnection.exec(stmt, DBBeanSQLResultHandler.createList(c, db) );
|
List<T> list = DBConnection.exec(stmt, DBBeanSQLResultHandler.createList(c, db) );
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads all the rows in the table into a LinkedList
|
* Loads all the rows in the table into a LinkedList
|
||||||
*
|
*
|
||||||
|
|
@ -270,15 +316,14 @@ public abstract class DBBean {
|
||||||
initBeanConfig( c );
|
initBeanConfig( c );
|
||||||
DBBeanConfig config = beanConfigs.get(c);
|
DBBeanConfig config = beanConfigs.get(c);
|
||||||
// Generate query
|
// Generate query
|
||||||
PreparedStatement stmt = db.getPreparedStatement( "SELECT * FROM ? WHERE ?=? LIMIT 1" );
|
PreparedStatement stmt = db.getPreparedStatement( "SELECT * FROM "+config.tableName+" WHERE ?=? LIMIT 1" );
|
||||||
stmt.setString(1, config.tableName);
|
stmt.setString(1, config.id_field.getName());
|
||||||
stmt.setString(2, config.id_field.getName());
|
stmt.setObject(2, id );
|
||||||
stmt.setObject(3, id );
|
|
||||||
// Run query
|
// Run query
|
||||||
T obj = DBConnection.exec(stmt, DBBeanSQLResultHandler.create(c, db) );
|
T obj = DBConnection.exec(stmt, DBBeanSQLResultHandler.create(c, db) );
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a specific table for the given Bean
|
* Creates a specific table for the given Bean
|
||||||
*/
|
*/
|
||||||
|
|
@ -289,8 +334,8 @@ public abstract class DBBean {
|
||||||
|
|
||||||
// Generate the SQL
|
// Generate the SQL
|
||||||
StringBuilder query = new StringBuilder();
|
StringBuilder query = new StringBuilder();
|
||||||
query.append("CREATE TABLE ? ( ");
|
query.append("CREATE TABLE "+config.tableName+" ( ");
|
||||||
|
|
||||||
for( Field field : config.fields ){
|
for( Field field : config.fields ){
|
||||||
query.append(" ");
|
query.append(" ");
|
||||||
query.append( field.getName() );
|
query.append( field.getName() );
|
||||||
|
|
@ -302,13 +347,11 @@ public abstract class DBBean {
|
||||||
query.delete( query.length()-2, query.length());
|
query.delete( query.length()-2, query.length());
|
||||||
query.append(")");
|
query.append(")");
|
||||||
PreparedStatement stmt = sql.getPreparedStatement( sql.toString() );
|
PreparedStatement stmt = sql.getPreparedStatement( sql.toString() );
|
||||||
// add the table name
|
|
||||||
stmt.setObject(1, config.tableName);
|
|
||||||
|
|
||||||
// Execute the SQL
|
// Execute the SQL
|
||||||
DBConnection.exec(stmt);
|
DBConnection.exec(stmt);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String classToDBName(Class<?> c){
|
private static String classToDBName(Class<?> c){
|
||||||
if( c == String.class) return "CLOB"; // TEXT
|
if( c == String.class) return "CLOB"; // TEXT
|
||||||
else if(c == Short.class) return "SMALLINT";
|
else if(c == Short.class) return "SMALLINT";
|
||||||
|
|
@ -329,7 +372,7 @@ public abstract class DBBean {
|
||||||
else if(c == byte.class) return "BINARY(1)";
|
else if(c == byte.class) return "BINARY(1)";
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is a workaround if the field is not visible to other classes
|
* This is a workaround if the field is not visible to other classes
|
||||||
*
|
*
|
||||||
|
|
@ -345,7 +388,7 @@ public abstract class DBBean {
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is a workaround if the field is not visible to other classes
|
* This is a workaround if the field is not visible to other classes
|
||||||
*
|
*
|
||||||
|
|
@ -360,4 +403,11 @@ public abstract class DBBean {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the object id or null if the bean has not bean saved yet
|
||||||
|
*/
|
||||||
|
public Long getId(){
|
||||||
|
return id;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,16 +5,32 @@ import java.sql.PreparedStatement;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.sql.Statement;
|
import java.sql.Statement;
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import zutil.db.DBConnection;
|
import zutil.db.DBConnection;
|
||||||
import zutil.db.SQLResultHandler;
|
import zutil.db.SQLResultHandler;
|
||||||
import zutil.db.bean.DBBean.DBBeanConfig;
|
import zutil.db.bean.DBBean.DBBeanConfig;
|
||||||
import zutil.db.bean.DBBean.DBLinkTable;
|
import zutil.db.bean.DBBean.DBLinkTable;
|
||||||
|
import zutil.log.LogUtil;
|
||||||
|
|
||||||
public class DBBeanSQLResultHandler<T> implements SQLResultHandler<T>{
|
public class DBBeanSQLResultHandler<T> implements SQLResultHandler<T>{
|
||||||
|
public static final Logger logger = LogUtil.getLogger();
|
||||||
|
/** This is the time to live for the cached items **/
|
||||||
|
public static final long CACHE_TTL = 1000*60*10; // in ms
|
||||||
|
/** A cache for detecting recursion **/
|
||||||
|
protected static HashMap<Class<?>, HashMap<Object,DBBeanCache>> cache =
|
||||||
|
new HashMap<Class<?>, HashMap<Object,DBBeanCache>>();
|
||||||
|
/**
|
||||||
|
* A cache container that contains a object and last read time
|
||||||
|
*/
|
||||||
|
protected static class DBBeanCache{
|
||||||
|
public long timestamp;
|
||||||
|
public DBBean bean;
|
||||||
|
}
|
||||||
|
|
||||||
private Class<? extends DBBean> bean_class;
|
private Class<? extends DBBean> bean_class;
|
||||||
private DBBeanConfig bean_config;
|
private DBBeanConfig bean_config;
|
||||||
private DBConnection db;
|
private DBConnection db;
|
||||||
|
|
@ -108,16 +124,24 @@ public class DBBeanSQLResultHandler<T> implements SQLResultHandler<T>{
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
private DBBean createBean(ResultSet result) throws SQLException{
|
private DBBean createBean(ResultSet result) throws SQLException{
|
||||||
try {
|
try {
|
||||||
DBBean obj = bean_class.newInstance();
|
Object id = result.getObject( bean_config.id_field.getName() );
|
||||||
|
DBBean obj = getCachedDBBean(bean_class, id);
|
||||||
|
if( obj != null )
|
||||||
|
return obj;
|
||||||
|
obj = bean_class.newInstance();
|
||||||
|
cacheDBBean(obj, id);
|
||||||
|
|
||||||
for( Field field : bean_config.fields ){
|
for( Field field : bean_config.fields ){
|
||||||
String name = field.getName();
|
String name = field.getName();
|
||||||
|
|
||||||
// Another DBBean class
|
// Another DBBean class
|
||||||
if( DBBean.class.isAssignableFrom( field.getType() )){
|
if( DBBean.class.isAssignableFrom( field.getType() )){
|
||||||
if(db != null){
|
if(db != null){
|
||||||
DBBean subobj = DBBean.load(db, (Class<? extends DBBean>)field.getType(), result.getObject(name));
|
Object subid = result.getObject(name);
|
||||||
|
DBBean subobj = getCachedDBBean(field.getType(), subid);
|
||||||
|
if( subobj == null )
|
||||||
|
subobj = DBBean.load(db, (Class<? extends DBBean>)field.getType(), subid);
|
||||||
obj.setFieldValue(field, subobj);
|
obj.setFieldValue(field, subobj);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -130,17 +154,16 @@ public class DBBeanSQLResultHandler<T> implements SQLResultHandler<T>{
|
||||||
String idcol = (linkTable.column().isEmpty() ? bean_config.tableName : linkTable.column() );
|
String idcol = (linkTable.column().isEmpty() ? bean_config.tableName : linkTable.column() );
|
||||||
|
|
||||||
// Load list from link table
|
// Load list from link table
|
||||||
PreparedStatement subStmt = db.getPreparedStatement("SELECT * FROM ? WHERE ?=?");
|
PreparedStatement subStmt = db.getPreparedStatement("SELECT * FROM "+subtable+" WHERE ?=?");
|
||||||
subStmt.setString(1, subtable);
|
subStmt.setString(1, idcol);
|
||||||
subStmt.setString(2, idcol);
|
subStmt.setObject(2, bean_config.id_field.get( obj ));
|
||||||
subStmt.setObject(3, bean_config.id_field.get( obj ));
|
|
||||||
List<? extends DBBean> list = DBConnection.exec(subStmt,
|
List<? extends DBBean> list = DBConnection.exec(subStmt,
|
||||||
DBBeanSQLResultHandler.createList((Class<? extends DBBean>)field.getType(), db));
|
DBBeanSQLResultHandler.createList(linkTable.beanClass(), db));
|
||||||
obj.setFieldValue(field, list);
|
obj.setFieldValue(field, list);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Normal field
|
// Normal field
|
||||||
else
|
else
|
||||||
obj.setFieldValue(field, result.getObject(name));
|
obj.setFieldValue(field, result.getObject(name));
|
||||||
}
|
}
|
||||||
return obj;
|
return obj;
|
||||||
|
|
@ -152,4 +175,46 @@ public class DBBeanSQLResultHandler<T> implements SQLResultHandler<T>{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the given object to the cache
|
||||||
|
*
|
||||||
|
* @param obj is the object to cache
|
||||||
|
* @param id is the id object of the bean
|
||||||
|
*/
|
||||||
|
protected static void cacheDBBean(DBBean obj, Object id) {
|
||||||
|
DBBeanCache item = new DBBeanCache();
|
||||||
|
item.timestamp = System.currentTimeMillis();
|
||||||
|
item.bean = obj;
|
||||||
|
if( cache.containsKey(obj.getClass()) )
|
||||||
|
cache.get(obj.getClass()).put(id, item);
|
||||||
|
else{
|
||||||
|
HashMap<Object, DBBeanCache> map = new HashMap<Object, DBBeanCache>();
|
||||||
|
map.put(id, item);
|
||||||
|
cache.put(obj.getClass(), map);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param c is the class of the bean
|
||||||
|
* @param id is the id object of the bean
|
||||||
|
* @return an cached DBBean object or null if the object is not cached or has expired
|
||||||
|
*/
|
||||||
|
protected static DBBean getCachedDBBean(Class<?> c, Object id){
|
||||||
|
if( cache.containsKey(c) ){
|
||||||
|
DBBeanCache item = cache.get(c).get(id);
|
||||||
|
// Check if the cache is valid
|
||||||
|
if( item != null && item.timestamp+CACHE_TTL > System.currentTimeMillis() ){
|
||||||
|
return item.bean;
|
||||||
|
}
|
||||||
|
// The cache is old, remove it and return null
|
||||||
|
else{
|
||||||
|
logger.finer("Cache to old: "+c.getName()+" ID: "+id);
|
||||||
|
cache.get(c).remove(id);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
logger.finer("Cache miss: "+c.getName()+" ID: "+id);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue