Extracted findAllKeys() query into a helper class, made it possible for Query

to request a read-write connection.
This commit is contained in:
Michael Bayne
2008-11-21 02:30:08 +00:00
parent 3cf711e083
commit 22c086f64e
8 changed files with 143 additions and 113 deletions
@@ -309,68 +309,10 @@ public abstract class DepotRepository
* the latest data. * the latest data.
*/ */
protected <T extends PersistentRecord> List<Key<T>> findAllKeys ( protected <T extends PersistentRecord> List<Key<T>> findAllKeys (
final Class<T> type, boolean forUpdate, Collection<? extends QueryClause> clauses) Class<T> type, boolean forUpdate, Collection<? extends QueryClause> clauses)
throws DatabaseException throws DatabaseException
{ {
final List<Key<T>> keys = Lists.newArrayList(); return _ctx.invoke(new FindAllKeysQuery<T>(_ctx, type, forUpdate, clauses));
final DepotMarshaller<T> marsh = _ctx.getMarshaller(type);
SelectClause<T> select = new SelectClause<T>(type, marsh.getPrimaryKeyFields(), clauses);
final SQLBuilder builder = _ctx.getSQLBuilder(DepotTypes.getDepotTypes(_ctx, select));
builder.newQuery(select);
if (forUpdate) {
_ctx.invoke(new Modifier(null) {
@Override
protected int invoke (Connection conn, DatabaseLiaison liaison) throws SQLException {
PreparedStatement stmt = builder.prepare(conn);
try {
ResultSet rs = stmt.executeQuery();
while (rs.next()) {
keys.add(marsh.makePrimaryKey(rs));
}
// TODO: cache this result?
if (PersistenceContext.CACHE_DEBUG) {
log.info("Loaded " + StringUtil.shortClassName(type) + " keys",
"count", keys.size());
}
return 0;
} finally {
JDBCUtil.close(stmt);
}
}
@Override public void updateStats (Stats stats) {
stats.noteQuery(0, 1, 0, 0); // one uncached query
}
});
} else {
_ctx.invoke(new Query.Trivial<Void>() {
@Override
public Void invoke (PersistenceContext ctx, Connection conn,
DatabaseLiaison liaison) throws SQLException {
PreparedStatement stmt = builder.prepare(conn);
try {
ResultSet rs = stmt.executeQuery();
while (rs.next()) {
keys.add(marsh.makePrimaryKey(rs));
}
// TODO: cache this result?
if (PersistenceContext.CACHE_DEBUG) {
log.info("Loaded " + StringUtil.shortClassName(type) + " keys",
"count", keys.size());
}
return null;
} finally {
JDBCUtil.close(stmt);
}
}
public void updateStats (Stats stats) {
stats.noteQuery(0, 1, 0, 0); // one uncached query
}
});
}
return keys;
} }
/** /**
@@ -0,0 +1,100 @@
//
// $Id$
//
// Depot library - a Java relational persistence library
// Copyright (C) 2006-2008 Michael Bayne and Pär Winzell
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.samskivert.depot;
import java.util.Collection;
import java.util.List;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import com.google.common.collect.Lists;
import com.samskivert.jdbc.DatabaseLiaison;
import com.samskivert.jdbc.JDBCUtil;
import com.samskivert.depot.clause.QueryClause;
import com.samskivert.depot.clause.SelectClause;
import static com.samskivert.depot.Log.log;
/**
* Loads all primary keys for the records matching the supplied clause.
*/
public class FindAllKeysQuery<T extends PersistentRecord> extends Query<List<Key<T>>>
{
public FindAllKeysQuery (PersistenceContext ctx, Class<T> type, boolean forUpdate,
Collection<? extends QueryClause> clauses)
throws DatabaseException
{
_forUpdate = forUpdate;
_marsh = ctx.getMarshaller(type);
_select = new SelectClause<T>(type, _marsh.getPrimaryKeyFields(), clauses);
_builder = ctx.getSQLBuilder(DepotTypes.getDepotTypes(ctx, _select));
_builder.newQuery(_select);
}
@Override // from Query
public boolean isReadOnly ()
{
return !_forUpdate;
}
@Override // from Query
public List<Key<T>> getCachedResult (PersistenceContext ctx)
{
return null; // TODO
}
@Override // from Query
public List<Key<T>> invoke (PersistenceContext ctx, Connection conn, DatabaseLiaison liaison)
throws SQLException
{
List<Key<T>> keys = Lists.newArrayList();
PreparedStatement stmt = _builder.prepare(conn);
try {
ResultSet rs = stmt.executeQuery();
while (rs.next()) {
keys.add(_marsh.makePrimaryKey(rs));
}
// TODO: cache this result?
if (PersistenceContext.CACHE_DEBUG) {
log.info("Loaded " + _marsh.getTableName(), "count", keys.size());
}
return keys;
} finally {
JDBCUtil.close(stmt);
}
}
@Override // from Query
public void updateStats (Stats stats)
{
stats.noteQuery(0, 1, 0, 0); // one uncached query
}
protected boolean _forUpdate;
protected SQLBuilder _builder;
protected DepotMarshaller<T> _marsh;
protected SelectClause<T> _select;
}
+14 -37
View File
@@ -49,8 +49,7 @@ import static com.samskivert.depot.Log.log;
* This class implements the functionality required by {@link DepotRepository#findAll}: fetch * This class implements the functionality required by {@link DepotRepository#findAll}: fetch
* a collection of persistent objects using one of two included strategies. * a collection of persistent objects using one of two included strategies.
*/ */
public abstract class FindAllQuery<T extends PersistentRecord> public abstract class FindAllQuery<T extends PersistentRecord> extends Query<List<T>>
implements Query<List<T>>
{ {
/** /**
* The two-pass collection query implementation. See {@link DepotRepository#findAll} for * The two-pass collection query implementation. See {@link DepotRepository#findAll} for
@@ -76,7 +75,7 @@ public abstract class FindAllQuery<T extends PersistentRecord>
} }
_select = new SelectClause<T>(_type, _marsh.getPrimaryKeyFields(), clauses); _select = new SelectClause<T>(_type, _marsh.getPrimaryKeyFields(), clauses);
_builder = _ctx.getSQLBuilder(DepotTypes.getDepotTypes(ctx, _select)); _builder = ctx.getSQLBuilder(DepotTypes.getDepotTypes(ctx, _select));
_builder.newQuery(_select); _builder.newQuery(_select);
} }
@@ -95,7 +94,7 @@ public abstract class FindAllQuery<T extends PersistentRecord>
Key<T> key = _marsh.makePrimaryKey(rs); Key<T> key = _marsh.makePrimaryKey(rs);
allKeys.add(key); allKeys.add(key);
T value = _ctx.<T>cacheLookup(key); T value = ctx.<T>cacheLookup(key);
if (value != null) { if (value != null) {
@SuppressWarnings("unchecked") T newValue = (T) value.clone(); @SuppressWarnings("unchecked") T newValue = (T) value.clone();
entities.put(key, newValue); entities.put(key, newValue);
@@ -124,7 +123,6 @@ public abstract class FindAllQuery<T extends PersistentRecord>
stats.noteQuery(0, 1, _cachedRecords, _uncachedRecords); // one uncached query stats.noteQuery(0, 1, _cachedRecords, _uncachedRecords); // one uncached query
} }
protected SelectClause<T> _select;
protected int _cachedRecords, _uncachedRecords; protected int _cachedRecords, _uncachedRecords;
} }
@@ -148,7 +146,7 @@ public abstract class FindAllQuery<T extends PersistentRecord>
Map<Key<T>, T> entities = Maps.newHashMap(); Map<Key<T>, T> entities = Maps.newHashMap();
Set<Key<T>> fetchKeys = Sets.newHashSet(); Set<Key<T>> fetchKeys = Sets.newHashSet();
for (Key<T> key : _keys) { for (Key<T> key : _keys) {
T value = _ctx.<T>cacheLookup(key); T value = ctx.<T>cacheLookup(key);
if (value != null) { if (value != null) {
@SuppressWarnings("unchecked") T newValue = (T) value.clone(); @SuppressWarnings("unchecked") T newValue = (T) value.clone();
entities.put(key, newValue); entities.put(key, newValue);
@@ -213,49 +211,28 @@ public abstract class FindAllQuery<T extends PersistentRecord>
stats.noteQuery(0, 1, 0, _uncachedRecords); stats.noteQuery(0, 1, 0, _uncachedRecords);
} }
protected SelectClause<T> _select;
protected int _uncachedRecords; protected int _uncachedRecords;
} }
public FindAllQuery (PersistenceContext ctx, Class<T> type) @Override // from Query
throws DatabaseException
{
_ctx = ctx;
_type = type;
_marsh = _ctx.getMarshaller(type);
}
// from interface Query
public List<T> getCachedResult (PersistenceContext ctx) public List<T> getCachedResult (PersistenceContext ctx)
{ {
return null; // TODO return null; // TODO
} }
// // from interface Query @Override // from Operation
// public List<T> transformCacheHit (CacheKey key, List<T> bits)
// {
// if (bits == null) {
// return bits;
// }
// List<T> result = Lists.newArrayList();
// for (T bit : bits) {
// if (bit != null) {
// @SuppressWarnings("unchecked") T cbit = (T) bit.clone();
// result.add(cbit);
// } else {
// result.add(null);
// }
// }
// return result;
// }
// from interface Operation
public void updateStats (Stats stats) public void updateStats (Stats stats)
{ {
// TODO // TODO
} }
protected FindAllQuery (PersistenceContext ctx, Class<T> type)
throws DatabaseException
{
_type = type;
_marsh = ctx.getMarshaller(type);
}
protected List<T> loadAndResolve (PersistenceContext ctx, Connection conn, protected List<T> loadAndResolve (PersistenceContext ctx, Connection conn,
Collection<Key<T>> allKeys, Set<Key<T>> fetchKeys, Collection<Key<T>> allKeys, Set<Key<T>> fetchKeys,
Map<Key<T>, T> entities, String origStmt) Map<Key<T>, T> entities, String origStmt)
@@ -346,8 +323,8 @@ public abstract class FindAllQuery<T extends PersistentRecord>
return builder.append(")").toString(); return builder.append(")").toString();
} }
protected PersistenceContext _ctx;
protected SQLBuilder _builder; protected SQLBuilder _builder;
protected DepotMarshaller<T> _marsh; protected DepotMarshaller<T> _marsh;
protected Class<T> _type; protected Class<T> _type;
protected SelectClause<T> _select;
} }
@@ -37,8 +37,7 @@ import static com.samskivert.depot.Log.log;
/** /**
* The implementation of {@link DepotRepository#load} functionality. * The implementation of {@link DepotRepository#load} functionality.
*/ */
public class FindOneQuery<T extends PersistentRecord> public class FindOneQuery<T extends PersistentRecord> extends Query<T>
implements Query<T>
{ {
public FindOneQuery (PersistenceContext ctx, Class<T> type, QueryClause[] clauses) public FindOneQuery (PersistenceContext ctx, Class<T> type, QueryClause[] clauses)
throws DatabaseException throws DatabaseException
@@ -53,7 +52,7 @@ public class FindOneQuery<T extends PersistentRecord>
_builder.newQuery(_select); _builder.newQuery(_select);
} }
// from interface Query @Override // from Query
public T getCachedResult (PersistenceContext ctx) public T getCachedResult (PersistenceContext ctx)
{ {
CacheKey key = getCacheKey(); CacheKey key = getCacheKey();
@@ -70,7 +69,7 @@ public class FindOneQuery<T extends PersistentRecord>
return cvalue; return cvalue;
} }
// from interface Query @Override // from Query
public T invoke (PersistenceContext ctx, Connection conn, DatabaseLiaison liaison) public T invoke (PersistenceContext ctx, Connection conn, DatabaseLiaison liaison)
throws SQLException throws SQLException
{ {
@@ -110,7 +109,7 @@ public class FindOneQuery<T extends PersistentRecord>
} }
} }
// from interface Operation @Override // from Operation
public void updateStats (Stats stats) public void updateStats (Stats stats)
{ {
stats.noteQuery(0, 0, _cachedRecords, 1-_cachedRecords); stats.noteQuery(0, 0, _cachedRecords, 1-_cachedRecords);
@@ -117,6 +117,12 @@ public abstract class Modifier implements Operation<Integer>
_invalidator = invalidator; _invalidator = invalidator;
} }
// from interface Operation
public boolean isReadOnly ()
{
return false;
}
// from interface Operation // from interface Operation
public Integer invoke (PersistenceContext ctx, Connection conn, DatabaseLiaison liaison) public Integer invoke (PersistenceContext ctx, Connection conn, DatabaseLiaison liaison)
throws SQLException throws SQLException
@@ -30,6 +30,11 @@ import com.samskivert.jdbc.DatabaseLiaison;
*/ */
public interface Operation<T> public interface Operation<T>
{ {
/**
* Indicates whether or not this operation is safe to invoke on a database mirror.
*/
public boolean isReadOnly ();
/** /**
* Performs the actual JDBC interactions associated with this operation. * Performs the actual JDBC interactions associated with this operation.
*/ */
@@ -523,7 +523,7 @@ public class PersistenceContext
{ {
checkAreInitialized(); // le check du sanity checkAreInitialized(); // le check du sanity
boolean isReadOnly = !(op instanceof Modifier); boolean isReadOnly = op.isReadOnly();
Connection conn; Connection conn;
long preConnect = System.nanoTime(); long preConnect = System.nanoTime();
try { try {
+11 -10
View File
@@ -29,21 +29,16 @@ import com.samskivert.depot.PersistenceContext.CacheListener;
/** /**
* The base of all read-only queries. * The base of all read-only queries.
*/ */
public interface Query<T> extends Operation<T> public abstract class Query<T>
implements Operation<T>
{ {
/** A simple base class for non-complex queries. */ /** A simple base class for non-complex queries. */
public abstract class Trivial<T> implements Query<T> public static abstract class Trivial<T> extends Query<T>
{ {
public abstract T invoke (PersistenceContext ctx, Connection conn, DatabaseLiaison liaison) @Override // from Query
throws SQLException;
public T getCachedResult (PersistenceContext ctx) { public T getCachedResult (PersistenceContext ctx) {
return null; return null;
} }
public T transformCacheHit (CacheKey key, T value) {
return value;
}
} }
/** /**
@@ -51,5 +46,11 @@ public interface Query<T> extends Operation<T>
* method. If null is returned, the query will be {@link #invoke}d to obtain its result from * method. If null is returned, the query will be {@link #invoke}d to obtain its result from
* persistent storage. * persistent storage.
*/ */
public T getCachedResult (PersistenceContext ctx); public abstract T getCachedResult (PersistenceContext ctx);
// from interface Operation
public boolean isReadOnly ()
{
return true;
}
} }