/** * Execute the clause and return the generated key cast to the given type. * If no rows were created, null is returned, otherwise the key of the first * row is returned. * * @param <T> * @param type type of key * @return generated key */ public <T> T executeWithKey(Class<T> type) { return executeWithKey(type, null); }
private AbstractSQLInsertClause<?> onDuplicateUpdates(AbstractSQLInsertClause<?> insert, Collection<Path<?>> duplicates) { if (duplicates != null && !duplicates.isEmpty()) { insert.addFlag(QueryFlag.Position.END, " ON DUPLICATE KEY UPDATE "); boolean first = true; for (Path<?> duplicate : duplicates) { insert.addFlag(QueryFlag.Position.END, Expressions.template(Object.class, first ? "{0} = VALUES({0})" : ", {0} = VALUES({0})", duplicate)); first = false; } } return insert; }
protected <T> T executeWithKey(Class<T> type, @Nullable Path<T> path) { ResultSet rs = null; try { rs = executeWithKeys(); if (rs.next()) { return configuration.get(rs, path, 1, type); } else { return null; } } catch (SQLException e) { throw configuration.translate(e); } finally { if (rs != null) { close(rs); } reset(); } }
@Override public List<SQLBindings> getSQL() { if (batches.isEmpty()) { SQLSerializer serializer = createSerializer(); serializer.serializeInsert(metadata, entity, columns, values, subQuery); return ImmutableList.of(createBindings(metadata, serializer)); } else if (batchToBulk) { SQLSerializer serializer = createSerializer(); serializer.serializeInsert(metadata, entity, batches); return ImmutableList.of(createBindings(metadata, serializer)); } else { ImmutableList.Builder<SQLBindings> builder = ImmutableList.builder(); for (SQLInsertBatch batch : batches) { SQLSerializer serializer = createSerializer(); serializer.serializeInsert(metadata, entity, batch.getColumns(), batch.getValues(), batch.getSubQuery()); builder.add(createBindings(metadata, serializer)); } return builder.build(); } }
@Override public long execute() { context = startContext(connection(), metadata,entity); PreparedStatement stmt = null; Collection<PreparedStatement> stmts = null; try { if (batches.isEmpty()) { stmt = createStatement(false); listeners.notifyInsert(entity, metadata, columns, values, subQuery); return rc; } else if (batchToBulk) { stmt = createStatement(false); listeners.notifyInserts(entity, metadata, batches); return rc; } else { stmts = createStatements(false); listeners.notifyInserts(entity, metadata, batches); long rc = executeBatch(stmts); listeners.executed(context); return rc; onException(context,e); throw configuration.translate(queryString, constants, e); } finally { if (stmt != null) { close(stmt);
context = startContext(connection(), metadata, entity); try { PreparedStatement stmt = null; if (batches.isEmpty()) { stmt = createStatement(true); listeners.notifyInsert(entity, metadata, columns, values, subQuery); listeners.executed(context); } else if (batchToBulk) { stmt = createStatement(true); listeners.notifyInserts(entity, metadata, batches); listeners.executed(context); } else { Collection<PreparedStatement> stmts = createStatements(true); if (stmts != null && stmts.size() > 1) { throw new IllegalStateException("executeWithKeys called with batch statement and multiple SQL strings"); onException(context, e); reset(); endContext(context); throw configuration.translate(queryString, constants, e);
SQLSerializer serializer = createSerializer(); serializer.serializeInsert(metadata, entity, batches.get(0).getColumns(), batches .get(0).getValues(), batches.get(0).getSubQuery()); PreparedStatement stmt = prepareStatementAndSetParameters(serializer, withKeys); if (addBatches) { stmt.addBatch(); context.addSQL(createBindings(metadata, serializer)); listeners.rendered(context); serializer = createSerializer(); serializer.serializeInsert(metadata, entity, batch.getColumns(), batch.getValues(), batch.getSubQuery()); context.addSQL(createBindings(metadata, serializer)); listeners.rendered(context); stmt = prepareStatementAndSetParameters(serializer, withKeys); stmts.put(serializer.toString(), stmt); } else { setParameters(stmt, serializer.getConstants(), serializer.getConstantPaths(), metadata.getParams());
/** * MySql专用批量保存实体,如果唯一键已存在则更新。 */ public long insertDuplicateUpdates(Collection<?> beans, Path<?>... duplicatePaths) { // 把相同的SQL合并成批量模式 Map<Collection<Path<?>>, AbstractSQLInsertClause<?>> updatePathsInsertMap = new HashMap<>(); for (Object bean : beans) { Map<Path<?>, Object> valuesMap = DefaultMapper.DEFAULT.createMap(entity, bean); Collection<Path<?>> duplicates = filterUpdatePaths(valuesMap.keySet(), duplicatePaths); AbstractSQLInsertClause<?> insert = updatePathsInsertMap.computeIfAbsent( duplicates, (paths) -> onDuplicateUpdates( new MysqlInsert(connection(), configuration, entity), paths)); valuesMap.forEach((key, value) -> insert.set((Path<Object>) key, value)); insert.addBatch(); } return updatePathsInsertMap.values().stream() .mapToLong(AbstractSQLInsertClause::execute).sum(); }
protected PreparedStatement createStatement(boolean withKeys) throws SQLException { listeners.preRender(context); SQLSerializer serializer = createSerializer(); if (subQueryBuilder != null) { subQuery = subQueryBuilder.select(values.toArray(new Expression[values.size()])).clone(); values.clear(); } if (!batches.isEmpty() && batchToBulk) { serializer.serializeInsert(metadata, entity, batches); } else { serializer.serializeInsert(metadata, entity, columns, values, subQuery); } context.addSQL(createBindings(metadata, serializer)); listeners.rendered(context); return prepareStatementAndSetParameters(serializer, withKeys); }
protected PreparedStatement prepareStatementAndSetParameters(SQLSerializer serializer, boolean withKeys) throws SQLException { listeners.prePrepare(context); queryString = serializer.toString(); constants = serializer.getConstants(); logQuery(logger, queryString, constants); PreparedStatement stmt; if (withKeys) { if (entity.getPrimaryKey() != null) { String[] target = new String[entity.getPrimaryKey().getLocalColumns().size()]; for (int i = 0; i < target.length; i++) { Path<?> path = entity.getPrimaryKey().getLocalColumns().get(i); String column = ColumnMetadata.getName(path); target[i] = column; } stmt = connection().prepareStatement(queryString, target); } else { stmt = connection().prepareStatement(queryString, Statement.RETURN_GENERATED_KEYS); } } else { stmt = connection().prepareStatement(queryString); } setParameters(stmt, serializer.getConstants(), serializer.getConstantPaths(), metadata.getParams()); context.addPreparedStatement(stmt); listeners.prepared(context); return stmt; }
/** * Populate the INSERT clause with the properties of the given bean using * the given Mapper. * * @param obj object to use for population * @param mapper mapper to use * @return the current object */ @SuppressWarnings("rawtypes") @WithBridgeMethods(value = SQLInsertClause.class, castRequired = true) public <T> C populate(T obj, Mapper<T> mapper) { Map<Path<?>, Object> values = mapper.createMap(entity, obj); for (Map.Entry<Path<?>, Object> entry : values.entrySet()) { set((Path) entry.getKey(), entry.getValue()); } return (C) this; }
@Override public String toString() { SQLSerializer serializer = createSerializer(); if (!batches.isEmpty() && batchToBulk) { serializer.serializeInsert(metadata, entity, batches); } else { serializer.serializeInsert(metadata, entity, columns, values, subQuery); } return serializer.toString(); }
protected <T> List<T> executeWithKeys(Class<T> type, @Nullable Path<T> path) { ResultSet rs = null; try { rs = executeWithKeys(); List<T> rv = new ArrayList<T>(); while (rs.next()) { rv.add(configuration.get(rs, path, 1, type)); } return rv; } catch (SQLException e) { throw configuration.translate(e); } finally { if (rs != null) { close(rs); } reset(); } }
/** * Execute the clause and return the generated key with the type of the * given path. If no rows were created, null is returned, otherwise the key * of the first row is returned. * * @param <T> * @param path path for key * @return generated key */ @SuppressWarnings("unchecked") @Nullable public <T> T executeWithKey(Path<T> path) { return executeWithKey((Class<T>) path.getType(), path); }
/** * MySql专用保存实体并填充实体主键,如果唯一键已存在则更新。 */ public <KEY> KEY insertDuplicateUpdateGetKey(Object bean, Path<?>... duplicatePaths) { Path<KEY> keyPath = QueryUtils.getSinglePrimaryKey((RelationalPathBase) entity); Map<Path<?>, Object> valuesMap = DefaultMapper.DEFAULT.createMap(entity, bean); valuesMap.forEach((key, value) -> set((Path<Object>) key, value)); Collection<Path<?>> duplicates = filterUpdatePaths(valuesMap.keySet(), duplicatePaths); KEY value = onDuplicateUpdates(this, duplicates) .executeWithKey(keyPath); QueryUtils.setBeanProperty(bean, keyPath.getMetadata().getName(), value); return value; }