This issue almost driven me crazy! I use spring Redis template as the Redis client portal to manage my cache items in Redis. Recently I try to store some important data in it (expire time is about 60s) , but sometimes ( occasionally) it is deleted after several seconds without any sign! I check my code again and again, no other delete entries. I took many experiments and only a litter of cause was found:
1. when the my web application started, during about the fore five minutes, the phenomenon occurs frequently (probability is about 1/3), but after that time, everything is ok.
2. Retrieving the data immediately after set is always right, even in the error situation. But after several seconds, it disappears. Yes you may think of that there must be some other delete operations exists in my codes. I have check it very carefully, and the answer is no :(.
My spring-redis.xml's content is as following:
<bean id="parentJedisConnFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" abstract="true"
p:timeout="50"
p:database="0">
<constructor-arg index="0" ref="sentinelConfig"/>
<constructor-arg index="1" ref="jedisPoolConfig"/>
</bean>
<bean id="jedisConnFactory" parent="parentJedisConnFactory" />
<bean id="nullSupportedRedisCacheTemplate"
class="org.springframework.data.redis.core.RedisTemplate"
p:connection-factory-ref="jedisConnFactory">
<property name="keySerializer">
<bean class="org.springframework.data.redis.serializer.StringRedisSerializer" />
</property>
<property name="valueSerializer">
<bean class="com.***.KryoRedisSerializer"/>
</property>
</bean>
And below is the Redis client implement:
#Repository("redisCache")
public class RedisCache implements Cache{
#Autowired
#Qualifier("nullSupportedRedisCacheTemplate")
private RedisTemplate<String, Object> nullSupportedRedisCacheTemplate;
private ValueOperations<String, Object> opsValue;
#PostConstruct
public void init(){
opsValue = nullSupportedRedisCacheTemplate.opsForValue();
}
#Override
public <T> void set(String key, T obj) {
set(key, obj, StaticConfiguration.DEFAULT_EXPIRE_TIME);
}
#Override
public <T> void set(String key, T obj, long expireTime) {
opsValue.set(key, obj, expireTime, TimeUnit.MILLISECONDS);
nullSupportedRedisCacheTemplate.expire(key, expireTime, TimeUnit.MILLISECONDS);
}
#SuppressWarnings("unchecked")
#Override
public <T> T get(String key) {
return (T) opsValue.get(key);
}
#Override
public void remove(String key) {
nullSupportedRedisCacheTemplate.delete(key);
}
#Override
public <T> void asynSet(String key, T obj) {
asynSet(key, obj, StaticConfiguration.DEFAULT_EXPIRE_TIME);
}
#Override
public <T> void asynSet(String key, T obj, long expireTime) {
opsValue.set(key, obj, expireTime, TimeUnit.MILLISECONDS);
nullSupportedRedisCacheTemplate.expire(key, expireTime, TimeUnit.MILLISECONDS);
}
#Override
public void asynRemove(String key) {
nullSupportedRedisCacheTemplate.delete(key);
}
#Override
public boolean contain(String key) {
return nullSupportedRedisCacheTemplate.hasKey(key);
}
}
Or you may doubt that the memory is full and maxmemmory-policy delete the key automatically. However according to the ops man's feedback, the peak memory of Redis is about 500M while the max memory of Redis is set as 4G.
Any cause or analysis from you will be highly appreciated :)
Related
I came across an issue, when the jpos channel header string has spaces. I configured that in the channel adaptor configuration as below, but when I start the Q2 server, it seems it trims the header value. As a result of that, I'm not getting any response from the jpos server for certain requests.
<channel-adaptor class="org.jpos.q2.iso.ChannelAdaptor" logger="Q2" name="my-channel">
<channel class="CBCChannel" logger="Q2"
packager="org.jpos.iso.packager.GenericPackager" header="ISOHEADER ">
<property name="packager-config" value="/path/to/PACKAGER/iso87ascii.xml" />
<property name="host" value="xxx.xx.xx.xx"/>
<property name="port" value="yyyy" />
</channel>
<in>channel-send</in>
<out>channel-receive</out>
<property name="timeout" value="300000" />
<property name="keep-alive" value="true" />
<reconnect-delay>10000</reconnect-delay>
</channel-adaptor>
The CBCChannel just extends the RawChannel
public class CBCChannel extends RawChannel {
public CBCChannel() throws ISOException {
}
public CBCChannel(String host, int port, ISOPackager p, byte[] header) {
super(host, port, p, header);
}
public CBCChannel(ISOPackager p, byte[] header) throws IOException {
super(p, header);
}
public CBCChannel(ISOPackager p, byte[] header, ServerSocket serverSocket) throws IOException {
super(p, header, serverSocket);
}
}
Is there any way to configure channel header which contains spaces without neglecting the spaces?
I guess you only need to override setHeader method:
public CBCChannel extends RawChannel {
....
public void setHeader(String header){
super.setHeader(header.getBytes());
}
}
But you would only be doing what BaseChannel does in regard to the header. Are you sure you need a RawChannel based channel?
I am new to rabbitmq. I am using spring-rabbit 1.3.5 Release.
I want to register multiple message listner. How to do that?
I can register a single message listner.
Here is my code:
1)Interface which extends MessageListner interface
public interface MessageQueueManager extends MessageListener{
public String createQueue(String queueName);
public void sendMessage(String message, String destinationQueueName) throws Exception;
}
2) Here is the implementation:
#Service("messageQueueManager")
public class MessageQueueManagerImpl implements MessageQueueManager {
#Autowired
private AmqpAdmin admin;
#Autowired
private AmqpTemplate template;
#Autowired
private ConnectionFactory connectionFactory;
#Autowired
private SimpleMessageListenerContainer container;
#Override
public void onMessage(Message message) {
// Different message can behave differently.
}
#Override
public String createQueue(String queueName) {
// survive a server restart
boolean durable = true;
// keep it even if nobody is using it
boolean autoDelete = false;
boolean exclusive = false;
// create queue
Queue newQueue = new Queue(queueName, durable, exclusive, autoDelete);
queueName = admin.declareQueue(newQueue);
// create binding with exchange
// Producer sends to an Exchange and a Consumer receives from a Queue, the bindings that connect Queues to Exchanges are critical for connecting those producers and consumers via messaging.
/*admin.declareBinding(new Binding(queueName, DestinationType.QUEUE,
"directExchange", queueName, new HashMap<String, Object>()));*/
Binding binding = BindingBuilder.bind(newQueue).to(DirectExchange.DEFAULT).with(queueName);
admin.declareBinding(binding);
// add queue to listener
container.addQueues(newQueue);
// start listener
container.start();
return queueName;
}
#Override
public void sendMessage(String message, String destinationQueueName)
throws Exception {
template.convertAndSend("directExchange", destinationQueueName,
MessageBuilder.withBody(message.getBytes()).build());
}
}
3)Listner register in applicationContext.xml file
<!-- Listener container for setting up concurrent listeners for queues -->
<bean id="simpleMessageListenerContainer"
class="org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer">
<constructor-arg index="0" ref="connectionFactory" />
<property name="missingQueuesFatal" value="false" />
<property name="concurrentConsumers" value="5" />
<property name="autoStartup" value="false" />
<property name="messageListener" ref="messageQueueManager" />
</bean>
So here SimpleMessageListenerContainer class can take only one messageListner. Do I need to declare multiple SimpleMessageListenerContainer instance to register different messageListner?
I want to register this class as a message listner.
#Service("myMessageListener")
public class MessageHandler implements MessageListener {
#Override
public void onMessage(Message message) {
log.info("Received message: " + message);
log.info("Text: " + new String(message.getBody()));
}
}
1)Register your queues:
<rabbit:queue id="spring.queue" auto-delete="false" durable="true" exclusive="false" name="spring.queue"/>
<rabbit:queue id="user.login.notification" auto-delete="false" durable="true" exclusive="false" name="user.login.notification"/>
2)Declare the bindings:
<rabbit:direct-exchange name="directExchange" auto-delete="false">
<rabbit:bindings>
<rabbit:binding queue="spring.queue" key="spring.queue" />
<rabbit:binding queue="user.login.notification" key="user.login.notification MAIYAM" />
</rabbit:bindings>
</rabbit:direct-exchange>
3)Tell the container to call onMessage(Message message) method when the any of the queue publishes the message.
<rabbit:listener-container
connection-factory="connectionFactory" acknowledge="auto" concurrency="10"
requeue-rejected="true">
<rabbit:listener ref="myMessageListener" queues="spring.queue" />
<rabbit:listener ref="messageQueueManager" queues="user.login.notification" />
</rabbit:listener-container>
4)Remove private SimpleMessageListenerContainer container; from MessageQueueManagerImpl class.
Now it should work.
Recently, I have been trying to implement an in-memory database based on HSQLDB for one of our applications which uses Oracle DB in the production. The application uses spring framework. However, I have to implement the data-source bean programmatically as we are using the existing SQL DDL statements(Oracle queries) and so have to programmatically remove constructs like namespaces before they can run on HSQLDB.
I initialize the database using EmbeddedDatabaseBuilder(ResourceLoader).
Now my issue is that I now want to add connection pooling using say c3p0 to this.
Normally I would be using
<bean id="c3p0DataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass" value="HSQLDB driver path" /> (this is just for representation)
<property name="jdbcUrl" value="${xxx.jdbcUrl}" />
<property name="user" value="${xxx.username}" />
<property name="password" value="${xxx.password}" />
<property name="minPoolSize" value="1" />
<property name="maxPoolSize" value="3" />
<property name="maxIdleTime" value="20" />
</bean>
However, I am confused as to how I can define this while using the Spring embedded database.
Disclaimer: I am really new to spring.
Following this link:
import com.mchange.v2.c3p0.ComboPooledDataSource;
public class C3P0Utils {
public static ComboPooledDataSource newDefaultDS() {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setMinPoolSize(1);
dataSource.setMaxPoolSize(1);
dataSource.setMaxIdleTime(20);
return dataSource;
}
}
import java.beans.PropertyVetoException;
import java.sql.Driver;
import org.springframework.jdbc.datasource.embedded.ConnectionProperties;
import org.springframework.jdbc.datasource.embedded.DataSourceFactory;
import com.mchange.v2.c3p0.ComboPooledDataSource;
public class ComboPoolDataSourceFactory implements DataSourceFactory,
ConnectionProperties {
private final ComboPooledDataSource dataSource;
public ComboPoolDataSourceFactory() {
this(C3P0Utils.newDefaultDS());
}
public ComboPoolDataSourceFactory(ComboPooledDataSource dataSource) {
assert dataSource != null;
this.dataSource = dataSource;
}
public ConnectionProperties getConnectionProperties() {
return this;
}
public ComboPooledDataSource getDataSource() {
return dataSource;
}
public void setUsername(String username) {
dataSource.setUser(username);
}
public void setPassword(String password) {
dataSource.setPassword(password);
}
public void setUrl(String url) {
dataSource.setJdbcUrl(url);
}
public void setDriverClass(Class<? extends Driver> driverClass) {
try {
dataSource.setDriverClass(driverClass.getName());
} catch (PropertyVetoException e) {
e.printStackTrace();
}
}
}
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
public class EmbeddedC3P0DatabaseBuilder extends EmbeddedDatabaseBuilder {
public EmbeddedC3P0DatabaseBuilder() {
setDataSourceFactory(new ComboPoolDataSourceFactory());
}
}
And a short usage example:
EmbeddedC3P0DatabaseBuilder builder = new EmbeddedC3P0DatabaseBuilder();
EmbeddedDatabase db = builder
.setType(EmbeddedDatabaseType.H2)
.addScript("setup-tables.sql")
.build();
JdbcTemplate template = new JdbcTemplate(db);
....
db.shutdown();
I wanted to test whether my entities can be persisted to the database or not, so I came across this article:
http://www.codethinked.com/nhibernate-20-sqlite-and-in-memory-databases
My code to initialize the session factory is the same the one in the article:
public class NHibernateInMemoryTestFixtureBase
{
protected static ISessionFactory sessionFactory;
protected static Configuration configuration;
public static void InitalizeSessionFactory(params Assembly[] assemblies)
{
if (sessionFactory != null)
return;
var properties = new Dictionary<string, string>();
properties.Add("connection.driver_class", "NHibernate.Driver.SQLite20Driver");
properties.Add("dialect", "NHibernate.Dialect.SQLiteDialect");
properties.Add("connection.provider", "NHibernate.Connection.DriverConnectionProvider");
properties.Add("connection.connection_string", "Data Source=:memory:;Version=3;New=True;");
properties.Add("connection.release_mode", "on_close");
configuration = new Configuration();
configuration.Properties = properties;
foreach (Assembly assembly in assemblies)
{
configuration = configuration.AddAssembly(assembly);
}
sessionFactory = configuration.BuildSessionFactory();
}
public ISession CreateSession()
{
ISession openSession = sessionFactory.OpenSession();
IDbConnection connection = openSession.Connection;
new SchemaExport(configuration).Execute(false, true, false, true, connection, null);
return openSession;
}
}
And here's my test:
[Test]
public void IWillChangeThisNameLater()
{
InitalizeSessionFactory(typeof(LogRepository).Assembly);
var session = this.CreateSession();
Log log = Log.New("a", "b", "I");
session.Save(log);
session.Flush();
Assert.Greater(log.IDColumn, 0);
}
And the problem is, I removed the "a" property of Log from the log.hbm.xml and session.Save(log) is not throwing an exception or anything, it just works...
This must be obvious and on porpose, but I fail to find out why that is, how can it save it if is not mapped, is that how the in memory database work? how can I test my mapping then?
I mainly did this in-memory test so that I can know right away if a valid entity is failing to persist, of course that would include missing properties on the mapping file.
Any thoughts will be appreciated.
EDIT:
As requested,
the Log entity definition:
public class Log : DomainBase<Log, ILogRepository<Log>>
{
private int logId;
private string tableName;
private string field;
private string userLogin;
protected Log()
{
}
protected Log(string tableName, string field, string userLogin)
{
TableName = tableName;
Field = field;
UserLogin = userLogin;
}
public virtual int LogId { get; set; }
public virtual string TableName { get; set; }
public virtual string Field { get; set; }
public virtual string UserLogin { get; set; }
}
the Log Mapping:
<?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
<class name="DomainProject" table="Log" lazy="true">
<id name="logId" column="ID" type="int">
<generator class="native" />
</id>
<property name="TableName" column="TableName" type="string" />
<property name="Field" column="Field" type="string" />
<property name="UserLogin" column="UserLogin" type="string" />
</class>
</hibernate-mapping>
If a class contains a property that is not mentioned in the mappings, NHibernate will ignore the property.
our project only query data over a legacy database, can we use a stateless session by default when spring framework auto injected session by OSIV situation?
I mean the base class NHibernateRepository's method GetCurrentSession can retrieve a stateless session object.
Does it work that I change _sessionFactory.GetCurrentSession() to _sessionFactory.OpenStatelessSession() ?
public abstract class NHibernateRepository
{
private ISessionFactory _sessionFactory;
public ISessionFactory SessionFactory
{
protected get { return _sessionFactory; }
set { _sessionFactory = value; }
}
protected ISession CurrentSession
{
get { return _sessionFactory.GetCurrentSession(); }
}
......
But my Spring configurations will left as the regular setting:
<!-- Session Factory Configuration -->
<object id="SessionFactory" type="MyProject.Infrastructure.NHibernate.NHibernateLocalSessionFactoryObject, MyProject.Infrastructure">
<property name="DbProvider" ref="MyDbProvider"/>
<property name="MappingAssemblies">
<list>
<value>MyProject.DataAccess.NHibernateMappingLocal</value>
</list>
</property>
Anything should I do for my case? thanks for your help.