зеркало из
				https://github.com/iharh/notes.git
				synced 2025-10-30 21:26:09 +02:00 
			
		
		
		
	m
Этот коммит содержится в:
		
							родитель
							
								
									39c253aac4
								
							
						
					
					
						Коммит
						888843626a
					
				| @ -21,6 +21,411 @@ public class JdbcAggregateTemplate implements JdbcAggregateOperations { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| class AggregateChangeExecutor { | 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