I'm getting this exception when adding Transactional to Spring mongo code.
Caused by: com.mongodb.MongoClientException: Transactions are not supported by the MongoDB cluster to which this client is connected
This is my code: #Configuration
#EnableMongoRepositories(basePackages = { "com.repository" })
public class MongoConfig extends AbstractMongoClientConfiguration {
#Value("${spring.data.mongodb.uri}")
private String connection;
#Value("${spring.data.mongodb.database}")
private String database;
#Autowired
MongoProperties mongoProperties;
#Bean
MongoTransactionManager transactionManager(MongoDatabaseFactory dbFactory) {
return new MongoTransactionManager(dbFactory);
}
#Override
protected String getDatabaseName() {
return "hendrix";
}
#Override
public MongoClient mongoClient() {
final ConnectionString connectionString = new ConnectionString(connection);
final MongoClientSettings mongoClientSettings = MongoClientSettings.builder()
.applyConnectionString(connectionString)
.build();
return MongoClients.create(mongoClientSettings);
}
}
How do I add replicas to a barebones Mongo setup I have access to? If the cluster is on AWS what setting would I have to change?
Related
I'm working on a project whereby my spring service needs to connect to multiple Mongo DB's.
In order to achieve the ability to connect to multiple mongo db's I've created a MongoDatabaseFactory config class to represent each connection. I'am however getting random mongo SSL timeout errors. Normally when I would connect to a single mongo db I would create the client like so:
#Value("${spring.data.mongodb.host}")
private String connectionString;
#Bean
public MongoClient mongoClient() {
CodecRegistry pojoCodecRegistry = fromProviders(PojoCodecProvider.builder().automatic(true).build());
CodecRegistry codecRegistry = fromRegistries(MongoClientSettings.getDefaultCodecRegistry(), pojoCodecRegistry);
return MongoClients.create(MongoClientSettings.builder()
.applyConnectionString(new ConnectionString(connectionString))
.uuidRepresentation(UuidRepresentation.STANDARD)
.codecRegistry(codecRegistry)
.build());
}
#Bean
public MongoClientSettings mongoClientSettings() {
final MongoClientSettings clientSettings = MongoClientSettings.builder()
.retryWrites(true)
.applyToConnectionPoolSettings((ConnectionPoolSettings.Builder builder) -> {
builder.maxSize(300) //connections count
.minSize(100)
.maxConnectionLifeTime(300, TimeUnit.MILLISECONDS)
.maintenanceFrequency(5000, TimeUnit.MILLISECONDS)
.maxConnectionIdleTime(200, TimeUnit.MILLISECONDS)
.maxWaitTime(150, TimeUnit.MILLISECONDS);
})
.applyToSocketSettings(builder -> {
builder.connectTimeout(2000, TimeUnit.MILLISECONDS)
.readTimeout(5500, TimeUnit.MILLISECONDS);
})
.applicationName("TestApplication")
.retryWrites(true)
.build();
return clientSettings;
}
#Bean
public MongoCustomConversions mongoCustomConversions() {
return new MongoCustomConversions(Arrays.asList(
new BigDecimalDecimal128Converter(),
new Decimal128BigDecimalConverter()
));
}
#WritingConverter
private static class BigDecimalDecimal128Converter implements Converter<BigDecimal, Decimal128> {
#Override
public Decimal128 convert(#NonNull BigDecimal source) {
return new Decimal128(source);
}
}
#ReadingConverter
private static class Decimal128BigDecimalConverter implements Converter<Decimal128, BigDecimal> {
#Override
public BigDecimal convert(#NonNull Decimal128 source) {
return source.bigDecimalValue();
}
}
And when connecting to multiple mongo db's here's how I do it:
#Configuration
public class UserProfileInformationMongoConfig {
#Autowired
private Environment env;
#Bean
public MongoDatabaseFactory userProfileInformationFactory() {
return new SimpleMongoClientDatabaseFactory(new ConnectionString(env.getProperty("spring.data.mongo.userprofileinformationdb.uri")));
}
#Bean
public MongoTemplate userProfileInformationMongoTemplate() {
return new MongoTemplate(userProfileInformationFactory());
}
}
So, my question again is how do I set my mongo client options like in the first code example when using MongoDatabaseFactory.
Many thanks
Except the maintenanceFrequency configuration, the rest can be provided in the connection string e.g.
mongodb://db1.example.net:27017,db2.example.net:2500/?replicaSet=test&maxPoolSize=300&minPoolSize=100&maxLifeTimeMS=300&maxIdleTimeMS=200&waitQueueTimeoutMS=150&connectTimeoutMS=2000&socketTimeoutMS=5500
I'm configuring mongoDB in my spring boot application like this:
#Configuration
#SpringBootApplication
public class ConfigDbApp extends SpringBootServletInitializer {
#Value("${myapp.mongodb.uri}")
private String mongoDbUri;
[...]
#Bean
public MongoClient mongoClient() {
MongoClientSettings mongoClientSettings = MongoClientSettings.builder()
.applyConnectionString(new ConnectionString(mongoDbUri.trim()))
.build();
return MongoClients.create(mongoClientSettings);
}
[...]
}
The database uri is:
myapp.mongodb.uri=mongodb://localhost:27017/myApp?sslInvalidHostNameAllowed=true&streamType=netty&ssl=false
The connection is fine but instead of connecting to "myApp" database it connect to "test" database (the default).
If I use the spring property:
spring.data.mongodb.uri=mongodb://localhost:27017/myApp?sslInvalidHostNameAllowed=true&streamType=netty&ssl=false
it works well, but I don't want to use it because I can have diferent apps in the same server reading the same configuration file.
Any suggestion is appreciated, thanks.
This worked with me : override the database name
#Configuration
public class MongoConfig extends AbstractMongoClientConfiguration {
#Value("${spring.data.mongodb.uri}")
private String uri;
#Value("${spring.data.mongodb.database}")
private String database;
#Override
protected String getDatabaseName() {
return database;
}
#Bean
#Override
public MongoClient mongoClient() {
final ConnectionString connectionString = new ConnectionString(uri);
final MongoClientSettings.Builder mongoClientSettings = MongoClientSettings.builder().applyConnectionString(connectionString)
.applyToConnectionPoolSettings(builder -> builder.applySettings(connectionPoolSettings()));
return MongoClients.create(mongoClientSettings.build());
}
private ConnectionPoolSettings connectionPoolSettings() {
return ConnectionPoolSettings.builder()
.maxSize(50)
.maxWaitTime(20, TimeUnit.SECONDS)
.maxConnectionIdleTime(20, TimeUnit.SECONDS)
.maxConnectionLifeTime(60, TimeUnit.SECONDS).build();
}
}
We are using Redis connection with JedisConnectionFactory and using CrudRepository for querying data
#Component
#Configuration
public class RedisConfig {
#Bean
public RedisTemplate<String, Object> redisTemplate(RedisProperties redisProperties) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(jedisConnectionFactory(redisProperties));
return template;
}
private JedisConnectionFactory jedisConnectionFactory(RedisProperties redisProperties) {
RedisStandaloneConfiguration redisStandaloneConfiguration =
new RedisStandaloneConfiguration(redisProperties.getHost(), redisProperties.getPort());
return new JedisConnectionFactory(redisStandaloneConfiguration);
}
}
My Redis Object
#RedisHash("Resource")
public class ResourceDto {
#Id private String resourceId;
#Indexed private Date lastUpdatedDate;
private String resource;
}
I want to fetch all unique ResourceDto by resourceId with Latest lastUpdatedDate.
I have tried with few things
Using findByDistinctResourceId() but it gives error
Is there any alternative?
Dont know how to query for this kind of result using RedisTemplate
public static void main(String[] args) {
ApplicationContext ctx =
SpringApplication.run(Application.class, args);
RedisTemplate redisTemplate=ctx.getBean(RedisTemplate.class);
RedisScript redisScript=new RedisScript() {
#Override
public String getSha1() {
return null;
}
#Override
public Class getResultType() {
return ResourceDto.class;
}
#Override
public String getScriptAsString() {
return "SORT Resource BY nosort";
}
};
redisTemplate.execute(redisScript,null,null);
}
RedisTemplate is configured properly but dont know how to query for all unique ResourceDto by resourceId with Latest lastUpdatedDate
I have initialized the Spring Boot app with Lettuce(io.lettuce.core.api) configuration like this
#Configuration
class RedisConfiguration {
#Value("${spring.redis.host}")
private String redisHostname;
#Value("${spring.redis.port}")
private int redisPort;
private StatefulRedisConnection<String, String> redisConnection;
private static RedisClient redisClient;
#Bean
public RedisCommands connectionFactory() {
RedisURI redisURI = RedisURI.create(redisHostname,redisPort);
redisClient = RedisClient.create(redisURI);
redisConnection = redisClient.connect();
RedisCommands<String, String> syncCommands =
redisConnection.sync();
return syncCommands;
}
}
I want to call redisClient.shutdown(); when application shuts down or exits. What is the right place to terminate the redis connection ?
You have two options:
Using #PreDestroy:
#PreDestroy
public StatefulRedisConnection<String, String> redisConnection() {
redisConnection.close();
redisClient.close();
}
Via #Bean methods
Make sure to expose RedisClient and StatefulRedisConnection as beans. Command interfaces (RedisCommands) do not expose a close() method.
#Configuration
class RedisConfiguration {
#Value("${spring.redis.host}")
private String redisHostname;
#Value("${spring.redis.port}")
private int redisPort;
#Bean(destroyMethod = "close")
public StatefulRedisConnection<String, String> redisClient() {
RedisURI redisURI = RedisURI.create(redisHostname,redisPort);
return RedisClient.create(redisURI);
redisConnection = redisClient.connect();
}
#Bean(destroyMethod = "close")
public StatefulRedisConnection<String, String> redisConnection(RedisClient client) {
return client.connect();
}
#Bean
public RedisCommands redisCommands(StatefulRedisConnection<String, String> connection) {
return connection.sync();
}
}
The first method is shorter while the #Bean approach lets you interact with intermediate objects in your application.
I am trying to use both Cassandra and MySQL in my project. Some data will be saved into Cassandra and some to Mysql. I had been using mySql for last 1 yr in the same project and now since I'm Expanding it, I want to add Cassandra DB also.
My Cassandra Configuration file is as follows.
#Configuration
#PropertySource(value = {"classpath:META-INF/application.properties"})
#EnableCassandraRepositories(basePackages = {"com.example.repository"})
public class CassandraConfig {
#Autowired
private Environment environment;
private static final Logger LOGGER = LoggerFactory.getLogger(CassandraConfig.class);
#Bean
public CassandraClusterFactoryBean cluster() {
CassandraClusterFactoryBean cluster = new CassandraClusterFactoryBean();
cluster.setContactPoints(environment.getProperty("spring.cassandra.contactpoints"));
cluster.setPort(Integer.parseInt(environment.getProperty("spring.cassandra.port")));
return cluster;
}
#Bean
public CassandraMappingContext mappingContext() {
return new BasicCassandraMappingContext();
}
#Bean
public CassandraConverter converter() {
return new MappingCassandraConverter(mappingContext());
}
#Bean
public CassandraSessionFactoryBean session() throws Exception {
CassandraSessionFactoryBean session = new CassandraSessionFactoryBean();
session.setCluster(cluster().getObject());
session.setKeyspaceName(environment.getProperty("spring.cassandra.keyspace"));
session.setConverter(converter());
session.setSchemaAction(SchemaAction.NONE);
return session;
}
#Bean
public CassandraOperations cassandraTemplate() throws Exception {
return new CassandraTemplate(session().getObject());
}
}
My Repository is
public interface NewRepository extends CassandraRepository<ID>{
}
Now I'm trying to save an entity to it using the reposiroty
repo.save(entity);
where repo is the object for NewRepository.
But it shows InvalidDataAccessApiUsageException: unknown Type.
Where am i wrong.
Thank You in advance.