зеркало из
				https://github.com/iharh/notes.git
				synced 2025-10-31 05:36:08 +02:00 
			
		
		
		
	m
Этот коммит содержится в:
		
							родитель
							
								
									39c253aac4
								
							
						
					
					
						Коммит
						888843626a
					
				| @ -21,6 +21,411 @@ public class JdbcAggregateTemplate implements JdbcAggregateOperations { | ||||
| } | ||||
| 
 | ||||
| class AggregateChangeExecutor { | ||||
| 
 | ||||
| 	private final JdbcConverter converter; | ||||
| 	private final DataAccessStrategy accessStrategy; | ||||
| 
 | ||||
|   ... | ||||
| 	<T> List<T> executeSave(AggregateChange<T> aggregateChange) { | ||||
| 
 | ||||
| 		JdbcAggregateChangeExecutionContext executionContext = new JdbcAggregateChangeExecutionContext(converter, | ||||
| 				accessStrategy); | ||||
| 
 | ||||
| 		aggregateChange.forEachAction(action -> execute(action, executionContext)); | ||||
| 
 | ||||
| 		return executionContext.populateIdsIfNecessary(); | ||||
| 	} | ||||
|   ... | ||||
| 
 | ||||
| 	private void execute(DbAction<?> action, JdbcAggregateChangeExecutionContext executionContext) { | ||||
| 
 | ||||
| 		try { | ||||
| 			if (action instanceof DbAction.InsertRoot<?> insertRoot) { | ||||
| 				executionContext.executeInsertRoot(insertRoot); | ||||
| 			} else if (action instanceof DbAction.BatchInsertRoot<?> batchInsertRoot) { | ||||
| 				executionContext.executeBatchInsertRoot(batchInsertRoot); | ||||
| 			} else if (action instanceof DbAction.Insert<?> insert) { | ||||
| 				executionContext.executeInsert(insert); | ||||
| 			} else if (action instanceof DbAction.BatchInsert<?> batchInsert) { | ||||
| 				executionContext.executeBatchInsert(batchInsert); | ||||
| 			} else if (action instanceof DbAction.UpdateRoot<?> updateRoot) { | ||||
| 				executionContext.executeUpdateRoot(updateRoot); | ||||
| 			} else if (action instanceof DbAction.Delete<?> delete) { | ||||
| 				executionContext.executeDelete(delete); | ||||
| 			} else if (action instanceof DbAction.BatchDelete<?> batchDelete) { | ||||
| 				executionContext.executeBatchDelete(batchDelete); | ||||
| 			} else if (action instanceof DbAction.DeleteAll<?> deleteAll) { | ||||
| 				executionContext.executeDeleteAll(deleteAll); | ||||
| 			} else if (action instanceof DbAction.DeleteRoot<?> deleteRoot) { | ||||
| 				executionContext.executeDeleteRoot(deleteRoot); | ||||
| 			} else if (action instanceof DbAction.BatchDeleteRoot<?> batchDeleteRoot) { | ||||
| 				executionContext.executeBatchDeleteRoot(batchDeleteRoot); | ||||
| 			} else if (action instanceof DbAction.DeleteAllRoot<?> deleteAllRoot) { | ||||
| 				executionContext.executeDeleteAllRoot(deleteAllRoot); | ||||
| 			} else if (action instanceof DbAction.AcquireLockRoot<?> acquireLockRoot) { | ||||
| 				executionContext.executeAcquireLock(acquireLockRoot); | ||||
| 			} else if (action instanceof DbAction.AcquireLockAllRoot<?> acquireLockAllRoot) { | ||||
| 				executionContext.executeAcquireLockAllRoot(acquireLockAllRoot); | ||||
| 			} else { | ||||
| 				throw new RuntimeException("unexpected action"); | ||||
| 			} | ||||
| 		} catch (Exception e) { | ||||
| 
 | ||||
| 			if (e instanceof OptimisticLockingFailureException) { | ||||
| 				throw e; | ||||
| 			} | ||||
| 			throw new DbActionExecutionException(action, e); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| @SuppressWarnings("rawtypes") | ||||
| class JdbcAggregateChangeExecutionContext { | ||||
| 
 | ||||
| 	private final RelationalMappingContext context; | ||||
| 	private final JdbcConverter converter; | ||||
| 	private final DataAccessStrategy accessStrategy; | ||||
| 
 | ||||
| 	private final Map<DbAction<?>, DbActionExecutionResult> results = new LinkedHashMap<>(); | ||||
| 
 | ||||
|   ... | ||||
| 	<T> void executeInsertRoot(DbAction.InsertRoot<T> insert) { | ||||
| 
 | ||||
| 		Object id = accessStrategy.insert(insert.getEntity(), insert.getEntityType(), Identifier.empty(), | ||||
| 				insert.getIdValueSource()); | ||||
| 		add(new DbActionExecutionResult(insert, id)); | ||||
| 	} | ||||
|   ... | ||||
| } | ||||
| 
 | ||||
| package org.springframework.data.jdbc.core.convert; | ||||
| 
 | ||||
| 
 | ||||
| public interface DataAccessStrategy extends ReadingDataAccessStrategy, RelationResolver { | ||||
|   ... | ||||
| 
 | ||||
|   ... | ||||
| } | ||||
| 
 | ||||
| core/convert/DefaultDataAccessStrategy.java | ||||
| core/convert/DelegatingDataAccessStrategy.java | ||||
| core/convert/CascadingDataAccessStrategy.java | ||||
| 
 | ||||
| 
 | ||||
| public class DefaultDataAccessStrategy implements DataAccessStrategy { | ||||
| 
 | ||||
| 	private final SqlGeneratorSource sqlGeneratorSource; | ||||
| 	private final RelationalMappingContext context; | ||||
| 	private final JdbcConverter converter; | ||||
| 	private final NamedParameterJdbcOperations operations; | ||||
| 	private final SqlParametersFactory sqlParametersFactory; | ||||
| 	private final InsertStrategyFactory insertStrategyFactory; | ||||
|   ... | ||||
| 	@Override | ||||
| 	public <T> Object insert(T instance, Class<T> domainType, Identifier identifier, IdValueSource idValueSource) { | ||||
| 
 | ||||
| 		SqlIdentifierParameterSource parameterSource = sqlParametersFactory.forInsert(instance, domainType, identifier, | ||||
| 				idValueSource); | ||||
| 
 | ||||
| 		String insertSql = sql(domainType).getInsert(parameterSource.getIdentifiers()); | ||||
| 
 | ||||
| 		return insertStrategyFactory.insertStrategy(idValueSource, getIdColumn(domainType)).execute(insertSql, | ||||
| 				parameterSource); | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| 	private SqlGenerator sql(Class<?> domainType) { | ||||
| 		return sqlGeneratorSource.getSqlGenerator(domainType); | ||||
| 	} | ||||
|   ... | ||||
| } | ||||
| 
 | ||||
| core/convert/DataAccessStrategyFactory.java | ||||
| 
 | ||||
| 
 | ||||
| public class SqlGeneratorSource { | ||||
| 
 | ||||
| 	private final Map<Class<?>, SqlGenerator> CACHE = new ConcurrentReferenceHashMap<>(); | ||||
| 	private final RelationalMappingContext context; | ||||
| 	private final JdbcConverter converter; | ||||
| 	private final Dialect dialect; | ||||
| 
 | ||||
| 	public Dialect getDialect() { | ||||
| 		return dialect; | ||||
| 	} | ||||
| 
 | ||||
| 	SqlGenerator getSqlGenerator(Class<?> domainType) { | ||||
| 
 | ||||
| 		return CACHE.computeIfAbsent(domainType, | ||||
| 				t -> new SqlGenerator(context, converter, context.getRequiredPersistentEntity(t), dialect)); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| class SqlGenerator { | ||||
| 
 | ||||
| 	static final SqlIdentifier VERSION_SQL_PARAMETER = SqlIdentifier.unquoted("___oldOptimisticLockingVersion"); | ||||
| 	static final SqlIdentifier ID_SQL_PARAMETER = SqlIdentifier.unquoted("id"); | ||||
| 	static final SqlIdentifier IDS_SQL_PARAMETER = SqlIdentifier.unquoted("ids"); | ||||
| 	static final SqlIdentifier ROOT_ID_PARAMETER = SqlIdentifier.unquoted("rootId"); | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Length of an aggregate path that is one longer then the root path. | ||||
| 	 */ | ||||
| 	private static final int FIRST_NON_ROOT_LENTH = 2; | ||||
| 
 | ||||
| 	private final RelationalPersistentEntity<?> entity; | ||||
| 	private final RelationalMappingContext mappingContext; | ||||
| 	private final RenderContext renderContext; | ||||
| 
 | ||||
| 	private final SqlContext sqlContext; | ||||
| 	private final SqlRenderer sqlRenderer; | ||||
| 	private final Columns columns; | ||||
| 
 | ||||
| 	private final Lazy<String> findOneSql = Lazy.of(this::createFindOneSql); | ||||
| 	private final Lazy<String> findAllSql = Lazy.of(this::createFindAllSql); | ||||
| 	private final Lazy<String> findAllInListSql = Lazy.of(this::createFindAllInListSql); | ||||
| 
 | ||||
| 	private final Lazy<String> existsSql = Lazy.of(this::createExistsSql); | ||||
| 	private final Lazy<String> countSql = Lazy.of(this::createCountSql); | ||||
| 
 | ||||
| 	private final Lazy<String> updateSql = Lazy.of(this::createUpdateSql); | ||||
| 	private final Lazy<String> updateWithVersionSql = Lazy.of(this::createUpdateWithVersionSql); | ||||
| 
 | ||||
| 	private final Lazy<String> deleteByIdSql = Lazy.of(this::createDeleteByIdSql); | ||||
| 	private final Lazy<String> deleteByIdInSql = Lazy.of(this::createDeleteByIdInSql); | ||||
| 	private final Lazy<String> deleteByIdAndVersionSql = Lazy.of(this::createDeleteByIdAndVersionSql); | ||||
| 	private final Lazy<String> deleteByListSql = Lazy.of(this::createDeleteByListSql); | ||||
| 	private final QueryMapper queryMapper; | ||||
| 	private final Dialect dialect; | ||||
|   ... | ||||
| 	String getInsert(Set<SqlIdentifier> additionalColumns) { | ||||
| 		return createInsertSql(additionalColumns); | ||||
| 	} | ||||
| 
 | ||||
| 	private String createInsertSql(Set<SqlIdentifier> additionalColumns) { | ||||
| 
 | ||||
| 		Table table = getTable(); | ||||
| 
 | ||||
| 		Set<SqlIdentifier> columnNamesForInsert = new TreeSet<>(Comparator.comparing(SqlIdentifier::getReference)); | ||||
| 		columnNamesForInsert.addAll(columns.getInsertableColumns()); | ||||
| 		columnNamesForInsert.addAll(additionalColumns); | ||||
| 
 | ||||
| 		InsertBuilder.InsertIntoColumnsAndValuesWithBuild insert = Insert.builder().into(table); | ||||
| 
 | ||||
| 		for (SqlIdentifier cn : columnNamesForInsert) { | ||||
| 			insert = insert.column(table.column(cn)); | ||||
| 		} | ||||
| 
 | ||||
| 		if (columnNamesForInsert.isEmpty()) { | ||||
| 			return render(insert.build()); | ||||
| 		} | ||||
| 
 | ||||
| 		InsertBuilder.InsertValuesWithBuild insertWithValues = null; | ||||
| 		for (SqlIdentifier cn : columnNamesForInsert) { | ||||
| 			insertWithValues = (insertWithValues == null ? insert : insertWithValues).values(getBindMarker(cn)); | ||||
| 		} | ||||
| 
 | ||||
| 		return render(insertWithValues.build()); | ||||
| 	} | ||||
| 
 | ||||
| 	private String render(Insert insert) { | ||||
| 		return this.sqlRenderer.render(insert); | ||||
| 	} | ||||
|   ... | ||||
| } | ||||
| 
 | ||||
| ************************************************************************* | ||||
| 
 | ||||
| package org.springframework.data.relational.core.sql.render; | ||||
| 
 | ||||
| 
 | ||||
| public class SqlRenderer implements Renderer { | ||||
| 
 | ||||
| 	private final RenderContext context; | ||||
|   ... | ||||
| 	@Override | ||||
| 	public String render(Insert insert) { | ||||
| 		InsertStatementVisitor visitor = new InsertStatementVisitor(context); | ||||
| 		insert.visit(visitor); | ||||
| 		return visitor.getRenderedPart().toString(); | ||||
| 	} | ||||
|   ... | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| class InsertStatementVisitor extends DelegatingVisitor implements PartRenderer { | ||||
| 
 | ||||
| 	private final StringBuilder builder = new StringBuilder(); | ||||
| 	private final StringBuilder into = new StringBuilder(); | ||||
| 	private final StringBuilder columns = new StringBuilder(); | ||||
| 	private final StringBuilder values = new StringBuilder(); | ||||
| 
 | ||||
| 	private final IntoClauseVisitor intoClauseVisitor; | ||||
| 	private final ColumnVisitor columnVisitor; | ||||
| 	private final ValuesVisitor valuesVisitor; | ||||
| 	private final RenderContext renderContext; | ||||
|   ... | ||||
| 
 | ||||
|   // !!! from here !!! | ||||
| 	@Override | ||||
| 	public Delegation doEnter(Visitable segment) { | ||||
| 
 | ||||
| 		if (segment instanceof Into) { | ||||
| 			return Delegation.delegateTo(this.intoClauseVisitor); | ||||
| 		} | ||||
| 
 | ||||
| 		if (segment instanceof Column) { | ||||
| 			return Delegation.delegateTo(this.columnVisitor); | ||||
| 		} | ||||
| 
 | ||||
| 		if (segment instanceof Values) { | ||||
| 			return Delegation.delegateTo(this.valuesVisitor); | ||||
| 		} | ||||
| 
 | ||||
| 		return Delegation.retain(); | ||||
| 	} | ||||
| 
 | ||||
| 	@Override | ||||
| 	public Delegation doLeave(Visitable segment) { | ||||
| 
 | ||||
| 		if (segment instanceof Insert) { | ||||
| 
 | ||||
| 			builder.append("INSERT"); | ||||
| 
 | ||||
| 			builder.append(" INTO ").append(into); | ||||
| 
 | ||||
| 			addInsertColumnsIfPresent(); | ||||
| 
 | ||||
| 			addInsertValuesIfPresentElseDefault(); | ||||
| 
 | ||||
| 			return Delegation.leave(); | ||||
| 		} | ||||
| 
 | ||||
| 		return Delegation.retain(); | ||||
| 	} | ||||
|   ... | ||||
| 
 | ||||
| 	@Override | ||||
| 	public CharSequence getRenderedPart() { | ||||
| 		return builder;                                         // just a StringBuilder | ||||
| 	} | ||||
|   ... | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| abstract class DelegatingVisitor implements Visitor { | ||||
|   ... | ||||
| 
 | ||||
| 	@Nullable | ||||
| 	public abstract Delegation doEnter(Visitable segment); | ||||
| 
 | ||||
| 	@Override | ||||
| 	public final void enter(Visitable segment) { | ||||
| 
 | ||||
| 		if (delegation.isEmpty()) { | ||||
| 
 | ||||
| 			Delegation visitor = doEnter(segment); | ||||
| 			Assert.notNull(visitor, | ||||
| 					() -> String.format("Visitor must not be null Caused by %s.doEnter(…)", getClass().getName())); | ||||
| 			Assert.state(!visitor.isLeave(), | ||||
| 					() -> String.format("Delegation indicates leave. Caused by %s.doEnter(…)", getClass().getName())); | ||||
| 
 | ||||
| 			if (visitor.isDelegate()) { | ||||
| 				delegation.push(visitor.getDelegate()); | ||||
| 				visitor.getDelegate().enter(segment); | ||||
| 			} | ||||
| 		} else { | ||||
| 			delegation.peek().enter(segment); | ||||
| 		} | ||||
| 	} | ||||
|   ... | ||||
| 
 | ||||
| 	public abstract Delegation doLeave(Visitable segment); | ||||
| 
 | ||||
| 	public final void leave(Visitable segment) { | ||||
| 		doLeave0(segment); | ||||
| 	} | ||||
| 
 | ||||
| 	private Delegation doLeave0(Visitable segment) { | ||||
| 
 | ||||
| 		if (delegation.isEmpty()) { | ||||
| 			return doLeave(segment); | ||||
| 		} else { | ||||
| 
 | ||||
| 			DelegatingVisitor visitor = delegation.peek(); | ||||
| 			while (visitor != null) { | ||||
| 
 | ||||
| 				Delegation result = visitor.doLeave0(segment); | ||||
| 				Assert.notNull(visitor, | ||||
| 						() -> String.format("Visitor must not be null Caused by %s.doLeave(…)", getClass().getName())); | ||||
| 
 | ||||
| 				if (visitor == this) { | ||||
| 					if (result.isLeave()) { | ||||
| 						return delegation.isEmpty() ? Delegation.leave() : Delegation.retain(); | ||||
| 					} | ||||
| 					return Delegation.retain(); | ||||
| 				} | ||||
| 
 | ||||
| 				if (result.isRetain()) { | ||||
| 					return result; | ||||
| 				} | ||||
| 
 | ||||
| 				if (result.isLeave()) { | ||||
| 
 | ||||
| 					if (!delegation.isEmpty()) { | ||||
| 						delegation.pop(); | ||||
| 					} | ||||
| 
 | ||||
| 					if (!delegation.isEmpty()) { | ||||
| 						visitor = delegation.peek(); | ||||
| 					} else { | ||||
| 						visitor = this; | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		return Delegation.leave(); | ||||
| 	} | ||||
|   ... | ||||
| } | ||||
| 
 | ||||
| ---------------------------------------------------------------------------------------- | ||||
| package org.springframework.data.relational.core.sql; | ||||
| 
 | ||||
| public interface Insert extends Segment, Visitable { | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Creates a new {@link InsertBuilder}. | ||||
| 	 * | ||||
| 	 * @return a new {@link InsertBuilder}. | ||||
| 	 */ | ||||
| 	static InsertBuilder builder() { | ||||
| 		return new DefaultInsertBuilder(); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| class DefaultInsert implements Insert { | ||||
| 
 | ||||
| 	private final Into into; | ||||
| 	private final List<Column> columns; | ||||
| 	private final Values values; | ||||
|   ... | ||||
| 
 | ||||
| 	@Override | ||||
| 	public void visit(Visitor visitor) { | ||||
| 
 | ||||
| 		Assert.notNull(visitor, "Visitor must not be null"); | ||||
| 
 | ||||
| 		visitor.enter(this); | ||||
| 
 | ||||
| 		into.visit(visitor); | ||||
| 		columns.forEach(it -> it.visit(visitor)); | ||||
| 		values.visit(visitor); | ||||
| 
 | ||||
| 		visitor.leave(this); | ||||
| 	} | ||||
|   ... | ||||
| } | ||||
|  | ||||
		Загрузка…
	
	
			
			x
			
			
		
	
		Ссылка в новой задаче
	
	Block a user
	 Ihar Hancharenka
						Ihar Hancharenka