情况 我正在使用带有Scala和RxJava2的Spring Boot来编写一组服务。服务修改了RDBMS中的数据,因此我创建了一个事务处理方法,该方法采用一个块,然后执行它,然后调用以下之一:doOnError,doOnNext,doOnTerminate。这是这样的样子:
object JdbcTransaction {
def transaction[T](executeInTransaction: => Flowable[T])(implicit
con:Connection):Flowable[T] = {
con.setAutoCommit(false)
executeInTransaction
.doOnNext(next => {
try {
con.commit()
} catch {
case e:Exception => print(e)
} finally {
con.setAutoCommit(true)
con.close()
}
}).doOnError(error => {
try {
con.rollback()
} catch {
case e:Exception => print(e)
} finally {
con.setAutoCommit(true)
con.close()
}
}).doOnTerminate(() => {
try {
if (!con.getAutoCommit) {
con.setAutoCommit(true)
}
if (!con.isClosed) {
con.close()
}
} catch {
case e:Exception => print(e)
}
})
}
}
令人惊讶的是,在某些情况下该块会执行,但不会调用doOnError,doOnNext或doOnTerminate。这是下面的代码中返回 return error(ConflictException())时的这种情况的示例:
def handle(create: CreateCredential):Flowable[CreatedCredential] = {
// if not valid crete request
if (!isValidCreateRequest(create)) {
return error(BadRequestException())
}
implicit val con:Connection = dataSource.getConnection
//noinspection ConvertExpressionToSAM
credentialRepository.getCredentialByUsername(create.username)
.flatMap[CreatedCredential](new Function[Optional[Credential], Publisher[CreatedCredential]]() {
override def apply(t: Optional[Credential]): Publisher[CreatedCredential] = {
transaction[CreatedCredential] ({
// The credential exists
if (t.isPresent) {
// inform the requester that there's a conflict.
return error(ConflictException())
}
import com.shapestone.authentication.v2.PasswordString._
val date = new Date()
val hashedPassword = create.password.encrypt(authenticationServiceData.getPasswordHashIterations)
val confirmationCode = createConfirmationCode(create.username)
val credential:Credential = toCredential(create, hashedPassword, date)
val confirmation:Confirmation = toConfirmation(credential.credentialId, confirmationCode, date)
val credentialEvent:Event = toEvent(create, credential, date)
val confirmationEvent:Event = toEvent(create, confirmation, date)
val newCredentialEvent:Flowable[Event] = eventRepository.save(credentialEvent)
val newConfirmationEvent:Flowable[Event] = eventRepository.save(confirmationEvent)
val newCredential:Flowable[Credential] = credentialRepository.save(credential)
val newConfirmation:Flowable[Confirmation] = confirmationRepository.save(confirmation)
val publishedValue:Flowable[CreatedCredential] = zip[Event, Event, Credential, Confirmation, CreatedCredential](
newCredentialEvent, newConfirmationEvent, newCredential, newConfirmation,
(cre:Event, cne:Event, cr: Credential, cf: Confirmation) => {
CreatedCredential(cr, cf)
}).flatMap[CreatedCredential](new Function[CreatedCredential, Publisher[CreatedCredential]]() {
override def apply(t: CreatedCredential): Publisher[CreatedCredential] = {
eventPublisher.publish(t).flatMap[CreatedCredential](new Function[String, Publisher[CreatedCredential]]() {
override def apply(s: String): Publisher[CreatedCredential] = {
if (!Option(s).exists(_.trim.nonEmpty)) {
error(BadRequestException("Failed to send notification."))
} else {
just[CreatedCredential](t)
}
}
})
}
})
publishedValue
})(con)
}
})
}
(注意:我也尝试过使用Single。但是,我想我会先询问RxJava 2代码。)