Spring boot CacheEvict and CachePut is not updating the Cacheable content - spring

Spring boot #CacheEvict and #CachePut is not updating list of the all #Cacheable content.
Not updating list of all cache
While updating - Not refreshing the global cache || #Cacheable(cacheNames="employeeDetails")
While creating - Not refreshing the global cache || #Cacheable(cacheNames="employeeDetails")
While deleting - Not refreshing the global cache || #Cacheable(cacheNames="employeeDetails")
While fetching - Not refreshing the global cache // Single record || #Cacheable(cacheNames="employeeDetails")
Steps I have taken -
I know, if I do -
// #Scheduled(fixedDelay = 10 * 60 * 1000) // Running after 10 minutes get the fresh Cache
// #Scheduled(cron = "0 0 2 * * ?") // Running Everyday at 2 AM public get the fresh Cache
Also, I don't want to delete all the cache, while - updating or deleting data from database,
#CacheEvict(value ="employeeDetails", allEntries = true)
What I want when we are - Deleting cache or updating cache, It should update the #Cacheable content as well.
Programming Language - Spring boot - 2.7.0 Database - Mongodb
Code -
ServiceImp.java
#Service
public class EmployeeServiceImp implements EmployeeService {
private static final Logger logger = LoggerFactory.getLogger(EmployeeServiceImp.class);
#Autowired
private EmployeeRepository employeeRepository;
#Override
public void createEmployee(Employee employee) throws ConstraintViolationException, EmployeeCollectionException {
// TODO Auto-generated method stub
Optional<Employee> employeeOptional = employeeRepository.findByEmployee(employee.getEmpName());
if(employeeOptional.isPresent()) {
throw new EmployeeCollectionException(EmployeeCollectionException.EmployeeAlreadyExists());
} else {
employee.setCreateAt(new Date(System.currentTimeMillis()));
employeeRepository.save(employee);
}
}
#Override
// #Scheduled(fixedDelay = 10 * 60 * 1000) // Running after 10 minutes get the fresh Cache
// #Scheduled(cron = "0 0 2 * * ?") // Running Everyday at 2 AM public get the fresh Cache
#Cacheable(cacheNames="employeeDetails")
public List<Employee> getAllEmployeeDetails() {
// TODO Auto-generated method stub
logger.info("Calling all the list of Employees !!!");
List<Employee> employee = employeeRepository.findAll();
if(employee.size() > 0) {
logger.info("Get all the Employee data from MongoDB:");
return employee;
} else {
return new ArrayList<Employee>();
}
}
#Override
#Cacheable(cacheNames="employeeDetails", key="#id")
public Employee getEmployeeRecord(String id) throws EmployeeCollectionException {
Optional<Employee> employeeOptional = employeeRepository.findById(id);
logger.info("Customer invoked id - "+id);
if(!employeeOptional.isPresent()) {
throw new EmployeeCollectionException(EmployeeCollectionException.NotFoundException(id));
} else {
return employeeOptional.get();
}
}
#Override
#CacheEvict(value ="employeeDetails", key="#id") // allEntries = true //First Delete the existing cache then update so that next time first fetch will be from DB and then it will store in cache and fetch from the cache.
#CachePut(cacheNames="employeeDetails", key="#id", unless="#result==null")
public void updateEmployee(String id, Employee emp) throws EmployeeCollectionException {
Optional<Employee> employeeOptional = employeeRepository.findById(id);
logger.info("Customer update id - "+id);
Optional<Employee> employeeOptionalByEmpName = employeeRepository.findByEmployee(emp.getEmpName());
if(employeeOptional.isPresent()) {
if(employeeOptionalByEmpName.isPresent()) { // If same Employee is present in the Database
throw new EmployeeCollectionException(EmployeeCollectionException.EmployeeAlreadyExists());
}
Employee employeeToUpdate = employeeOptional.get();
employeeToUpdate.setEmpName(emp.getEmpName());
employeeToUpdate.setCompanyName(emp.getCompanyName());
employeeToUpdate.setExp(emp.getExp());
employeeToUpdate.setEmpAddress(emp.getEmpAddress());
employeeToUpdate.setUpdatedAt(new Date(System.currentTimeMillis()));
employeeRepository.save(employeeToUpdate);
} else {
throw new EmployeeCollectionException(EmployeeCollectionException.NotFoundException(id));
}
}
#Override
#CacheEvict(cacheNames="employeeDetails", key="#id")
public void deleteEmployeeById(String id) throws EmployeeCollectionException {
Optional<Employee> employeeOptional = employeeRepository.findById(id);
logger.info("Customer deleted id - "+id);
if(!employeeOptional.isPresent()) {
throw new EmployeeCollectionException(EmployeeCollectionException.NotFoundException(id));
} else {
employeeRepository.deleteById(id);
}
}
}
CacheConfiguration -
#Configuration
public class CacheConfig {
private static final Logger log = LoggerFactory.getLogger(CacheConfig.class);
#Bean
CacheManagerCustomizer<ConcurrentMapCacheManager> customizer(){
return new ConcurrentCustomizer();
}
class ConcurrentCustomizer implements CacheManagerCustomizer<ConcurrentMapCacheManager>{
#Override
public void customize(ConcurrentMapCacheManager cacheManager) {
cacheManager.setAllowNullValues(false);
cacheManager.setStoreByValue(true); // We added serializable in the Dao class
log.info("customizer invoked!!");
}
}
}
Please help me on the same. I am new to this concept.

Related

Always getting a empty object in unitTest JPA/Hibernate

I am currently trying if my functions work with my current database but I keep getting an empty object back. My Test is the following:
#Test
public void findJobOfferByIdReturnsCorrectJobOffer() {
User user = UserBuilder.anUser().build();
JobOffer firstJobOffer = JobOfferBuilder.aJobOffer()
.withId(108L)
.withCompany(user)
.build();
JobOffer secondJoboffer = JobOfferBuilder.aJobOffer()
.withAmountPerSession(55)
.withCompany(user)
.withId(208L)
.withJobDescription("Software Tester in PHP")
.build();
userDao.saveUser(user);
jobOfferDao.saveJobOffer(firstJobOffer);
jobOfferDao.saveJobOffer(secondJoboffer);
entityManager.clear();
entityManager.flush();
Optional<JobOffer> retrievedJobOffer = jobOfferDao.findJobOfferById(firstJobOffer.getId());
assertTrue(retrievedJobOffer.isPresent());
JobOffer jobOffer = retrievedJobOffer.get();
assertEquals(jobOffer.getId(), firstJobOffer.getId());
assertNotEquals(jobOffer.getId(), secondJoboffer.getId());
}
The Test uses the following DAOImpl repository:
#Repository
public class JobOfferDaoImpl implements JobOfferDao {
#PersistenceContext
private EntityManager entityManager;
private static final Logger LOGGER = LogManager.getLogger(UserDaoImpl.class);
#Override
public Optional<JobOffer> findJobOfferById(Long id) {
TypedQuery<JobOffer> jobOfferQuery = entityManager.createNamedQuery("findJobOfferById", JobOffer.class);
jobOfferQuery.setParameter("jobOfferId", id);
try {
return Optional.of(jobOfferQuery.getSingleResult());
} catch (NoResultException e) {
return Optional.empty();
}
}
#Transactional
public void saveJobOffer(JobOffer jobOffer) {
if (findJobOfferById(jobOffer.getId()).isEmpty()) {
entityManager.merge(jobOffer);
LOGGER.info(String.format("Joboffer with id %d is inserted in the database", jobOffer.getId()));
} else {
throw new JobOfferNotFoundException();
}
}
}
And the Query to select the correct jobOffer for "findJobOfferById" is the following:
#NamedQuery(name = "findJobOfferById", query = "SELECT j from JobOffer j WHERE j.id = :jobOfferId"),
When trying to debug I get the following:
In the Test you shouldn't give your own ID. Change it with:
.withId(null)
And in the DAO you have to Persist the jobOffer and actually add it. With merge you are modifying it.
entityManager.persist(jobOffer);

Read data from an Android Room database in a background Service, no exceptions but no data

I am attempting to read data from an Android Room database in a background Service. There are no exceptions but no data is returned.
I wrote a function to select all rows from a table in the DAO. Calling that function from a background service succeeds, but it returns no data.
My "Contact" class holds contact information (names, phone numbers, emails) and defines the database schema. The database holds rows of contacts, with names, phone numbers, an emails as columns.
The function that returns the LiveData in the DAO is:
#Query("SELECT * FROM contacts_table")
LiveData<List<Contact>> getAll();
where "contacts_table" is the database table holding contact information.
I called getAll as follows:
AppDatabase db = AppDatabase.getDatabase(messageSenderContext.getApplicationContext());
mContactDAO = db.contactDAO();
mAllContacts = mContactDAO.getAll();
where mContactDao is a ContactDAO (The Database Access Object for my Contact class), and mAllContacts is a LiveData>. These are private fields of the class calling getAll().
db.contactDAO() returns an object, as does mContactDAO.getAll(). But attempting to unpack the List from mAllContacts using mAllContacts.getValue() returns null.
This turned out to be a misuse of LiveData. That requires an Observer to actually get the data.
In your ROOM
#Database(entities={Contact.class}, version = 1, exportSchema = false)
public abstract class AppDatabase extends RoomDatabase {
public static final String DATABASE_NAME = "AppDatabase.db";
private static volatile AppDatabase INSTANCE;
private static final int NUMBER_OF_THREADS = 4;
public static final ExecutorService EXECUTOR_SERVICE = Executors.newFixedThreadPool(NUMBER_OF_THREADS);
public abstract ContactDAO contactDAO();
public static AppDatabase getDatabase(final Context context) {
if (INSTANCE == null) {
synchronized (AppDatabase.class) {
if (INSTANCE == null) {
INSTANCE = Room.databaseBuilder(context.getApplicationContext(),
AppDatabase.class, DATABASE_NAME)
.build();
}
}
}
return INSTANCE;
}
}
In your DAO
#Dao
public interface ContactDAO{
#Query("SELECT * FROM contacts_table")
LiveData<List<Contact>> getAll();
}
In your repository:
public class AppRepository {
private ContactDAO mContactDAO;
//constructor
public AppRepository(Application application) {
AppDatabase db = AppDatabase.getDatabase(application);
mContactDAO= db.contactDAO();
}
public LiveData<List<Contact>> getAllContacts(){
LiveData<List<Contact>> contactsList = null;
Future<LiveData<List<Contact>>> futureList = AppDatabase.EXECUTOR_SERVICE.submit(new Callable(){
#Override
public LiveData<List<Contact>> call() {
return contactDAO.getAll();
}
});
try {
contactsList = futureList.get();
} catch (ExecutionException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
return contactsList ;
}
}
In your ViewModel
public class ContactsViewModel extends AndroidViewModel {
private AppRepository appRepository;
private LiveData<List<Contact>> contactsList;
public ContactsViewModel(#NonNull Application application) {
super(application);
appRepository = new AppRepository(application);
}
public LiveData<List<Contacts>> list() {
return appRepository.getAllContacts();
}
}
In your activity (inside of onCreated put)
ContactsViewModel contactsViewModel = new ViewModelProvider(this).get(ContactsViewModel.class);
contactsViewModel.list().observe(getViewLifecycleOwner(), new Observer<List<Contact>>() {
#Override
public void onChanged(List<Contact> contactsList) {
//the contact list will be observed and will return data if there are changes.
//use for example to feed the adapter of a recyclerview
//below an example just to view the contacts data
for(Contact conctact : contactsList){
Log.d("TestApp>>>", "Id: + contact.getId);
Log.d("TestApp>>>", "Name: + contact.getName);
}
});

Caffeine cache refresh / reload cache manually or on demand

I have implemented caffeine cache in my application. I am caching data from few static tables. But i want to know if i can refresh / clear / reload cache manually or on demand using a REST API or any other way.
Can any one please suggest a way to implement such a requirement.
I want something like :-
an endpoint url like :- http://localhost:8080/refreshCache
this will trigger some method internally and clear the cache or reload new values in cache manually.
Below is the cache configuration:
#Configuration
public class CacheConfig{
private com.github.benmanes.caffeine.cache.Cache<Object, Object> cache;
#Bean
Caffeine<Object,Object> cacheBuilder(){
return Caffeine.newBuilder()
.initialCapacity(300)
.maximumSize(50000)
.expireAfterAccess(1, TimeUnit.DAYS)
.removalListener(new CacheRemovalListener())
.recordStats();
}
class CacheRemovalListener implements RemovalListener<Object, Object> {
#Override
public void onRemoval(Object key, Object value, RemovalCause cause) {
System.out.format("Removal listener called with key [%s], cause[%s], evicted [%s] %n",
key , cause.toString(), cause.wasEvicted());
}
}
}
You can use Spring's CacheManager to create CaffeineCache instances and then you can perform CRUD operations on any cache using CacheManager.
See Below code.
Bean Configuration:
public class CacheBeansConfig {
#Bean
public CacheManager cacheManager() {
// create multiple instances of cache
CaffeineCacheManager cacheManager = new CaffeineCacheManager("UserCache","InventoryCache");
cacheManager.setCaffeine(caffeineCacheBuilder());
return cacheManager;
}
private Caffeine<Object, Object> caffeineCacheBuilder() {
return Caffeine.newBuilder()
.initialCapacity(<initial capacity>)
.maximumSize(<max size>)
.expireAfterAccess(<expire after hrs>, TimeUnit.HOURS)
.recordStats();
}
This will initialize your CacheManager with two Caffeeine Cache instances.
Use below Rest Controller Class to access these class.
#RestController
#RequestMapping(path = "/v1/admin/cache")
public class ACSCacheAdminController {
#Autowired
private CacheManager cacheManager;
/**
* call this to invalidate all cache instances
*/
#DeleteMapping(
path = "/",
produces = {"application/json"})
public void invalidateAll() {
Collection<String> cacheNames = cacheManager.getCacheNames();
cacheNames.forEach(this::getCacheAndClear);
}
/**
* call this to invalidate a given cache name
*/
#DeleteMapping(
path = "/{cacheName}",
produces = {"application/json"})
public void invalidateCache(#PathVariable("cacheName") final String cacheName) {
getCacheAndClear(cacheName);
}
/**
* Use this to refresh a cache instance
*/
#PostMapping(
path = "/{cacheName}",
produces = {"application/json"})
public void invalidateCache(#PathVariable("cacheName") final String cacheName) {
getCacheAndClear(cacheName);
Cache cache = cacheManager.getCache(cacheName);
// your logic to put in above cache instance
// use cache.put(key,value)
}
/**
* call this to invalidate cache entry by given cache name and cache key
*/
#DeleteMapping(
path = "/{cacheName}/{key}/",
produces = {"application/json"})
public void invalidateCacheKey(
#PathVariable("cacheName") final String cacheName, #PathVariable("key") Object key) {
final Cache cache = cacheManager.getCache(cacheName);
if (cache == null) {
throw new IllegalArgumentException("invalid cache name for key invalidation: " + cacheName);
}
cache.evict(key);
}
#GetMapping(
path = "/{cacheName}/{key}",
produces = {"application/json"})
public ResponseEntity<Object> getByCacheNameAndKey(
#PathVariable("cacheName") final String cacheName, #PathVariable("key") final int key) {
final Cache cache = cacheManager.getCache(cacheName);
if (cache == null) {
throw new IllegalArgumentException("invalid cache name: " + cacheName);
}
return ResponseEntity.ok().body(cache.get(key));
}
private void getCacheAndClear(final String cacheName) {
final Cache cache = cacheManager.getCache(cacheName);
if (cache == null) {
throw new IllegalArgumentException("invalid cache name: " + cacheName);
}
cache.clear();
}
Just change the code as per your need :)

camelContext attribute discriminator for tenant resolver , using jpa multitenant and camel routeId

i ask you how can use camelContext to get the name of route fired by an event, more in details, how can I use any kind of discriminator attribute x in camelContext for predicate decision (if x =1 then .. else ..)
For example:
I have this kind of route:
//this route use the forst database
from("direct:csvprocessor1")
.routeId("tenant1")
.from("file:src/main/resources/data/1?move=OUT&moveFailed=REFUSED")
.unmarshal(csv)
.to("bean:myCsvHandler?method=doHandleCsvData")
.setBody(constant("OK VB"))
.setHeader(Exchange.HTTP_RESPONSE_CODE, constant(200))
.setHeader(Exchange.CONTENT_TYPE, constant("text/html"));
and this other route:
//this route use tenant2, the second database
from("direct:csvprocessor1")
.routeId("tenant2")
.from("file:src/main/resources/data/2?move=OUT&moveFailed=REFUSED")
.unmarshal(csv)
.to("bean:myCsvHandler?method=doHandleCsvData")
.setBody(constant("OK 2"))
.setHeader(Exchange.HTTP_RESPONSE_CODE, constant(200))
.setHeader(Exchange.CONTENT_TYPE, constant("text/html"));
when i pick up file in 1 folder the first route named "tenant1" starts, the same happen when pick up file in 2, the second route tenant2 starts.It reads csv content and the content must be write using jpa on the right tenantX (database)
I have to retrieve routeid name in another class but this class instanced before the camel Context start so i can't inject context (because this class "BatchCurrentTenantIdentifierResolverImpl " belong to Spring database initializator). I try to add method "of" to set camelContext but i get tenant1 only, also when route 2 starts, so can't switch from tenant to another tenant (tenant is database, i have two database):
#Component
public class BatchTenantContext {
private static final Logger log = LoggerFactory.getLogger(BatchTenantContext.class);
// don't Inject, use method Of because injecton was null
CamelContext cctx;
public BatchTenantContext(){getInstance();}
private final static BatchTenantContext instance = new BatchTenantContext();
public static BatchTenantContext getInstance(){
return instance;
}
public synchronized String get() {
if (cctx != null){
Route val = cctx.getRoute("tenant1");
if (val == null){
val = cctx.getRoute("tenant2");
if (val == null){
return "";
}
else {
return "tenant_2";
}
}
else return "tenant_1";
}
return "";
}
public synchronized void of(CamelContext ctx){
cctx = ctx;
}
public CamelContext getCamelContext()
{
return cctx;
}
}
//multitenant approach, switch from one database to another
//based on BatchTenantContext resolution..
public class BatchCurrentTenantIdentifierResolverImpl implements CurrentTenantIdentifierResolver {
static final Logger log = LoggerFactory.getLogger(BatchCurrentTenantIdentifierResolverImpl.class);
#Override
public String resolveCurrentTenantIdentifier() {
String val = BatchTenantContext.getInstance().get();
log.info("*** get tenant " + val);
return val;
}
#Override
public boolean validateExistingCurrentSessions() {
return true;
}
}
So, how to know how route fire? Note thaht the class above is singleton..I'm in a right way?
I use jpa whitin hibernate provider, configured using rhe multitenant configuration like this post: http://tech.asimio.net/2017/01/17/Multitenant-applications-using-Spring-Boot-JPA-Hibernate-and-Postgres.html
The application work in spring-boot Runtime environment or with Tomcat app server.
Any ideas about all?
Thanks so much!
roby
I add this code:
#Configuration
#EnableConfigurationProperties({ MultiTenantAfSissProperties.class, JpaProperties.class })
#ImportResource(locations = { "classpath:applicationContent.xml" })
#EnableTransactionManagement
public class MultiTenantJpaConfiguration {
static final Logger logger = LoggerFactory.getLogger(MultiTenantJpaConfiguration.class);
#Inject
private JpaProperties jpaProperties;
#Inject
MultiTenantAFSISSProperties multiTenantAFSISSProperties; //lista dei datasources collegati ai tenant
#Bean
public Map<String, DataSource> dataSourceRetrieval(){
Map<String, DataSource> result = new HashMap<>();
for (DataSourceProperties dsProperties : this.multiTenantAFSISSProperties.getDataSources()) {
DataSourceBuilder factory = DataSourceBuilder
.create()
.url(dsProperties.getUrl())
.username(dsProperties.getUsername())
.password(dsProperties.getPassword())
.driverClassName(dsProperties.getDriverClassName());
result.put(dsProperties.getTenantId(), factory.build());
}
return result;
}
/**
*
* #return
*/
#Bean
public MultiTenantConnectionProvider multiTenantConnectionProvider(){
return new AfsissMultiTenantConnectionProviderImpl();
}
/**
*
* #return
*/
#Bean
public CurrentTenantIdentifierResolver currentTenantIdentifierResolver(){
return new BatchCurrentTenantIdentifierResolverImpl();
}
/**
*
* #param multiTenantConnectionProvider
* #param currentTenantIdentifierResolver
* #return
*/
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean(MultiTenantConnectionProvider multiTenantConnectionProvider,
CurrentTenantIdentifierResolver currentTenantIdentifierResolver) {
Map<String, Object> hibernateProps = new LinkedHashMap<>();
hibernateProps.putAll(this.jpaProperties.getProperties());
Map<String,String> all = this.jpaProperties.getProperties();
for ( Map.Entry<String, String> prop : all.entrySet()){
System.out.println(" " + prop.getKey() + " = " + prop.getValue());
}
hibernateProps.put(Environment.MULTI_TENANT, MultiTenancyStrategy.DATABASE);
hibernateProps.put(Environment.MULTI_TENANT_CONNECTION_PROVIDER, multiTenantConnectionProvider);
hibernateProps.put(Environment.MULTI_TENANT_IDENTIFIER_RESOLVER, currentTenantIdentifierResolver);
// No dataSource is set to resulting entityManagerFactoryBean
LocalContainerEntityManagerFactoryBean result = new LocalContainerEntityManagerFactoryBean();
result.setPackagesToScan(new String[] { AfFileEntity.class.getPackage().getName() });
result.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
result.setJpaPropertyMap(hibernateProps);
return result;
}
/**
* crea la factory per ricavare l'entity manager
* #param entityManagerFactoryBean
* #return
*/
#Bean
public EntityManagerFactory entityManagerFactory(LocalContainerEntityManagerFactoryBean entityManagerFactoryBean) {
return entityManagerFactoryBean.getObject();
}
/**
* get transaction manager
* #param entityManagerFactory
* #return
*/
#Bean
public PlatformTransactionManager txManager(EntityManagerFactory entityManagerFactory) {
SessionFactory sessionFactory = entityManagerFactory.unwrap(SessionFactory.class);
HibernateTransactionManager result = new HibernateTransactionManager();
result.setAutodetectDataSource(false);
result.setSessionFactory(sessionFactory);
return result;
}
}
In applicationContent.xml:
<jpa:repositories base-package="com.xxx.dao" transaction-manager-ref="txManager" />
<tx:annotation-driven transaction-manager="txManager" proxy-target-class="true" />
The class BatchCurrentTenantIdentifierResolverImpl is called in currentTenantIdentifierResolver() method above by spring transaction manager every time i use entity manager and transaction manager in csvHanlder :
#Component
#Transactional(propagation = Propagation.REQUIRED)
public class MyCsvHandler {
#Inject
AFMOVCrudRepository _entitymanagerMov; //it extends JpaRepository
#Inject
AFVINCCrudRepository _entityManagerVINC;//it extends JpaRepository
#Inject
AFFileCrudRepository _entityManagerAfFile;//it extends JpaRepository
static final Logger logger = LoggerFactory.getLogger(MyCsvHandler.class);
//save csv data on the right table on the right tenant
public void doHandleCsvData(List<List<String>> csvData) throws FileNotEvaluableException
{
//System.out.println("stampo..");
boolean status = true;
if (csvData.size() > 0){
AfFileEntity afbean = new AfFileEntity();
afbean.setNomeFile("test");
afbean.setDataImport(new java.sql.Timestamp(System.currentTimeMillis()));
afbean.setTipoFile("M");
afbean.setAfStatoFlusso("I");
_entityManagerAfFile.save(afbean);
long pkfile = afbean.getId();
logger.info("pkfile: " + pkfile);
int i = 1;
logger.info("file size:" + csvData.size());
for (List<String> rows : csvData){
//for (int j = 0; i < rows.size(); j++){
if (rows.get(2).trim().equalsIgnoreCase(...)){
MovEntity mbean = new MovEntity();
setMovFields(mbean, rows);
mbean.setAfFileId(afbean);
logger.info(String.valueOf((i++)) + " " + mbean);
_entitymanagerMov.save(mbean);
}
else if (rows.get(2).trim().equalsIgnoreCase(..) || rows.get(2).trim().equalsIgnoreCase(..) ) {
VincEntity vincBean = new VincEntity();
setVincFields(vincBean, rows);
vincBean.setAfFileId(afbean);
logger.info(String.valueOf((i++)) + " " + vincBean);
_entityManagerVINC.save(vincBean);
}
else {
status = false;
break;
}
}
if (!status) throw new FileNotEvaluableException("error file format");
}
}
private void setVincFields(VincEntity vincBean, List<String> rows) {
vincBean.setXXX().. and others methods
}
private void setMovFields(MovEntity mbean, List<String> rows) {
mbean.setStxxx() and other .. methods
}
return new
Something like this in your routes
from("direct:csvprocessor1").routeId("tenant2").process((Exchange e)-> {
BatchCurrentTenantIdentifierResolverImpl.tenant.set("tenant_1");
})
.from("file:src/main/resources/data/2?move=OUT&moveFailed=REFUSED")
.unmarshal().csv()
.to("bean:myCsvHandler?method=doHandleCsvData")
.setBody(constant("OK 2"))
.setHeader(Exchange.HTTP_RESPONSE_CODE, constant(200))
.setHeader(Exchange.CONTENT_TYPE, constant("text/html"));
And in your BatchCurrentTenantIdentifierResolverImpl implement it aspublic
class BatchCurrentTenantIdentifierResolverImpl {
public static ThreadLocal<String> tenant = new ThreadLocal<String>();
static final Logger log = LoggerFactory.getLogger(BatchCurrentTenantIdentifierResolverImpl.class);
#Override
public String resolveCurrentTenantIdentifier() {
String val = tenant.get();
log.info("*** get tenant " + val);
return val;
}
#Override
public boolean validateExistingCurrentSessions() {
return true;
}
}

spring boot mybatis with redis as cache

I'm using Spring Boot with Mybatis, and I noticed that everytime I fetch some data with the same query, it will connect to db and query without using cache. So I search the solution for Mybatis with Redis, but cannot find one. All the answer is for Spring and xml configuration file, and I think it's better to use annotation. So, how to configure Redis as Cache to Mybatis in Spring Boot.
here is one of my solution, it just doesn't work.
MybatisRedisCache:
public class MybatisRedisCache implements Cache {
private static Logger logger = Logger.getLogger(MybatisRedisCache.class);
private Jedis redisClient = createClient();
/** The ReadWriteLock. */
private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
private String id;
public MybatisRedisCache(final String id) {
if (id == null) {
throw new IllegalArgumentException("Cache instances require an ID");
}
logger.debug("MybatisRedisCache:id=" + id);
this.id = id;
}
#Override
public String getId() {
return this.id;
}
#Override
public int getSize() {
return Integer.valueOf(redisClient.dbSize().toString());
}
#Override
public void putObject(Object key, Object value) {
logger.debug("putObject:" + key + "=" + value);
redisClient.set(SerializeUtil.serialize(key.toString()), SerializeUtil.serialize(value));
}
#Override
public Object getObject(Object key) {
Object value = SerializeUtil.unserialize(redisClient.get(SerializeUtil.serialize(key.toString())));
logger.debug("getObject:" + key + "=" + value);
return value;
}
#Override
public Object removeObject(Object key) {
return redisClient.expire(SerializeUtil.serialize(key.toString()), 0);
}
#Override
public void clear() {
redisClient.flushDB();
}
#Override
public ReadWriteLock getReadWriteLock() {
return readWriteLock;
}
protected static Jedis createClient() {
try {
JedisPool pool = new JedisPool(new JedisPoolConfig(), "127.0.0.1");
return pool.getResource();
} catch (Exception e) {
e.printStackTrace();
}
throw new RuntimeException("connect failed");
}
}
And here is LoggingRedisCache
public class LoggingRedisCache extends LoggingCache {
public LoggingRedisCache(String id) {
super(new MybatisRedisCache(id));
}
}

Resources