我最近开始尝试使用RxJava,并且遇到了Netflix工程师的演示文稿,该工程师建议将我们的业务API移至Observable API,例如:
public interface VideoService {
Observable<VideoBasicInfo> createVideoBasicInfo(VideoBasicInfo videoBasic);
Observable<VideoBasicInfo> getVideoBasicInfo(Integer videoId);
Observable<VideoRating> getVideoRating(Integer videoId);
}
但是,我没有找到任何解释如何在此服务中管理事务性的地方。首先,我使用@Transactional
@Service
@Transactional
public class VideoServiceImpl implements VideoService{
@Autowired
private VideoBasicInfoRepository basicInfoRepo;
@Autowired
private VideoRatingRepository ratingRepo;
public Observable<VideoBasicInfo> createVideoBasicInfo(VideoBasicInfo videoBasic){
return Observable.create( s -> {
s.onNext(basicInfoRepo.save(videBasic));
});
}
我们想要的是在Object.create
lambda(s -> { // This code }
)中执行所有代码都发生在事务中。 HOWEVER ,实际发生的是:
createVideoBasicInfo()
的调用以事务方式执行,返回冷可观察对象。save()
作为原子事务执行。显然,由于Spring代理适用于serviceImpl方法,因此它是有意义的。我已经想到了如何做我真正期望的事情,例如开始程序化交易:
return Observable.create( s -> {
VideoBasicInfo savedBasic = transactionTemplate.execute( status -> {
VideoBasicInfo basicInfo = basicInfoRepo.save(videoBasicInfo);
return basicInfo;
});
s.onNext(savedBasic);
});
这是在使用反应式API时管理事务的推荐方法吗?
答案 0 :(得分:7)
Spring Data JpaRepository方法签名已标记为@Transactional,因此如果您只使用一个,那么您不需要做任何特别的事情:
public interface PersonRepository extends JpaRepository<Person, Integer> {
}
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = {RepositoryConfiguration.class})
public class PersonRepositoryTest {
private PersonRepository personRepository;
@Autowired
public void setPersonRepository(PersonRepository PersonRepository) {
this.personRepository = PersonRepository;
}
@Test
public void testReactiveSavePerson() {
Person person = new Person("Jane", "Doe");
assertNull(person.getId()); //null before save
//save person
Observable.create(s -> {
s.onNext(personRepository.save(person));
}).subscribe();
//fetch from DB
Person fetchedPerson = personRepository.findOne(person.getId());
//should not be null
assertNotNull(fetchedPerson);
//should equal
assertEquals(person.getId(), fetchedPerson.getId());
assertEquals(person.getFirstName(), fetchedPerson.getFirstName());
}
}
如果您需要将多个存储库合并到一个事务中,您可以使用类似下面的类:
@Component()
public class ObservableTxFactory {
public final <T> Observable<T> create(Observable.OnSubscribe<T> f) {
return new ObservableTx<>(this, f);
}
@Transactional
public void call(Observable.OnSubscribe onSubscribe, Subscriber subscriber) {
onSubscribe.call(subscriber);
}
private static class ObservableTx<T> extends Observable<T> {
public ObservableTx(ObservableTxFactory observableTxFactory, OnSubscribe<T> f) {
super(new OnSubscribeDecorator<>(observableTxFactory, f));
}
}
private static class OnSubscribeDecorator<T> implements Observable.OnSubscribe<T> {
private final ObservableTxFactory observableTxFactory;
private final Observable.OnSubscribe<T> onSubscribe;
OnSubscribeDecorator(final ObservableTxFactory observableTxFactory, final Observable.OnSubscribe<T> s) {
this.onSubscribe = s;
this.observableTxFactory = observableTxFactory;
}
@Override
public void call(Subscriber<? super T> subscriber) {
observableTxFactory.call(onSubscribe, subscriber);
}
}
}
还需要定义工厂bean:
@Bean
ObservableTxFactory observableTxFactory() {
return new ObservableTxFactory();
}
服务:
@Service
public class PersonService {
@Autowired
PersonRepository personRepository;
@Autowired
ObservableTxFactory observableTxFactory;
public Observable<Person> createPerson(String firstName, String lastName) {
return observableTxFactory.create(s -> {
Person p = new Person(firstName, lastName);
s.onNext(personRepository.save(p));
});
}
}
测试:
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = {RepositoryConfiguration.class})
public class PersonServiceTest {
@Autowired
PersonRepository personRepository;
@Autowired
ObservableTxFactory observableTxFactory;
@Test
public void testPersonService() {
final PersonService service = new PersonService();
service.personRepository = personRepository;
service.observableTxFactory = observableTxFactory;
final Observable<Person> personObservable = service.createPerson("John", "Doe");
personObservable.subscribe();
//fetch from DB
final Person fetchedPerson = StreamSupport.stream(personRepository.findAll().spliterator(), false)
.filter(p -> p.getFirstName().equals("John") && p.getLastName().equals("Doe"))
.findFirst()
.get();
//should not be null
assertNotNull(fetchedPerson);
}
}
答案 1 :(得分:0)
我想借鉴John Scattergood出色的答案。我的典型用法是使用Observable.fromCallable()
,所以我一直在寻找一种方法,而不是实现Observable.OnSubscribe
所以我调整了他的技术,以便您可以通过传递Callable
来使用它
工厂类:
@Component
public class ObservableTxFactory {
public final <T> Observable.OnSubscribe<T> createFromCallable(Callable<? extends T> resultFactory) {
return new OnSubscribeDecorator<>(this, resultFactory);
}
@SuppressWarnings("unchecked")
@Transactional
public <T> void call(Callable<? extends T> resultFactory, Subscriber subscriber) {
final SingleDelayedProducer<T> singleDelayedProducer = new SingleDelayedProducer<>(subscriber);
subscriber.setProducer(singleDelayedProducer);
try {
singleDelayedProducer.setValue(resultFactory.call());
} catch (Throwable t) {
Exceptions.throwOrReport(t, subscriber);
}
}
private static class OnSubscribeDecorator<T> implements Observable.OnSubscribe<T> {
private final ObservableTxFactory observableTxFactory;
private final Callable<? extends T> resultFactory;
OnSubscribeDecorator(final ObservableTxFactory observableTxFactory, Callable<? extends T> resultFactory) {
this.resultFactory = resultFactory;
this.observableTxFactory = observableTxFactory;
}
@Override
public void call(Subscriber<? super T> subscriber) {
observableTxFactory.call(resultFactory, subscriber);
}
}
}
原始代码:
Observable.fromCallable(() -> fooRepository.findOne(fooID));
新守则:
Observable.create(observableTxFactory.createFromCallable(() -> fooRepository.findOne(fooID)));
确保您添加@Transactional
的方法为public
,否则Spring AOP将无法提供建议