我的应用程序在两个不同的数据库(Oracle和Cassandra)上执行写操作(创建/更新/删除)。
即使cassandra集群出现故障,我也希望在Oracle中执行写入操作。
这就是为什么我在Cassandra中的所有写操作都是异步的,并且将在与Oracle不同的线程中执行。
在我的配置文件中,我使用@Lazy Annotation加载我的CassandraClusterFactoryBean。我还用try-catch包围它,所以当它无法连接到集群时,它不会抛出异常。
@Bean
@Lazy
public CassandraClusterFactoryBean cluster() {
CassandraClusterFactoryBean cluster = null;
try{
cluster = new CassandraClusterFactoryBean();
cluster.setContactPoints(CASSANDRA_CONTACTPOINT);
cluster.setPort(CASSANDRA_PORT);
cluster.setUsername(CASSANDRA_USERNAME);
cluster.setPassword(CASSANDRA_PASSWORD);
}catch(Exception e){
logger.info("Unable to contact Cassandra Cluster.");
}
return cluster;
}
我已经创建了一个AsyncCompnent,它可以异步执行Cassandra的所有写操作。
@Component
public class AsyncComponent {
@Autowired
private OneWalletCassandraRepo oneWalletCassandraRepo;
@Autowired
private OneWalletProfileByCustUserIdRepo oneWalletProfileByCustUserIdRepo;
@Autowired
private OneWalletProfileByBillingCanRepo oneWalletProfileByBillingCanRepo;
public static Logger logger = LogManager.getLogger(AsyncComponent.class);
@Async
public Future<Tonewalletprofile> saveCassandraAsync(Tonewalletprofile cassandraProfile) throws InterruptedException {
logger.info("Executing Method asynchronously : " + Thread.currentThread().getName());
Tonewalletprofile savedCassandraProfile=oneWalletCassandraRepo.save(cassandraProfile);
return new AsyncResult<>(savedCassandraProfile);
}
@Async
public Future<Tonewalletprofile> findByPmtAccountRefIdAsync(int pmtAccountRefId) {
logger.info("Executing Method asynchronously : " + Thread.currentThread().getName());
Tonewalletprofile foundCassandraProfile=oneWalletCassandraRepo.findByPmtAccountRefId(pmtAccountRefId);
return new AsyncResult<>(foundCassandraProfile);
}
@Async
public Future<List<TonewalletprofileByCustUserId>> findByCustUserIdAsync(String custUserId) {
logger.info("Executing Method asynchronously : " + Thread.currentThread().getName());
List<TonewalletprofileByCustUserId> foundByCustUserId=oneWalletProfileByCustUserIdRepo.findByCustUserId(custUserId);
return new AsyncResult<>(foundByCustUserId);
}
@Async
public Future<List<TonewalletprofileByBillingCan>> findByBillingAcctNumAsync(String billingAcctNum) {
logger.info("Executing Method asynchronously : " + Thread.currentThread().getName());
List<TonewalletprofileByBillingCan> foundByBillingAcctNum=oneWalletProfileByBillingCanRepo.findByBillingAcctNum(billingAcctNum);
return new AsyncResult<>(foundByBillingAcctNum);
}
@Async
public void deleteCassandraAsync(Tonewalletprofile cassandraProfile) {
logger.info("Executing Method asynchronously : " + Thread.currentThread().getName());
oneWalletCassandraRepo.delete(cassandraProfile);
}
}
然后,我使用@Lazy Annotation在我的Service类中自动连接此组件。
为了Sanity的缘故,我还用@Lazy自动装配了我的Threadpoolexceutor和AsyncExceptionHanlder
@Override
@Lazy
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5);
executor.setMaxPoolSize(10);
executor.setQueueCapacity(25);
executor.setThreadNamePrefix("AsyncThread-");
executor.initialize();
return executor;
}
@Override
@Lazy
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return new CustomAsyncExceptionHandler();
}
当我放下cassandra集群时,当我启动我的应用程序时,它仍然试图寻找接触点并且它失败了。 (点击展开)
我不确定为什么会这样。
基本上我想要的是即使集群发生故障,Oracle DB上的Write操作也应该顺利进行。
答案 0 :(得分:2)
您可以这样做:
禁用spring数据cassandra自动配置:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration;
@SpringBootApplication(exclude = {
CassandraDataAutoConfiguration.class
})
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}
使用@Lazy及其依赖项创建您自己的CassandraTemplate:
import com.datastax.driver.core.Cluster;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.cassandra.config.CassandraTemplateFactoryBean;
import org.springframework.data.cassandra.core.convert.CassandraConverter;
import org.springframework.data.cassandra.core.convert.MappingCassandraConverter;
import org.springframework.data.cassandra.core.mapping.CassandraMappingContext;
/**
* @author fabiojose
*/
@Configuration
public class Config {
@Bean
@Lazy
public Cluster cassandra() {
return
Cluster.builder()
.addContactPoint("localhost")
.withoutMetrics()
.withPort(9042)
.build();
}
@Bean
@Lazy
public CassandraMappingContext mappingContext() {
return new CassandraMappingContext();
}
@Bean
@Lazy
public CassandraConverter converter() {
return new MappingCassandraConverter(mappingContext());
}
@Bean
@Lazy
public CassandraTemplateFactoryBean cassandraTemplate(Cluster cassandra,
CassandraConverter converter) {
CassandraTemplateFactoryBean factory = new CassandraTemplateFactoryBean();
factory.setConverter(converter);
factory.setSession(cassandra.newSession());
return factory;
}
}
答案 1 :(得分:1)
Spring Data Cassandra组件在启动期间初始化的Session
对象上运行。创建初始化的Session
需要与Cassandra主机进行远程交互,因此如果无法访问主机,您会看到失败。
只要通过org.springframework.data.cassandra.SessionFactory
请求Session
,您就可以启动自己的Session
并懒洋洋地初始化它。 CqlTemplate
和CassandraTemplate
都接受SessionFactory
作为构造函数args。