From 689f56bbc49059700e7eb02e1960f4bce67f9a3f Mon Sep 17 00:00:00 2001 From: Hideki Sugimoto Date: Mon, 15 Aug 2022 03:36:33 +0900 Subject: [PATCH] TableMetadata and MappingColumn cache includes schema --- .../AbstractExtractionCondition.java | 1 + .../jp/co/future/uroborosql/SqlAgentImpl.java | 19 +- .../future/uroborosql/SqlEntityQueryImpl.java | 7 +- .../jp/co/future/uroborosql/SqlQueryImpl.java | 4 +- .../future/uroborosql/context/SqlContext.java | 15 ++ .../uroborosql/context/SqlContextImpl.java | 24 +++ .../converter/EntityResultSetConverter.java | 6 +- .../mapping/DefaultEntityHandler.java | 96 ++++++---- .../uroborosql/mapping/MappingUtils.java | 164 ++++++++++++++---- 9 files changed, 255 insertions(+), 81 deletions(-) diff --git a/src/main/java/jp/co/future/uroborosql/AbstractExtractionCondition.java b/src/main/java/jp/co/future/uroborosql/AbstractExtractionCondition.java index 672f5119..6d355007 100644 --- a/src/main/java/jp/co/future/uroborosql/AbstractExtractionCondition.java +++ b/src/main/java/jp/co/future/uroborosql/AbstractExtractionCondition.java @@ -51,6 +51,7 @@ abstract class AbstractExtractionCondition> extends Abstr AbstractExtractionCondition(final SqlAgent agent, final TableMetadata tableMetadata, final SqlContext context) { super(agent, context); this.tableMetadata = tableMetadata; + context.setSchema(tableMetadata.getSchema()); this.rawStrings = new ArrayList<>(); this.useOperator = false; } diff --git a/src/main/java/jp/co/future/uroborosql/SqlAgentImpl.java b/src/main/java/jp/co/future/uroborosql/SqlAgentImpl.java index 5bbd4e67..5410c2b5 100644 --- a/src/main/java/jp/co/future/uroborosql/SqlAgentImpl.java +++ b/src/main/java/jp/co/future/uroborosql/SqlAgentImpl.java @@ -768,7 +768,7 @@ public int insert(final E entity) { context.setSqlKind(SqlKind.INSERT); // 自動採番カラムの取得とcontextへの設定を行う - MappingColumn[] mappingColumns = MappingUtils.getMappingColumns(entityType); + MappingColumn[] mappingColumns = MappingUtils.getMappingColumns(metadata.getSchema(), entityType); List autoGeneratedColumns = getAutoGeneratedColumns(context, mappingColumns, metadata, entity); @@ -955,11 +955,12 @@ public int update(final E entity) { handler.setUpdateParams(context, entity); int count = handler.doUpdate(this, context, entity); - MappingUtils.getVersionMappingColumn(type).ifPresent(versionColumn -> { + MappingUtils.getVersionMappingColumn(metadata.getSchema(), type).ifPresent(versionColumn -> { if (count == 0) { throw new OptimisticLockException(context); } else { - Map columnMap = MappingUtils.getMappingColumnMap(type, SqlKind.NONE); + Map columnMap = MappingUtils.getMappingColumnMap(metadata.getSchema(), type, + SqlKind.NONE); Object[] keys = metadata.getColumns().stream() .filter(TableMetadata.Column::isKey) .sorted(Comparator.comparingInt(TableMetadata.Column::getKeySeq)) @@ -1086,7 +1087,8 @@ private E mergeAndReturn(final E entity, final boolean locking) { throw new IllegalArgumentException("Entity has no keys."); } - Map mappingColumns = MappingUtils.getMappingColumnMap(type, SqlKind.UPDATE); + Map mappingColumns = MappingUtils.getMappingColumnMap(metadata.getSchema(), type, + SqlKind.UPDATE); SqlEntityQuery query = (SqlEntityQuery) query(type); for (TableMetadata.Column column : keyColumns) { @@ -1269,7 +1271,7 @@ protected int batchInsert(final Class entityType, final Stream entitie if (isFirst) { isFirst = false; - MappingColumn[] mappingColumns = MappingUtils.getMappingColumns(entityType); + MappingColumn[] mappingColumns = MappingUtils.getMappingColumns(metadata.getSchema(), entityType); autoGeneratedColumns = getAutoGeneratedColumns(context, mappingColumns, metadata, entity); // SQLのID項目IF分岐判定をtrueにするために値が設定されているID項目を保持しておく @@ -1356,7 +1358,7 @@ protected int bulkInsert(final Class entityType, final Stream entities if (isFirst) { isFirst = false; - MappingColumn[] mappingColumns = MappingUtils.getMappingColumns(entityType); + MappingColumn[] mappingColumns = MappingUtils.getMappingColumns(metadata.getSchema(), entityType); autoGeneratedColumns = getAutoGeneratedColumns(context, mappingColumns, metadata, entity); // SQLのID項目IF分岐判定をtrueにするために値が設定されているID項目を保持しておく @@ -1442,7 +1444,8 @@ protected int batchUpdate(final Class entityType, final Stream entitie SqlContext context = handler.createBatchUpdateContext(this, metadata, entityType); context.setSqlKind(SqlKind.BATCH_UPDATE); - Optional versionColumn = MappingUtils.getVersionMappingColumn(entityType); + Optional versionColumn = MappingUtils.getVersionMappingColumn(metadata.getSchema(), + entityType); int entityCount = 0; int updateCount = 0; List entityList = new ArrayList<>(); @@ -1476,7 +1479,7 @@ protected int batchUpdate(final Class entityType, final Stream entitie List keyColumns = metadata.getColumns().stream() .filter(TableMetadata.Column::isKey) .sorted(Comparator.comparingInt(TableMetadata.Column::getKeySeq)) - .map(c -> MappingUtils.getMappingColumnMap(entityType, SqlKind.NONE) + .map(c -> MappingUtils.getMappingColumnMap(metadata.getSchema(), entityType, SqlKind.NONE) .get(c.getCamelColumnName())) .collect(Collectors.toList()); diff --git a/src/main/java/jp/co/future/uroborosql/SqlEntityQueryImpl.java b/src/main/java/jp/co/future/uroborosql/SqlEntityQueryImpl.java index c0553fe0..aaf541eb 100644 --- a/src/main/java/jp/co/future/uroborosql/SqlEntityQueryImpl.java +++ b/src/main/java/jp/co/future/uroborosql/SqlEntityQueryImpl.java @@ -57,7 +57,6 @@ final class SqlEntityQueryImpl extends AbstractExtractionCondition list; private final List includeColumns; private final List excludeColumns; @@ -256,7 +255,7 @@ public long count(final String col) { @Override public T sum(final String col) { String camelColumnName = CaseFormat.CAMEL_CASE.convert(col); - MappingColumn mappingColumn = MappingUtils.getMappingColumn(entityType, camelColumnName); + MappingColumn mappingColumn = MappingUtils.getMappingColumn(context().getSchema(), entityType, camelColumnName); Class rawType = mappingColumn.getJavaType().getRawType(); if (!(short.class.equals(rawType) || int.class.equals(rawType) || @@ -291,7 +290,7 @@ public T sum(final String col) { @Override public T min(final String col) { String camelColumnName = CaseFormat.CAMEL_CASE.convert(col); - MappingColumn mappingColumn = MappingUtils.getMappingColumn(entityType, camelColumnName); + MappingColumn mappingColumn = MappingUtils.getMappingColumn(context().getSchema(), entityType, camelColumnName); TableMetadata.Column column = tableMetadata.getColumn(camelColumnName); StringBuilder sql = new StringBuilder("select min(t_.").append(column.getColumnIdentifier()).append(") as ") .append(column.getColumnIdentifier()).append(" from (") @@ -317,7 +316,7 @@ public T min(final String col) { @Override public T max(final String col) { String camelColumnName = CaseFormat.CAMEL_CASE.convert(col); - MappingColumn mappingColumn = MappingUtils.getMappingColumn(entityType, camelColumnName); + MappingColumn mappingColumn = MappingUtils.getMappingColumn(context().getSchema(), entityType, camelColumnName); TableMetadata.Column column = tableMetadata.getColumn(camelColumnName); StringBuilder sql = new StringBuilder("select max(t_.").append(column.getColumnIdentifier()).append(") as ") .append(column.getColumnIdentifier()).append(" from (") diff --git a/src/main/java/jp/co/future/uroborosql/SqlQueryImpl.java b/src/main/java/jp/co/future/uroborosql/SqlQueryImpl.java index b848a229..f3972f93 100644 --- a/src/main/java/jp/co/future/uroborosql/SqlQueryImpl.java +++ b/src/main/java/jp/co/future/uroborosql/SqlQueryImpl.java @@ -258,8 +258,8 @@ public Stream> stream(final CaseFormat caseFormat) { */ @Override public Stream stream(final Class type) { - return stream( - new EntityResultSetConverter<>(type, new PropertyMapperManager(this.agent.getSqlConfig().getClock()))); + return stream(new EntityResultSetConverter<>(context().getSchema(), type, + new PropertyMapperManager(this.agent.getSqlConfig().getClock()))); } } diff --git a/src/main/java/jp/co/future/uroborosql/context/SqlContext.java b/src/main/java/jp/co/future/uroborosql/context/SqlContext.java index 7b99b68f..84be3cfb 100644 --- a/src/main/java/jp/co/future/uroborosql/context/SqlContext.java +++ b/src/main/java/jp/co/future/uroborosql/context/SqlContext.java @@ -71,6 +71,21 @@ public interface SqlContext extends TransformContext, SqlFluent, Pro */ SqlContext setSqlId(String sqlId); + /** + * SQLを実行するスキーマを取得 + * + * @return スキーマ + */ + String getSchema(); + + /** + * SQLを実行するスキーマを設定 + * + * @param schema スキーマ + * @return 自身のSqlContext + */ + SqlContext setSchema(String schema); + /** * 最大リトライ回数 を取得する * diff --git a/src/main/java/jp/co/future/uroborosql/context/SqlContextImpl.java b/src/main/java/jp/co/future/uroborosql/context/SqlContextImpl.java index bc5e50aa..c13bad8a 100644 --- a/src/main/java/jp/co/future/uroborosql/context/SqlContextImpl.java +++ b/src/main/java/jp/co/future/uroborosql/context/SqlContextImpl.java @@ -103,6 +103,9 @@ public boolean contains(final Object o) { /** SQL文の識別子 */ private String sqlId; + /** SQLを実行するスキーマ */ + private String schema; + /** SQL実行の最大リトライ数 */ private int maxRetryCount = 0; @@ -303,6 +306,27 @@ public SqlContext setSqlId(final String sqlId) { return this; } + /** + * {@inheritDoc} + * + * @see jp.co.future.uroborosql.context.SqlContext#getSchema() + */ + @Override + public String getSchema() { + return this.schema; + } + + /** + * {@inheritDoc} + * + * @see jp.co.future.uroborosql.context.SqlContext#setSchema(java.lang.String) + */ + @Override + public SqlContext setSchema(String schema) { + this.schema = schema; + return this; + } + /** * {@inheritDoc} * diff --git a/src/main/java/jp/co/future/uroborosql/converter/EntityResultSetConverter.java b/src/main/java/jp/co/future/uroborosql/converter/EntityResultSetConverter.java index 8a2e5129..c32f184e 100644 --- a/src/main/java/jp/co/future/uroborosql/converter/EntityResultSetConverter.java +++ b/src/main/java/jp/co/future/uroborosql/converter/EntityResultSetConverter.java @@ -45,11 +45,13 @@ public class EntityResultSetConverter implements ResultSetConverter { /** * コンストラクタ * + * @param schema スキーマ * @param entityType エンティティタイプ * @param mapperManager PropertyMapperManager */ @SuppressWarnings({ "unchecked" }) - public EntityResultSetConverter(final Class entityType, final PropertyMapperManager mapperManager) { + public EntityResultSetConverter(String schema, final Class entityType, + final PropertyMapperManager mapperManager) { this.mapperManager = mapperManager; try { this.constructor = (Constructor) entityType.getConstructor(); @@ -57,7 +59,7 @@ public EntityResultSetConverter(final Class entityType, final Prope throw new UroborosqlRuntimeException(e); } - this.mappingColumnMap = Arrays.stream(MappingUtils.getMappingColumns(entityType)) + this.mappingColumnMap = Arrays.stream(MappingUtils.getMappingColumns(schema, entityType)) .collect(Collectors.toMap(c -> CaseFormat.UPPER_SNAKE_CASE.convert(c.getName()), Function.identity())); } diff --git a/src/main/java/jp/co/future/uroborosql/mapping/DefaultEntityHandler.java b/src/main/java/jp/co/future/uroborosql/mapping/DefaultEntityHandler.java index daf0a9fb..a30f21e9 100644 --- a/src/main/java/jp/co/future/uroborosql/mapping/DefaultEntityHandler.java +++ b/src/main/java/jp/co/future/uroborosql/mapping/DefaultEntityHandler.java @@ -10,10 +10,12 @@ import java.sql.SQLException; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Optional; -import java.util.concurrent.ConcurrentHashMap; import java.util.function.Function; import java.util.stream.IntStream; import java.util.stream.Stream; @@ -37,8 +39,15 @@ * @author ota */ public class DefaultEntityHandler implements EntityHandler { + protected static final int CACHE_SIZE = Integer.valueOf(System.getProperty("uroborosql.entity.cache.size", "30")); + protected static final Map CACHE = Collections + .synchronizedMap(new LinkedHashMap(CACHE_SIZE) { - protected static Map, TableMetadata> CONTEXTS = new ConcurrentHashMap<>(); + @Override + protected boolean removeEldestEntry(final Map.Entry eldest) { + return size() > CACHE_SIZE; + } + }); protected PropertyMapperManager propertyMapperManager; protected boolean emptyStringEqualsNull = true; protected SqlConfig sqlConfig = null; @@ -74,60 +83,65 @@ public EntityHandler setEmptyStringEqualsNull(final boolean emptyStringE /** * {@inheritDoc} * - * @see jp.co.future.uroborosql.mapping.EntityHandler#createSelectContext(jp.co.future.uroborosql.SqlAgent, jp.co.future.uroborosql.mapping.TableMetadata, java.lang.Class, boolean) + * @see jp.co.future.uroborosql.mapping.EntityHandler#createSelectContext(SqlAgent, TableMetadata, Class, boolean) */ @Override public SqlContext createSelectContext(final SqlAgent agent, final TableMetadata metadata, final Class entityType, final boolean addCondition) { return agent.contextWith(buildSelectSQL(metadata, entityType, agent.getSqlConfig(), addCondition)) - .setSqlId(createSqlId(metadata, entityType)); + .setSqlId(createSqlId(metadata, entityType)) + .setSchema(metadata.getSchema()); } /** * {@inheritDoc} * - * @see jp.co.future.uroborosql.mapping.EntityHandler#doSelect(jp.co.future.uroborosql.SqlAgent, jp.co.future.uroborosql.context.SqlContext, java.lang.Class) + * @see jp.co.future.uroborosql.mapping.EntityHandler#doSelect(SqlAgent, jp.co.future.uroborosql.context.SqlContext, Class) */ @Override public Stream doSelect(final SqlAgent agent, final SqlContext context, final Class entityType) throws SQLException { - return agent.query(context, new EntityResultSetConverter<>(entityType, propertyMapperManager)); + return agent.query(context, + new EntityResultSetConverter<>(context.getSchema(), entityType, propertyMapperManager)); } /** * {@inheritDoc} * - * @see jp.co.future.uroborosql.mapping.EntityHandler#createInsertContext(jp.co.future.uroborosql.SqlAgent, jp.co.future.uroborosql.mapping.TableMetadata, java.lang.Class) + * @see jp.co.future.uroborosql.mapping.EntityHandler#createInsertContext(SqlAgent, TableMetadata, Class) */ @Override public SqlContext createInsertContext(final SqlAgent agent, final TableMetadata metadata, final Class entityType) { return agent.contextWith(buildInsertSQL(metadata, entityType, agent.getSqlConfig())) - .setSqlId(createSqlId(metadata, entityType)); + .setSqlId(createSqlId(metadata, entityType)) + .setSchema(metadata.getSchema()); } /** * {@inheritDoc} * - * @see jp.co.future.uroborosql.mapping.EntityHandler#createUpdateContext(jp.co.future.uroborosql.SqlAgent, jp.co.future.uroborosql.mapping.TableMetadata, java.lang.Class, boolean) + * @see jp.co.future.uroborosql.mapping.EntityHandler#createUpdateContext(SqlAgent, TableMetadata, Class, boolean) */ @Override public SqlContext createUpdateContext(final SqlAgent agent, final TableMetadata metadata, final Class entityType, final boolean addCondition) { return agent.contextWith(buildUpdateSQL(metadata, entityType, agent.getSqlConfig(), addCondition, true)) - .setSqlId(createSqlId(metadata, entityType)); + .setSqlId(createSqlId(metadata, entityType)) + .setSchema(metadata.getSchema()); } /** * {@inheritDoc} * - * @see jp.co.future.uroborosql.mapping.EntityHandler#createDeleteContext(jp.co.future.uroborosql.SqlAgent, jp.co.future.uroborosql.mapping.TableMetadata, java.lang.Class, boolean) + * @see jp.co.future.uroborosql.mapping.EntityHandler#createDeleteContext(SqlAgent, TableMetadata, Class, boolean) */ @Override public SqlContext createDeleteContext(final SqlAgent agent, final TableMetadata metadata, final Class entityType, final boolean addCondition) { return agent.contextWith(buildDeleteSQL(metadata, entityType, agent.getSqlConfig(), addCondition)) - .setSqlId(createSqlId(metadata, entityType)); + .setSqlId(createSqlId(metadata, entityType)) + .setSchema(metadata.getSchema()); } /** @@ -139,7 +153,8 @@ public SqlContext createDeleteContext(final SqlAgent agent, final TableMetadata public SqlContext createBatchInsertContext(final SqlAgent agent, final TableMetadata metadata, final Class entityType) { return agent.contextWith(buildInsertSQL(metadata, entityType, agent.getSqlConfig(), false)) - .setSqlId(createSqlId(metadata, entityType)); + .setSqlId(createSqlId(metadata, entityType)) + .setSchema(metadata.getSchema()); } /** @@ -150,19 +165,22 @@ public SqlContext createBatchInsertContext(final SqlAgent agent, final TableMeta @Override public SqlContext createBulkInsertContext(final SqlAgent agent, final TableMetadata metadata, final Class entityType) { - return agent.context().setSqlId(createSqlId(metadata, entityType)); + return agent.context() + .setSqlId(createSqlId(metadata, entityType)) + .setSchema(metadata.getSchema()); } /** * {@inheritDoc} * - * @see jp.co.future.uroborosql.mapping.EntityHandler#createBatchUpdateContext(jp.co.future.uroborosql.SqlAgent, jp.co.future.uroborosql.mapping.TableMetadata, java.lang.Class) + * @see jp.co.future.uroborosql.mapping.EntityHandler#createBatchUpdateContext(SqlAgent, TableMetadata, Class) */ @Override public SqlContext createBatchUpdateContext(final SqlAgent agent, final TableMetadata metadata, final Class entityType) { return agent.contextWith(buildUpdateSQL(metadata, entityType, agent.getSqlConfig(), true, false)) - .setSqlId(createSqlId(metadata, entityType)); + .setSqlId(createSqlId(metadata, entityType)) + .setSchema(metadata.getSchema()); } /** @@ -173,13 +191,14 @@ public SqlContext createBatchUpdateContext(final SqlAgent agent, final TableMeta @Override public SqlContext setupSqlBulkInsertContext(final SqlAgent agent, final SqlContext context, final TableMetadata metadata, final Class entityType, final int numberOfRecords) { - return context.setSql(buildBulkInsertSQL(metadata, entityType, agent.getSqlConfig(), numberOfRecords)); + return context.setSql(buildBulkInsertSQL(metadata, entityType, agent.getSqlConfig(), numberOfRecords)) + .setSchema(metadata.getSchema()); } /** * {@inheritDoc} * - * @see jp.co.future.uroborosql.mapping.EntityHandler#setInsertParams(jp.co.future.uroborosql.context.SqlContext, java.lang.Object) + * @see jp.co.future.uroborosql.mapping.EntityHandler#setInsertParams(SqlContext, Object) */ @Override public void setInsertParams(final SqlContext context, final Object entity) { @@ -189,7 +208,7 @@ public void setInsertParams(final SqlContext context, final Object entity) { /** * {@inheritDoc} * - * @see jp.co.future.uroborosql.mapping.EntityHandler#setUpdateParams(jp.co.future.uroborosql.context.SqlContext, java.lang.Object) + * @see jp.co.future.uroborosql.mapping.EntityHandler#setUpdateParams(SqlContext, Object) */ @Override public void setUpdateParams(final SqlContext context, final Object entity) { @@ -199,7 +218,7 @@ public void setUpdateParams(final SqlContext context, final Object entity) { /** * {@inheritDoc} * - * @see jp.co.future.uroborosql.mapping.EntityHandler#setDeleteParams(jp.co.future.uroborosql.context.SqlContext, java.lang.Object) + * @see jp.co.future.uroborosql.mapping.EntityHandler#setDeleteParams(SqlContext, Object) */ @Override public void setDeleteParams(final SqlContext context, final Object entity) { @@ -209,7 +228,7 @@ public void setDeleteParams(final SqlContext context, final Object entity) { /** * {@inheritDoc} * - * @see jp.co.future.uroborosql.mapping.EntityHandler#setBulkInsertParams(jp.co.future.uroborosql.context.SqlContext, java.lang.Object, int) + * @see jp.co.future.uroborosql.mapping.EntityHandler#setBulkInsertParams(SqlContext, Object, int) */ @Override public void setBulkInsertParams(final SqlContext context, final Object entity, final int entityIndex) { @@ -229,12 +248,24 @@ public Class getEntityType() { @Override public TableMetadata getMetadata(final ConnectionManager connectionManager, final Class entityType) throws SQLException { - TableMetadata context = CONTEXTS.get(entityType); - if (context == null) { - context = createMetadata(connectionManager, entityType); - CONTEXTS.put(entityType, context); + String cacheKey = getCacheKey(connectionManager, entityType); + TableMetadata metadata = CACHE.get(cacheKey); + if (metadata == null) { + metadata = createMetadata(connectionManager, entityType); + CACHE.put(cacheKey, metadata); + } + return metadata; + } + + private String getCacheKey(final ConnectionManager connectionManager, final Class entityType) { + try { + Table table = MappingUtils.getTable(entityType); + String schema = StringUtils.isNotEmpty(table.getSchema()) ? table.getSchema() + : Objects.toString(connectionManager.getConnection().getSchema(), ""); + return String.format("%s.%s", schema.toUpperCase(), entityType.getName()); + } catch (SQLException ex) { + return entityType.getName(); } - return context; } /** @@ -393,7 +424,8 @@ protected String buildInsertSQL(final TableMetadata metadata, final Class type, final SqlConfig sqlConfig, final boolean ignoreWhenEmpty) { - Map mappingColumns = MappingUtils.getMappingColumnMap(type, SqlKind.INSERT); + Map mappingColumns = MappingUtils.getMappingColumnMap(metadata.getSchema(), type, + SqlKind.INSERT); StringBuilder sql = buildInsertTargetBlock(metadata, mappingColumns, sqlConfig, ignoreWhenEmpty); sql.append(" VALUES "); sql.append(buildInsertRowBlock(metadata, mappingColumns, sqlConfig, ignoreWhenEmpty, @@ -412,7 +444,8 @@ protected String buildInsertSQL(final TableMetadata metadata, final Class type, final SqlConfig sqlConfig, final int numberOfRecords) { - Map mappingColumns = MappingUtils.getMappingColumnMap(type, SqlKind.INSERT); + Map mappingColumns = MappingUtils.getMappingColumnMap(metadata.getSchema(), type, + SqlKind.INSERT); StringBuilder sql = buildInsertTargetBlock(metadata, mappingColumns, sqlConfig, false); sql.append(" VALUES "); @@ -442,7 +475,8 @@ protected String buildUpdateSQL(final TableMetadata metadata, final Class mappingColumns = MappingUtils.getMappingColumnMap(type, SqlKind.UPDATE); + Map mappingColumns = MappingUtils.getMappingColumnMap(metadata.getSchema(), type, + SqlKind.UPDATE); String versionColumnName = null; OptimisticLockSupplier optimisticLockSupplier = null; @@ -454,7 +488,7 @@ protected String buildUpdateSQL(final TableMetadata metadata, final Class versionColumn = MappingUtils.getVersionMappingColumn(type); + Optional versionColumn = MappingUtils.getVersionMappingColumn(metadata.getSchema(), type); versionColumnName = versionColumn.map(MappingColumn::getCamelName).orElse(null); optimisticLockSupplier = versionColumn .map(vc -> OptimisticLockSupplier.getSupplier(vc.getVersion().supplier())).orElse(null); @@ -788,7 +822,7 @@ protected void setFields(final SqlContext context, final Object entity, final Sq generatedKeyColumns.add(CaseFormat.CAMEL_CASE.convert(keyColumn)); } } - for (MappingColumn column : MappingUtils.getMappingColumns(entity.getClass(), kind)) { + for (MappingColumn column : MappingUtils.getMappingColumns(context.getSchema(), entity.getClass(), kind)) { if (SqlKind.INSERT.equals(kind) && generatedKeyColumns.contains(column.getCamelName())) { continue; } diff --git a/src/main/java/jp/co/future/uroborosql/mapping/MappingUtils.java b/src/main/java/jp/co/future/uroborosql/mapping/MappingUtils.java index b7c324ee..4e7b7748 100644 --- a/src/main/java/jp/co/future/uroborosql/mapping/MappingUtils.java +++ b/src/main/java/jp/co/future/uroborosql/mapping/MappingUtils.java @@ -9,8 +9,10 @@ import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.Arrays; +import java.util.Collections; import java.util.LinkedHashMap; import java.util.Map; +import java.util.Objects; import java.util.Optional; import java.util.function.Function; import java.util.stream.Collectors; @@ -25,6 +27,7 @@ import jp.co.future.uroborosql.mapping.annotations.Transient; import jp.co.future.uroborosql.mapping.annotations.Version; import jp.co.future.uroborosql.utils.CaseFormat; +import jp.co.future.uroborosql.utils.StringUtils; /** * マッピング情報ユーティリティ @@ -32,6 +35,17 @@ * @author ota */ public final class MappingUtils { + private static final int CACHE_SIZE = Integer.valueOf(System.getProperty("uroborosql.entity.cache.size", "30")); + + private static final Map> CACHE = Collections + .synchronizedMap(new LinkedHashMap>(CACHE_SIZE) { + + @Override + protected boolean removeEldestEntry(final Map.Entry> eldest) { + return size() > CACHE_SIZE; + } + }); + private MappingUtils() { } @@ -95,7 +109,7 @@ private static class MappingColumnImpl implements MappingColumn { /** * {@inheritDoc} * - * @see jp.co.future.uroborosql.mapping.MappingColumn#getValue(java.lang.Object) + * @see jp.co.future.uroborosql.mapping.MappingColumn#getValue(Object) */ @Override public Object getValue(final Object entity) { @@ -109,7 +123,7 @@ public Object getValue(final Object entity) { /** * {@inheritDoc} * - * @see jp.co.future.uroborosql.mapping.MappingColumn#setValue(java.lang.Object, java.lang.Object) + * @see jp.co.future.uroborosql.mapping.MappingColumn#setValue(Object, Object) */ @Override public void setValue(final Object entity, final Object value) { @@ -193,7 +207,7 @@ public Transient getTransient() { /** * {@inheritDoc} * - * @see jp.co.future.uroborosql.mapping.MappingColumn#isTransient(jp.co.future.uroborosql.enums.SqlKind) + * @see jp.co.future.uroborosql.mapping.MappingColumn#isTransient(SqlKind) */ @Override public boolean isTransient(final SqlKind sqlKind) { @@ -232,15 +246,6 @@ public Version getVersion() { } } - private static final Map, Map> CACHE = new LinkedHashMap, Map>() { - private final int cacheSize = Integer.valueOf(System.getProperty("uroborosql.entity.cache.size", "30")); - - @Override - protected boolean removeEldestEntry(final Map.Entry, Map> eldest) { - return size() > cacheSize; - } - }; - /** * エンティティ型からテーブル情報の取得 * @@ -269,7 +274,21 @@ public static Table getTable(final Class entityType) { * @exception UroborosqlRuntimeException 指定したキャメルケースカラム名に該当する{@link MappingColumn}が見つからなかった場合 */ public static MappingColumn getMappingColumn(final Class entityType, final String camelColumnName) { - return getMappingColumn(entityType, SqlKind.NONE, camelColumnName); + return getMappingColumn(null, entityType, camelColumnName); + } + + /** + * カラムマッピング情報取得 + * + * @param schema スキーマ + * @param entityType エンティティ型 + * @param camelColumnName 取得するカラムのキャメルケース名 + * @return カラムマッピング情報 + * @exception UroborosqlRuntimeException 指定したキャメルケースカラム名に該当する{@link MappingColumn}が見つからなかった場合 + */ + public static MappingColumn getMappingColumn(String schema, final Class entityType, + final String camelColumnName) { + return getMappingColumn(schema, entityType, SqlKind.NONE, camelColumnName); } /** @@ -283,7 +302,22 @@ public static MappingColumn getMappingColumn(final Class entityType, final St */ public static MappingColumn getMappingColumn(final Class entityType, final SqlKind kind, final String camelColumnName) { - return getMappingColumnMap(entityType, kind).entrySet().stream() + return getMappingColumn(null, entityType, kind, camelColumnName); + } + + /** + * カラムマッピング情報取得 + * + * @param schema スキーマ + * @param entityType エンティティ型 + * @param kind SQL種別 + * @param camelColumnName 取得するカラムのキャメルケース名 + * @return カラムマッピング情報 + * @exception UroborosqlRuntimeException 指定したキャメルケースカラム名に該当する{@link MappingColumn}が見つからなかった場合 + */ + public static MappingColumn getMappingColumn(String schema, final Class entityType, final SqlKind kind, + final String camelColumnName) { + return getMappingColumnMap(schema, entityType, kind).entrySet().stream() .filter(entry -> entry.getKey().equals(camelColumnName)) .map(Map.Entry::getValue) .findFirst() @@ -297,7 +331,18 @@ public static MappingColumn getMappingColumn(final Class entityType, final Sq * @return カラムマッピング情報 */ public static MappingColumn[] getMappingColumns(final Class entityType) { - return getMappingColumns(entityType, SqlKind.NONE); + return getMappingColumns(null, entityType); + } + + /** + * カラムマッピング情報取得 + * + * @param schema スキーマ + * @param entityType エンティティ型 + * @return カラムマッピング情報 + */ + public static MappingColumn[] getMappingColumns(final String schema, final Class entityType) { + return getMappingColumns(schema, entityType, SqlKind.NONE); } /** @@ -308,33 +353,49 @@ public static MappingColumn[] getMappingColumns(final Class entityType) { * @return カラムマッピング情報 */ public static MappingColumn[] getMappingColumns(final Class entityType, final SqlKind kind) { + return getMappingColumns(null, entityType, kind); + } + + /** + * カラムマッピング情報取得 + * + * @param schema スキーマ + * @param entityType エンティティ型 + * @param kind SQL種別 + * @return カラムマッピング情報 + */ + public static MappingColumn[] getMappingColumns(final String schema, final Class entityType, + final SqlKind kind) { if (entityType == null) { return new MappingColumn[0]; } - Map cols; - synchronized (CACHE) { - cols = CACHE.get(entityType); - } + String cacheKey = getCacheKey(schema, entityType); + Map cols = CACHE.get(cacheKey); if (cols != null) { return cols.computeIfAbsent(kind, k -> cols.get(SqlKind.NONE)); - } + } else { + Map> fieldsMap = Stream.of(SqlKind.NONE, SqlKind.INSERT, SqlKind.UPDATE) + .collect(Collectors.toMap(Function.identity(), e -> new LinkedHashMap<>())); - Map> fieldsMap = Stream.of(SqlKind.NONE, SqlKind.INSERT, SqlKind.UPDATE) - .collect(Collectors.toMap(Function.identity(), e -> new LinkedHashMap<>())); + JavaType.ImplementClass implementClass = new JavaType.ImplementClass(entityType); - JavaType.ImplementClass implementClass = new JavaType.ImplementClass(entityType); + walkFields(entityType, implementClass, fieldsMap); - walkFields(entityType, implementClass, fieldsMap); + Map entityCols = fieldsMap.entrySet().stream() + .collect(Collectors.toConcurrentMap(Map.Entry::getKey, + e -> e.getValue().values().toArray(new MappingColumn[e.getValue().size()]))); - final Map entityCols = fieldsMap.entrySet().stream() - .collect(Collectors.toConcurrentMap(Map.Entry::getKey, - e -> e.getValue().values().toArray(new MappingColumn[e.getValue().size()]))); - - synchronized (CACHE) { - CACHE.put(entityType, entityCols); + CACHE.put(cacheKey, entityCols); + return entityCols.computeIfAbsent(kind, k -> entityCols.get(SqlKind.NONE)); } - return entityCols.computeIfAbsent(kind, k -> entityCols.get(SqlKind.NONE)); + } + + private static String getCacheKey(String schema, Class entityType) { + Table table = getTable(entityType); + String currentSchema = StringUtils.isNotEmpty(table.getSchema()) ? table.getSchema() + : Objects.toString(schema, ""); + return String.format("%s.%s", currentSchema.toUpperCase(), entityType.getName()); } /** @@ -345,7 +406,20 @@ public static MappingColumn[] getMappingColumns(final Class entityType, final * @return カラムマッピング情報 */ public static Map getMappingColumnMap(final Class entityType, final SqlKind kind) { - return Arrays.stream(MappingUtils.getMappingColumns(entityType, kind)) + return getMappingColumnMap(null, entityType, kind); + } + + /** + * カラム名(小文字)をキーとしたMapにカラムマッピング情報を取得 + * + * @param schema スキーマ + * @param entityType エンティティ型 + * @param kind SQL種別 + * @return カラムマッピング情報 + */ + public static Map getMappingColumnMap(final String schema, final Class entityType, + final SqlKind kind) { + return Arrays.stream(getMappingColumns(schema, entityType, kind)) .collect(Collectors.toMap(MappingColumn::getCamelName, Function.identity())); } @@ -356,7 +430,18 @@ public static Map getMappingColumnMap(final Class enti * @return カラムマッピング情報 */ public static MappingColumn[] getIdMappingColumns(final Class entityType) { - return Arrays.stream(MappingUtils.getMappingColumns(entityType)) + return getIdMappingColumns(null, entityType); + } + + /** + * IDカラムマッピング情報を返す + * + * @param schema スキーマ + * @param entityType エンティティ型 + * @return カラムマッピング情報 + */ + public static MappingColumn[] getIdMappingColumns(String schema, final Class entityType) { + return Arrays.stream(getMappingColumns(schema, entityType)) .filter(MappingColumn::isId) .toArray(MappingColumn[]::new); } @@ -368,7 +453,18 @@ public static MappingColumn[] getIdMappingColumns(final Class entityType) { * @return カラムマッピング情報 */ public static Optional getVersionMappingColumn(final Class entityType) { - return Arrays.stream(getMappingColumns(entityType)) + return getVersionMappingColumn(null, entityType); + } + + /** + * バージョン情報のカラムマッピング情報を返す + * + * @param schema スキーマ + * @param entityType エンティティ型 + * @return カラムマッピング情報 + */ + public static Optional getVersionMappingColumn(String schema, final Class entityType) { + return Arrays.stream(getMappingColumns(schema, entityType)) .filter(MappingColumn::isVersion) .findFirst(); }