A (slightly modified) patch from Charlie to use the magical statement
collecting Connection to automatically close all statements created during the course of our operations.
This commit is contained in:
@@ -21,7 +21,6 @@
|
|||||||
package com.samskivert.depot;
|
package com.samskivert.depot;
|
||||||
|
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
import java.sql.PreparedStatement;
|
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.sql.Timestamp;
|
import java.sql.Timestamp;
|
||||||
|
|
||||||
@@ -39,8 +38,6 @@ import com.samskivert.util.ArrayUtil;
|
|||||||
|
|
||||||
import com.samskivert.jdbc.ConnectionProvider;
|
import com.samskivert.jdbc.ConnectionProvider;
|
||||||
import com.samskivert.jdbc.DatabaseLiaison;
|
import com.samskivert.jdbc.DatabaseLiaison;
|
||||||
import com.samskivert.jdbc.JDBCUtil;
|
|
||||||
|
|
||||||
import com.samskivert.depot.clause.FieldOverride;
|
import com.samskivert.depot.clause.FieldOverride;
|
||||||
import com.samskivert.depot.clause.InsertClause;
|
import com.samskivert.depot.clause.InsertClause;
|
||||||
import com.samskivert.depot.clause.QueryClause;
|
import com.samskivert.depot.clause.QueryClause;
|
||||||
@@ -459,19 +456,13 @@ public abstract class DepotRepository
|
|||||||
|
|
||||||
builder.newQuery(new InsertClause(pClass, _result, identityFields));
|
builder.newQuery(new InsertClause(pClass, _result, identityFields));
|
||||||
|
|
||||||
PreparedStatement stmt = builder.prepare(conn);
|
int mods = builder.prepare(conn).executeUpdate();
|
||||||
try {
|
// run any post-factum value generators and potentially generate our key
|
||||||
int mods = stmt.executeUpdate();
|
if (_key == null) {
|
||||||
// run any post-factum value generators and potentially generate our key
|
marsh.generateFieldValues(conn, liaison, _result, true);
|
||||||
if (_key == null) {
|
updateKey(marsh.getPrimaryKey(_result, false));
|
||||||
marsh.generateFieldValues(conn, liaison, _result, true);
|
|
||||||
updateKey(marsh.getPrimaryKey(_result, false));
|
|
||||||
}
|
|
||||||
return mods;
|
|
||||||
|
|
||||||
} finally {
|
|
||||||
JDBCUtil.close(stmt);
|
|
||||||
}
|
}
|
||||||
|
return mods;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -698,44 +689,36 @@ public abstract class DepotRepository
|
|||||||
_ctx.invoke(new CachingModifier<T>(record, key, key) {
|
_ctx.invoke(new CachingModifier<T>(record, key, key) {
|
||||||
@Override
|
@Override
|
||||||
protected int invoke (Connection conn, DatabaseLiaison liaison) throws SQLException {
|
protected int invoke (Connection conn, DatabaseLiaison liaison) throws SQLException {
|
||||||
PreparedStatement stmt = null;
|
if (_key != null) {
|
||||||
try {
|
// run the update
|
||||||
if (_key != null) {
|
int mods = builder.prepare(conn).executeUpdate();
|
||||||
// run the update
|
if (mods > 0) {
|
||||||
stmt = builder.prepare(conn);
|
// if it succeeded, we're done
|
||||||
int mods = stmt.executeUpdate();
|
return mods;
|
||||||
if (mods > 0) {
|
|
||||||
// if it succeeded, we're done
|
|
||||||
return mods;
|
|
||||||
}
|
|
||||||
JDBCUtil.close(stmt);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// if the update modified zero rows or the primary key was unset, insert
|
|
||||||
Set<String> identityFields = Collections.emptySet();
|
|
||||||
if (_key == null) {
|
|
||||||
// first, set any auto-generated column values
|
|
||||||
identityFields = marsh.generateFieldValues(conn, liaison, _result, false);
|
|
||||||
// update our modifier's key so that it can cache our results
|
|
||||||
updateKey(marsh.getPrimaryKey(_result, false));
|
|
||||||
}
|
|
||||||
|
|
||||||
builder.newQuery(new InsertClause(pClass, _result, identityFields));
|
|
||||||
|
|
||||||
stmt = builder.prepare(conn);
|
|
||||||
int mods = stmt.executeUpdate();
|
|
||||||
|
|
||||||
// run any post-factum value generators and potentially generate our key
|
|
||||||
if (_key == null) {
|
|
||||||
marsh.generateFieldValues(conn, liaison, _result, true);
|
|
||||||
updateKey(marsh.getPrimaryKey(_result, false));
|
|
||||||
}
|
|
||||||
created[0] = true;
|
|
||||||
return mods;
|
|
||||||
|
|
||||||
} finally {
|
|
||||||
JDBCUtil.close(stmt);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if the update modified zero rows or the primary key was unset, insert
|
||||||
|
Set<String> identityFields = Collections.emptySet();
|
||||||
|
if (_key == null) {
|
||||||
|
|
||||||
|
// first, set any auto-generated column values
|
||||||
|
identityFields = marsh.generateFieldValues(conn, liaison, _result, false);
|
||||||
|
// update our modifier's key so that it can cache our results
|
||||||
|
updateKey(marsh.getPrimaryKey(_result, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.newQuery(new InsertClause(pClass, _result, identityFields));
|
||||||
|
|
||||||
|
int mods = builder.prepare(conn).executeUpdate();
|
||||||
|
|
||||||
|
// run any post-factum value generators and potentially generate our key
|
||||||
|
if (_key == null) {
|
||||||
|
marsh.generateFieldValues(conn, liaison, _result, true);
|
||||||
|
updateKey(marsh.getPrimaryKey(_result, false));
|
||||||
|
}
|
||||||
|
created[0] = true;
|
||||||
|
return mods;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return created[0];
|
return created[0];
|
||||||
@@ -821,12 +804,7 @@ public abstract class DepotRepository
|
|||||||
return _ctx.invoke(new Modifier(invalidator) {
|
return _ctx.invoke(new Modifier(invalidator) {
|
||||||
@Override
|
@Override
|
||||||
protected int invoke (Connection conn, DatabaseLiaison liaison) throws SQLException {
|
protected int invoke (Connection conn, DatabaseLiaison liaison) throws SQLException {
|
||||||
PreparedStatement stmt = builder.prepare(conn);
|
return builder.prepare(conn).executeUpdate();
|
||||||
try {
|
|
||||||
return stmt.executeUpdate();
|
|
||||||
} finally {
|
|
||||||
JDBCUtil.close(stmt);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -855,12 +833,7 @@ public abstract class DepotRepository
|
|||||||
return _ctx.invoke(new Modifier(invalidator) {
|
return _ctx.invoke(new Modifier(invalidator) {
|
||||||
@Override
|
@Override
|
||||||
protected int invoke (Connection conn, DatabaseLiaison liaison) throws SQLException {
|
protected int invoke (Connection conn, DatabaseLiaison liaison) throws SQLException {
|
||||||
PreparedStatement stmt = builder.prepare(conn);
|
return builder.prepare(conn).executeUpdate();
|
||||||
try {
|
|
||||||
return stmt.executeUpdate();
|
|
||||||
} finally {
|
|
||||||
JDBCUtil.close(stmt);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import java.util.Set;
|
|||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
|
import java.sql.Statement;
|
||||||
|
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import com.google.common.collect.Maps;
|
import com.google.common.collect.Maps;
|
||||||
@@ -37,6 +38,7 @@ import com.samskivert.util.StringUtil;
|
|||||||
|
|
||||||
import com.samskivert.jdbc.ConnectionProvider;
|
import com.samskivert.jdbc.ConnectionProvider;
|
||||||
import com.samskivert.jdbc.DatabaseLiaison;
|
import com.samskivert.jdbc.DatabaseLiaison;
|
||||||
|
import com.samskivert.jdbc.JDBCUtil;
|
||||||
import com.samskivert.jdbc.LiaisonRegistry;
|
import com.samskivert.jdbc.LiaisonRegistry;
|
||||||
|
|
||||||
import com.samskivert.depot.CacheAdapter.CacheCategory;
|
import com.samskivert.depot.CacheAdapter.CacheCategory;
|
||||||
@@ -539,6 +541,10 @@ public class PersistenceContext
|
|||||||
throw new DatabaseException(pe.getMessage(), pe.getCause());
|
throw new DatabaseException(pe.getMessage(), pe.getCause());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// wrap the connection in a proxy that will collect all opened statements
|
||||||
|
List<Statement> stmts = Lists.newArrayListWithCapacity(1);
|
||||||
|
conn = JDBCUtil.makeCollector(conn, stmts);
|
||||||
|
|
||||||
// TEMP: we synchronize on the connection to cooperate with SimpleRepository when used in
|
// TEMP: we synchronize on the connection to cooperate with SimpleRepository when used in
|
||||||
// conjunction with a StaticConnectionProvider; at some point we'll switch to standard JDBC
|
// conjunction with a StaticConnectionProvider; at some point we'll switch to standard JDBC
|
||||||
// connection pooling which will block in getConnection() instead of returning a connection
|
// connection pooling which will block in getConnection() instead of returning a connection
|
||||||
@@ -547,7 +553,18 @@ public class PersistenceContext
|
|||||||
long preInvoke = System.nanoTime();
|
long preInvoke = System.nanoTime();
|
||||||
try {
|
try {
|
||||||
// invoke our database operation
|
// invoke our database operation
|
||||||
T value = op.invoke(this, conn, _liaison);
|
T value;
|
||||||
|
try {
|
||||||
|
value = op.invoke(this, conn, _liaison);
|
||||||
|
} finally {
|
||||||
|
// close all opened statements; if any close fails, abort the close process as
|
||||||
|
// the whole connection is now unusable and will be discarded
|
||||||
|
for (Statement stmt : stmts) {
|
||||||
|
if (!stmt.isClosed()) {
|
||||||
|
stmt.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
// if auto-commit is off and this is a write operation, push it through
|
// if auto-commit is off and this is a write operation, push it through
|
||||||
if (!isReadOnly && !conn.getAutoCommit()) {
|
if (!isReadOnly && !conn.getAutoCommit()) {
|
||||||
conn.commit();
|
conn.commit();
|
||||||
|
|||||||
@@ -44,8 +44,6 @@ import com.samskivert.util.Tuple;
|
|||||||
|
|
||||||
import com.samskivert.jdbc.ColumnDefinition;
|
import com.samskivert.jdbc.ColumnDefinition;
|
||||||
import com.samskivert.jdbc.DatabaseLiaison;
|
import com.samskivert.jdbc.DatabaseLiaison;
|
||||||
import com.samskivert.jdbc.JDBCUtil;
|
|
||||||
|
|
||||||
import com.samskivert.depot.DatabaseException;
|
import com.samskivert.depot.DatabaseException;
|
||||||
import com.samskivert.depot.Key;
|
import com.samskivert.depot.Key;
|
||||||
import com.samskivert.depot.PersistenceContext;
|
import com.samskivert.depot.PersistenceContext;
|
||||||
@@ -711,12 +709,7 @@ public class DepotMarshaller<T extends PersistentRecord>
|
|||||||
throws SQLException
|
throws SQLException
|
||||||
{
|
{
|
||||||
if (builder.newQuery(clause)) {
|
if (builder.newQuery(clause)) {
|
||||||
PreparedStatement stmt = builder.prepare(conn);
|
return builder.prepare(conn).executeUpdate();
|
||||||
try {
|
|
||||||
return stmt.executeUpdate();
|
|
||||||
} finally {
|
|
||||||
JDBCUtil.close(stmt);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,8 +28,6 @@ import java.sql.ResultSet;
|
|||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
|
|
||||||
import com.samskivert.jdbc.DatabaseLiaison;
|
import com.samskivert.jdbc.DatabaseLiaison;
|
||||||
import com.samskivert.jdbc.JDBCUtil;
|
|
||||||
|
|
||||||
import com.samskivert.depot.DatabaseException;
|
import com.samskivert.depot.DatabaseException;
|
||||||
import com.samskivert.depot.Key;
|
import com.samskivert.depot.Key;
|
||||||
import com.samskivert.depot.PersistenceContext;
|
import com.samskivert.depot.PersistenceContext;
|
||||||
@@ -76,19 +74,15 @@ public class FindAllKeysQuery<T extends PersistentRecord> extends Query<XList<Ke
|
|||||||
{
|
{
|
||||||
XList<Key<T>> keys = new XArrayList<Key<T>>();
|
XList<Key<T>> keys = new XArrayList<Key<T>>();
|
||||||
PreparedStatement stmt = _builder.prepare(conn);
|
PreparedStatement stmt = _builder.prepare(conn);
|
||||||
try {
|
ResultSet rs = stmt.executeQuery();
|
||||||
ResultSet rs = stmt.executeQuery();
|
while (rs.next()) {
|
||||||
while (rs.next()) {
|
keys.add(_marsh.makePrimaryKey(rs));
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
// TODO: cache this result?
|
||||||
|
if (PersistenceContext.CACHE_DEBUG) {
|
||||||
|
log.info("Loaded " + _marsh.getTableName(), "count", keys.size());
|
||||||
|
}
|
||||||
|
return keys;
|
||||||
}
|
}
|
||||||
|
|
||||||
// from Query
|
// from Query
|
||||||
|
|||||||
@@ -36,8 +36,6 @@ import com.google.common.collect.Sets;
|
|||||||
import com.google.common.collect.Maps;
|
import com.google.common.collect.Maps;
|
||||||
|
|
||||||
import com.samskivert.jdbc.DatabaseLiaison;
|
import com.samskivert.jdbc.DatabaseLiaison;
|
||||||
import com.samskivert.jdbc.JDBCUtil;
|
|
||||||
|
|
||||||
import com.samskivert.depot.CacheAdapter.CacheCategory;
|
import com.samskivert.depot.CacheAdapter.CacheCategory;
|
||||||
import com.samskivert.depot.DatabaseException;
|
import com.samskivert.depot.DatabaseException;
|
||||||
import com.samskivert.depot.DepotRepository.CacheStrategy;
|
import com.samskivert.depot.DepotRepository.CacheStrategy;
|
||||||
@@ -132,13 +130,9 @@ public abstract class FindAllQuery<T extends PersistentRecord> extends Query<XLi
|
|||||||
builder.newQuery(_select);
|
builder.newQuery(_select);
|
||||||
PreparedStatement stmt = builder.prepare(conn);
|
PreparedStatement stmt = builder.prepare(conn);
|
||||||
stmtString = stmt.toString(); // for debugging
|
stmtString = stmt.toString(); // for debugging
|
||||||
try {
|
ResultSet rs = stmt.executeQuery();
|
||||||
ResultSet rs = stmt.executeQuery();
|
while (rs.next()) {
|
||||||
while (rs.next()) {
|
keys.add(_marsh.makePrimaryKey(rs));
|
||||||
keys.add(_marsh.makePrimaryKey(rs));
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
JDBCUtil.close(stmt);
|
|
||||||
}
|
}
|
||||||
_keys = KeySet.newKeySet(_type, keys);
|
_keys = KeySet.newKeySet(_type, keys);
|
||||||
_uncachedQueries++;
|
_uncachedQueries++;
|
||||||
@@ -239,14 +233,9 @@ public abstract class FindAllQuery<T extends PersistentRecord> extends Query<XLi
|
|||||||
XList<T> result = new XArrayList<T>();
|
XList<T> result = new XArrayList<T>();
|
||||||
SQLBuilder builder = ctx.getSQLBuilder(DepotTypes.getDepotTypes(ctx, _select));
|
SQLBuilder builder = ctx.getSQLBuilder(DepotTypes.getDepotTypes(ctx, _select));
|
||||||
builder.newQuery(_select);
|
builder.newQuery(_select);
|
||||||
PreparedStatement stmt = builder.prepare(conn);
|
ResultSet rs = builder.prepare(conn).executeQuery();
|
||||||
try {
|
while (rs.next()) {
|
||||||
ResultSet rs = stmt.executeQuery();
|
result.add(_marsh.createObject(rs));
|
||||||
while (rs.next()) {
|
|
||||||
result.add(_marsh.createObject(rs));
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
JDBCUtil.close(stmt);
|
|
||||||
}
|
}
|
||||||
_explicitQueries++;
|
_explicitQueries++;
|
||||||
if (PersistenceContext.CACHE_DEBUG) {
|
if (PersistenceContext.CACHE_DEBUG) {
|
||||||
@@ -348,39 +337,33 @@ public abstract class FindAllQuery<T extends PersistentRecord> extends Query<XLi
|
|||||||
_type, _marsh.getFieldNames(), KeySet.newKeySet(_type, keys));
|
_type, _marsh.getFieldNames(), KeySet.newKeySet(_type, keys));
|
||||||
SQLBuilder builder = ctx.getSQLBuilder(DepotTypes.getDepotTypes(ctx, select));
|
SQLBuilder builder = ctx.getSQLBuilder(DepotTypes.getDepotTypes(ctx, select));
|
||||||
builder.newQuery(select);
|
builder.newQuery(select);
|
||||||
PreparedStatement stmt = builder.prepare(conn);
|
Set<Key<T>> got = Sets.newHashSet();
|
||||||
try {
|
ResultSet rs = builder.prepare(conn).executeQuery();
|
||||||
Set<Key<T>> got = Sets.newHashSet();
|
int cnt = 0, dups = 0;
|
||||||
ResultSet rs = stmt.executeQuery();
|
while (rs.next()) {
|
||||||
int cnt = 0, dups = 0;
|
T obj = _marsh.createObject(rs);
|
||||||
while (rs.next()) {
|
Key<T> key = _marsh.getPrimaryKey(obj);
|
||||||
T obj = _marsh.createObject(rs);
|
if (entities.put(key, obj) != null) {
|
||||||
Key<T> key = _marsh.getPrimaryKey(obj);
|
dups++;
|
||||||
if (entities.put(key, obj) != null) {
|
|
||||||
dups++;
|
|
||||||
}
|
|
||||||
ctx.cacheStore(CacheCategory.RECORD, new KeyCacheKey(key), obj.clone());
|
|
||||||
got.add(key);
|
|
||||||
cnt++;
|
|
||||||
}
|
}
|
||||||
// if we get more results than we planned, or if we're doing a two-phase query and got
|
ctx.cacheStore(CacheCategory.RECORD, new KeyCacheKey(key), obj.clone());
|
||||||
// fewer, then complain
|
got.add(key);
|
||||||
if (cnt > keys.size() || (origStmt != null && cnt < keys.size())) {
|
cnt++;
|
||||||
log.warning("Row count mismatch in second pass", "origQuery", origStmt,
|
|
||||||
// we need toString() here or StringUtil will get smart and dump our
|
|
||||||
// KeySet using its iterator which results in verbosity
|
|
||||||
"wanted", KeySet.newKeySet(_type, keys).toString(),
|
|
||||||
"got", KeySet.newKeySet(_type, got).toString(),
|
|
||||||
"dups", dups, new Exception());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (PersistenceContext.CACHE_DEBUG) {
|
|
||||||
log.info("Cached " + _marsh.getTableName(), "count", cnt);
|
|
||||||
}
|
|
||||||
|
|
||||||
} finally {
|
|
||||||
JDBCUtil.close(stmt);
|
|
||||||
}
|
}
|
||||||
|
// if we get more results than we planned, or if we're doing a two-phase query and got
|
||||||
|
// fewer, then complain
|
||||||
|
if (cnt > keys.size() || (origStmt != null && cnt < keys.size())) {
|
||||||
|
log.warning("Row count mismatch in second pass", "origQuery", origStmt,
|
||||||
|
// we need toString() here or StringUtil will get smart and dump our
|
||||||
|
// KeySet using its iterator which results in verbosity
|
||||||
|
"wanted", KeySet.newKeySet(_type, keys).toString(), "got", KeySet.newKeySet(
|
||||||
|
_type, got).toString(), "dups", dups, new Exception());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PersistenceContext.CACHE_DEBUG) {
|
||||||
|
log.info("Cached " + _marsh.getTableName(), "count", cnt);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String keysToString (Iterable<Key<T>> keySet)
|
protected String keysToString (Iterable<Key<T>> keySet)
|
||||||
|
|||||||
@@ -21,13 +21,10 @@
|
|||||||
package com.samskivert.depot.impl;
|
package com.samskivert.depot.impl;
|
||||||
|
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
import java.sql.PreparedStatement;
|
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
|
|
||||||
import com.samskivert.jdbc.DatabaseLiaison;
|
import com.samskivert.jdbc.DatabaseLiaison;
|
||||||
import com.samskivert.jdbc.JDBCUtil;
|
|
||||||
|
|
||||||
import com.samskivert.depot.CacheKey;
|
import com.samskivert.depot.CacheKey;
|
||||||
import com.samskivert.depot.DatabaseException;
|
import com.samskivert.depot.DatabaseException;
|
||||||
import com.samskivert.depot.DepotRepository;
|
import com.samskivert.depot.DepotRepository;
|
||||||
@@ -82,40 +79,34 @@ public class FindOneQuery<T extends PersistentRecord> extends Query<T>
|
|||||||
public T invoke (PersistenceContext ctx, Connection conn, DatabaseLiaison liaison)
|
public T invoke (PersistenceContext ctx, Connection conn, DatabaseLiaison liaison)
|
||||||
throws SQLException
|
throws SQLException
|
||||||
{
|
{
|
||||||
PreparedStatement stmt = _builder.prepare(conn);
|
// load up the record in question
|
||||||
try {
|
T result = null;
|
||||||
// load up the record in question
|
ResultSet rs = _builder.prepare(conn).executeQuery();
|
||||||
T result = null;
|
if (rs.next()) {
|
||||||
ResultSet rs = stmt.executeQuery();
|
result = _marsh.createObject(rs);
|
||||||
if (rs.next()) {
|
|
||||||
result = _marsh.createObject(rs);
|
|
||||||
}
|
|
||||||
// TODO: if (rs.next()) issue warning?
|
|
||||||
rs.close();
|
|
||||||
|
|
||||||
// potentially cache the result
|
|
||||||
CacheKey key = getCacheKey();
|
|
||||||
if (key == null) {
|
|
||||||
// no row-specific cache key was given, if we can, create a key from the record
|
|
||||||
if (result != null && _marsh.hasPrimaryKey()) {
|
|
||||||
key = new KeyCacheKey(_marsh.getPrimaryKey(result));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (PersistenceContext.CACHE_DEBUG) {
|
|
||||||
log.info("Loaded " + (key != null ? key : _marsh.getTableName()));
|
|
||||||
}
|
|
||||||
if (key != null) {
|
|
||||||
ctx.cacheStore(CacheCategory.RECORD, key, (result != null) ? result.clone() : null);
|
|
||||||
if (PersistenceContext.CACHE_DEBUG) {
|
|
||||||
log.info("Cached " + key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
|
|
||||||
} finally {
|
|
||||||
JDBCUtil.close(stmt);
|
|
||||||
}
|
}
|
||||||
|
// TODO: if (rs.next()) issue warning?
|
||||||
|
rs.close();
|
||||||
|
|
||||||
|
// potentially cache the result
|
||||||
|
CacheKey key = getCacheKey();
|
||||||
|
if (key == null) {
|
||||||
|
// no row-specific cache key was given, if we can, create a key from the record
|
||||||
|
if (result != null && _marsh.hasPrimaryKey()) {
|
||||||
|
key = new KeyCacheKey(_marsh.getPrimaryKey(result));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (PersistenceContext.CACHE_DEBUG) {
|
||||||
|
log.info("Loaded " + (key != null ? key : _marsh.getTableName()));
|
||||||
|
}
|
||||||
|
if (key != null) {
|
||||||
|
ctx.cacheStore(CacheCategory.RECORD, key, (result != null) ? result.clone() : null);
|
||||||
|
if (PersistenceContext.CACHE_DEBUG) {
|
||||||
|
log.info("Cached " + key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// from Operation
|
// from Operation
|
||||||
|
|||||||
@@ -25,12 +25,10 @@ import java.sql.Clob;
|
|||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
import java.sql.Date;
|
import java.sql.Date;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.sql.Statement;
|
|
||||||
import java.sql.Time;
|
import java.sql.Time;
|
||||||
import java.sql.Timestamp;
|
import java.sql.Timestamp;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import com.samskivert.jdbc.JDBCUtil;
|
|
||||||
import com.samskivert.util.Tuple;
|
import com.samskivert.util.Tuple;
|
||||||
|
|
||||||
import com.samskivert.depot.PersistentRecord;
|
import com.samskivert.depot.PersistentRecord;
|
||||||
@@ -206,13 +204,8 @@ public class MySQLBuilder
|
|||||||
}
|
}
|
||||||
update.append(")");
|
update.append(")");
|
||||||
|
|
||||||
Statement stmt = conn.createStatement();
|
log.info("Adding full-text search index: ftsIx_" + fts.name());
|
||||||
try {
|
conn.createStatement().executeUpdate(update.toString());
|
||||||
log.info("Adding full-text search index: ftsIx_" + fts.name());
|
|
||||||
stmt.executeUpdate(update.toString());
|
|
||||||
} finally {
|
|
||||||
JDBCUtil.close(stmt);
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ package com.samskivert.depot.impl;
|
|||||||
|
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
|
import java.sql.Statement;
|
||||||
|
|
||||||
import com.samskivert.depot.PersistenceContext;
|
import com.samskivert.depot.PersistenceContext;
|
||||||
import com.samskivert.depot.Stats;
|
import com.samskivert.depot.Stats;
|
||||||
@@ -38,7 +39,9 @@ public interface Operation<T>
|
|||||||
public boolean isReadOnly ();
|
public boolean isReadOnly ();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Performs the actual JDBC interactions associated with this operation.
|
* Performs the actual JDBC interactions associated with this operation. Any {@link Statement}
|
||||||
|
* instances created with the given connection will be closed automatically after this method
|
||||||
|
* returns. The operation need not close them itself.
|
||||||
*/
|
*/
|
||||||
public T invoke (PersistenceContext ctx, Connection conn, DatabaseLiaison liaison)
|
public T invoke (PersistenceContext ctx, Connection conn, DatabaseLiaison liaison)
|
||||||
throws SQLException;
|
throws SQLException;
|
||||||
|
|||||||
@@ -31,7 +31,6 @@ import java.sql.Timestamp;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import com.samskivert.jdbc.DatabaseLiaison;
|
import com.samskivert.jdbc.DatabaseLiaison;
|
||||||
import com.samskivert.jdbc.JDBCUtil;
|
|
||||||
import com.samskivert.jdbc.LiaisonRegistry;
|
import com.samskivert.jdbc.LiaisonRegistry;
|
||||||
import com.samskivert.util.ArrayUtil;
|
import com.samskivert.util.ArrayUtil;
|
||||||
import com.samskivert.util.StringUtil;
|
import com.samskivert.util.StringUtil;
|
||||||
@@ -185,18 +184,12 @@ public class PostgreSQLBuilder
|
|||||||
append(liaison.columnSQL(column)).append(")");
|
append(liaison.columnSQL(column)).append(")");
|
||||||
|
|
||||||
Statement stmt = conn.createStatement();
|
Statement stmt = conn.createStatement();
|
||||||
try {
|
log.info("Adding full-text search column, index and trigger: " + column + ", " +
|
||||||
log.info(
|
index + ", " + trigger);
|
||||||
"Adding full-text search column, index and trigger: " + column + ", " +
|
liaison.addColumn(conn, table, column, "TSVECTOR", true);
|
||||||
index + ", " + trigger);
|
stmt.executeUpdate(initColumn.toString());
|
||||||
liaison.addColumn(conn, table, column, "TSVECTOR", true);
|
stmt.executeUpdate(createIndex.toString());
|
||||||
stmt.executeUpdate(initColumn.toString());
|
stmt.executeUpdate(createTrigger.toString());
|
||||||
stmt.executeUpdate(createIndex.toString());
|
|
||||||
stmt.executeUpdate(createTrigger.toString());
|
|
||||||
|
|
||||||
} finally {
|
|
||||||
JDBCUtil.close(stmt);
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,7 +30,6 @@ import com.samskivert.depot.annotation.TableGenerator;
|
|||||||
|
|
||||||
import com.samskivert.jdbc.ColumnDefinition;
|
import com.samskivert.jdbc.ColumnDefinition;
|
||||||
import com.samskivert.jdbc.DatabaseLiaison;
|
import com.samskivert.jdbc.DatabaseLiaison;
|
||||||
import com.samskivert.jdbc.JDBCUtil;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates primary keys using an external table .
|
* Generates primary keys using an external table .
|
||||||
@@ -69,106 +68,83 @@ public class TableValueGenerator extends ValueGenerator
|
|||||||
new String[] { _pkColumnName });
|
new String[] { _pkColumnName });
|
||||||
|
|
||||||
// and also that there's a row in it for us
|
// and also that there's a row in it for us
|
||||||
PreparedStatement stmt = null;
|
PreparedStatement stmt = conn.prepareStatement(
|
||||||
try {
|
" SELECT * FROM " + liaison.tableSQL(_valueTable) +
|
||||||
stmt = conn.prepareStatement(
|
" WHERE " + liaison.columnSQL(_pkColumnName) + " = ?");
|
||||||
" SELECT * FROM " + liaison.tableSQL(_valueTable) +
|
stmt.setString(1, _pkColumnValue);
|
||||||
" WHERE " + liaison.columnSQL(_pkColumnName) + " = ?");
|
if (stmt.executeQuery().next()) {
|
||||||
stmt.setString(1, _pkColumnValue);
|
return;
|
||||||
if (stmt.executeQuery().next()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
JDBCUtil.close(stmt);
|
|
||||||
stmt = null;
|
|
||||||
|
|
||||||
int initialValue = _initialValue;
|
|
||||||
if (_migrateIfExists) {
|
|
||||||
Integer max = getFieldMaximum(conn, liaison);
|
|
||||||
if (max != null) {
|
|
||||||
initialValue = 1 + max.intValue();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
stmt = conn.prepareStatement(
|
|
||||||
" INSERT INTO " + liaison.tableSQL(_valueTable) + " (" +
|
|
||||||
liaison.columnSQL(_pkColumnName) + ", " + liaison.columnSQL(_valueColumnName) +
|
|
||||||
") VALUES (?, ?)");
|
|
||||||
stmt.setString(1, _pkColumnValue);
|
|
||||||
stmt.setInt(2, initialValue);
|
|
||||||
stmt.executeUpdate();
|
|
||||||
|
|
||||||
} finally {
|
|
||||||
JDBCUtil.close(stmt);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int initialValue = _initialValue;
|
||||||
|
if (_migrateIfExists) {
|
||||||
|
Integer max = getFieldMaximum(conn, liaison);
|
||||||
|
if (max != null) {
|
||||||
|
initialValue = 1 + max.intValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stmt = conn.prepareStatement(
|
||||||
|
" INSERT INTO " + liaison.tableSQL(_valueTable) + " (" +
|
||||||
|
liaison.columnSQL(_pkColumnName) + ", " + liaison.columnSQL(_valueColumnName) +
|
||||||
|
") VALUES (?, ?)");
|
||||||
|
stmt.setString(1, _pkColumnValue);
|
||||||
|
stmt.setInt(2, initialValue);
|
||||||
|
stmt.executeUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override // from ValueGenerator
|
@Override // from ValueGenerator
|
||||||
public void delete (Connection conn, DatabaseLiaison liaison) throws SQLException
|
public void delete (Connection conn, DatabaseLiaison liaison) throws SQLException
|
||||||
{
|
{
|
||||||
PreparedStatement stmt = null;
|
PreparedStatement stmt = conn.prepareStatement(
|
||||||
try {
|
" DELETE FROM " + liaison.tableSQL(_valueTable) +
|
||||||
stmt = conn.prepareStatement(
|
" WHERE " + liaison.columnSQL(_pkColumnName) + " = ?");
|
||||||
" DELETE FROM " + liaison.tableSQL(_valueTable) +
|
stmt.setString(1, _pkColumnValue);
|
||||||
" WHERE " + liaison.columnSQL(_pkColumnName) + " = ?");
|
stmt.executeUpdate();
|
||||||
stmt.setString(1, _pkColumnValue);
|
|
||||||
stmt.executeUpdate();
|
|
||||||
|
|
||||||
} finally {
|
|
||||||
JDBCUtil.close(stmt);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override // from ValueGenerator
|
@Override // from ValueGenerator
|
||||||
public int nextGeneratedValue (Connection conn, DatabaseLiaison liaison)
|
public int nextGeneratedValue (Connection conn, DatabaseLiaison liaison)
|
||||||
throws SQLException
|
throws SQLException
|
||||||
{
|
{
|
||||||
PreparedStatement readStatement = null;
|
// TODO: Make this lockless!
|
||||||
PreparedStatement writeStatement = null;
|
PreparedStatement readStatement = conn.prepareStatement(
|
||||||
try {
|
" SELECT " + liaison.columnSQL(_valueColumnName) +
|
||||||
// TODO: Make this lockless!
|
" FROM " + liaison.tableSQL(_valueTable) +
|
||||||
readStatement = conn.prepareStatement(
|
" WHERE " + liaison.columnSQL(_pkColumnName) + " = ? ");
|
||||||
" SELECT " + liaison.columnSQL(_valueColumnName) +
|
readStatement.setString(1, _pkColumnValue);
|
||||||
" FROM " + liaison.tableSQL(_valueTable) +
|
|
||||||
" WHERE " + liaison.columnSQL(_pkColumnName) + " = ? ");
|
|
||||||
readStatement.setString(1, _pkColumnValue);
|
|
||||||
|
|
||||||
writeStatement = conn.prepareStatement(
|
PreparedStatement writeStatement = conn.prepareStatement(
|
||||||
" UPDATE " + liaison.tableSQL(_valueTable) +
|
" UPDATE " + liaison.tableSQL(_valueTable) +
|
||||||
" SET " + liaison.columnSQL(_valueColumnName) + " = ? " +
|
" SET " + liaison.columnSQL(_valueColumnName) + " = ? " +
|
||||||
" WHERE " + liaison.columnSQL(_pkColumnName) + " = ? " +
|
" WHERE " + liaison.columnSQL(_pkColumnName) + " = ? " +
|
||||||
" AND " + liaison.columnSQL(_valueColumnName) + " = ? ");
|
" AND " + liaison.columnSQL(_valueColumnName) + " = ? ");
|
||||||
|
|
||||||
for (int tries = 0; tries < 10; tries ++) {
|
for (int tries = 0; tries < 10; tries ++) {
|
||||||
// execute the query
|
// execute the query
|
||||||
ResultSet rs = readStatement.executeQuery();
|
ResultSet rs = readStatement.executeQuery();
|
||||||
if (!rs.next()) {
|
if (!rs.next()) {
|
||||||
throw new SQLException(
|
throw new SQLException(
|
||||||
"Failed to find next primary key value [table=" + _valueTable +
|
"Failed to find next primary key value [table=" + _valueTable +
|
||||||
", column=" + _valueColumnName + "]");
|
", column=" + _valueColumnName + "]");
|
||||||
}
|
|
||||||
// fetch the next available value
|
|
||||||
int val = rs.getInt(1);
|
|
||||||
|
|
||||||
// claim this value locklessly
|
|
||||||
writeStatement.setInt(1, val + _allocationSize);
|
|
||||||
writeStatement.setString(2, _pkColumnValue);
|
|
||||||
writeStatement.setInt(3, val);
|
|
||||||
|
|
||||||
// if we modified a row, we know we and nobody else got this particular value!
|
|
||||||
if (writeStatement.executeUpdate() == 1) {
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
// else try again
|
|
||||||
}
|
}
|
||||||
throw new SQLException(
|
// fetch the next available value
|
||||||
"Failed to claim next primary key value in 10 attempts [table=" + _valueTable +
|
int val = rs.getInt(1);
|
||||||
", column=" + _valueColumnName + "]");
|
|
||||||
|
|
||||||
} finally {
|
// claim this value locklessly
|
||||||
JDBCUtil.close(readStatement);
|
writeStatement.setInt(1, val + _allocationSize);
|
||||||
JDBCUtil.close(writeStatement);
|
writeStatement.setString(2, _pkColumnValue);
|
||||||
|
writeStatement.setInt(3, val);
|
||||||
|
|
||||||
|
// if we modified a row, we know we and nobody else got this particular value!
|
||||||
|
if (writeStatement.executeUpdate() == 1) {
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
// else try again
|
||||||
}
|
}
|
||||||
|
throw new SQLException(
|
||||||
|
"Failed to claim next primary key value in 10 attempts [table=" + _valueTable +
|
||||||
|
", column=" + _valueColumnName + "]");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ import java.sql.SQLException;
|
|||||||
import java.sql.Statement;
|
import java.sql.Statement;
|
||||||
|
|
||||||
import com.samskivert.jdbc.DatabaseLiaison;
|
import com.samskivert.jdbc.DatabaseLiaison;
|
||||||
import com.samskivert.jdbc.JDBCUtil;
|
|
||||||
import com.samskivert.depot.annotation.GeneratedValue;
|
import com.samskivert.depot.annotation.GeneratedValue;
|
||||||
|
|
||||||
import static com.samskivert.depot.Log.log;
|
import static com.samskivert.depot.Log.log;
|
||||||
@@ -85,24 +84,19 @@ public abstract class ValueGenerator
|
|||||||
String table = _dm.getTableName();
|
String table = _dm.getTableName();
|
||||||
|
|
||||||
Statement stmt = conn.createStatement();
|
Statement stmt = conn.createStatement();
|
||||||
try {
|
ResultSet rs = stmt.executeQuery(
|
||||||
ResultSet rs = stmt.executeQuery(
|
" SELECT COUNT(*), MAX(" + liaison.columnSQL(column) + ") " +
|
||||||
" SELECT COUNT(*), MAX(" + liaison.columnSQL(column) + ") " +
|
" FROM " + liaison.tableSQL(table));
|
||||||
" FROM " + liaison.tableSQL(table));
|
if (!rs.next()) {
|
||||||
if (!rs.next()) {
|
log.warning("Query on count()/max() bizarrely returned no rows.");
|
||||||
log.warning("Query on count()/max() bizarrely returned no rows.");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
int cnt = rs.getInt(1);
|
|
||||||
if (cnt > 0) {
|
|
||||||
return Integer.valueOf(rs.getInt(2));
|
|
||||||
}
|
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
} finally {
|
|
||||||
JDBCUtil.close(stmt);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int cnt = rs.getInt(1);
|
||||||
|
if (cnt > 0) {
|
||||||
|
return Integer.valueOf(rs.getInt(2));
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DepotMarshaller<?> getDepotMarshaller ()
|
public DepotMarshaller<?> getDepotMarshaller ()
|
||||||
|
|||||||
Reference in New Issue
Block a user