我有一个简单的代码,可以将一些数据保存在数据库中并返回保存的值
public Flux<Person> savePersons(Flux<Person> persons){
Mono<Integer> lastPersonId = getLastPersonId();
AtomicInteger idNum = new AtomicInteger();
lastPersonId.log().subscribe(idNum::set);
System.out.println("id num "+idNum.get()); //Obviously zero since the data is not available yet from lastPersonId Mono
Flux<Person> personsWithId = persons.map(person->{
person.setId(idNum.getAndIncrement());
return person;
});
StringBuilder builder = new StringBuilder();
//Ignore the Sql Injection, was left as such for brevity.
personsWithId.subscribe(person-> builder.append("insert into person VALUES("+person.getId()+",\""+person.getName()+"\""));
return dbClient.execute(builder.toString()).fetch().rowsUpdated();//This fails as well, the builder has insert statements albeit with null Ids. since Id is not set yet.
}
在保存数据之前,我试图检索最后一个ID号并将其用于insert语句。
如何确保将这些Publisher
链接起来。
P.S:我了解SQL注入的风险。我将这些查询形式发送到外部实用程序以清理输入。为了简洁起见,我省略了这段代码。我没有使用批处理,因为mssql-r2dbc似乎不支持批处理。
更新:就某人从Imperatve编码切换而言,该问题更像是一个新手问题,应该忽略。 在一些评论的帮助下,以此类推,在这里写了些代码,我写了一些我能理解的东西。
public Mono<Integer> savePersons(Flux<Person> persons){
AtomicInteger idNum = new AtomicInteger();
StringBuilder builder = new StringBuilder();
return getLastPersonId() //returns a Mono<Integer>
.map(AtomicInteger::new)
.flatMapMany(val->assignIds(val, persons))
.map(person->Sqllib.escapedSql(builder, person))
.last()
.map(val->dbClient.execute(builder.toString()))
.fetch()
.rowsUpdated();
}
private Flux<Person> assignIds(AtomicInteger val, Flux<Person> persons) {
return persons.map(person-> {
person.setId(val.getAndIncrement());
return person;
});
}
答案 0 :(得分:0)
如果您真的不关心SQL注入或让数据库处理PK增量,则可以这样做
String query = "insert into person VALUES (%d,'%s');";
AtomicInteger idNum = new AtomicInteger();
return people
//for every flux element, join on the result of lastPersonId()
.join(lastPersonId(),s-> Flux.never(),s-> Flux.never(), Tuples::of)
//Create your query
.map(t ->
String.format(query,t.getT2() + idNum.incrementAndGet(),
t.getT1().getName()))
//Merge it together
.reduce(String::concat)
//Create execution spec
.map(client::execute)
//Execute spec
.map(DatabaseClient.GenericExecuteSpec::fetch)
//Get the number of updated rows
.flatMap(UpdatedRowsFetchSpec::rowsUpdated);