Implementing Custom EhCache - java

We have a requirement to Cache requests to a max of upto 2 categories per userId-sessionID pair. We are planning to use EhCache for this approach. The project is a spring boot application.
#Cacheable(value="products")
ProductList getProducts(String userID, String sessionID, String categoryID) {
return getProductListForThisUserAndSessionAndCategory(userId, sessionId, categoryId;)
}
The problem is how can I set the limit to a max of 2 cache elements per userID-sessionId when there could be more than one categories per user and session id pair?
One approach:
Setting a partial key of sessionId and userID and create a custom cache which can accept a max two values per sessionID-userID key. How does EhCache support custom Caches?
Any other approaches?

If I got your question right you will change the maximum number of mappings to cache you can config like this
import org.ehcache.config.builders.CacheConfigurationBuilder;
import org.ehcache.config.builders.ResourcePoolsBuilder;
import org.ehcache.expiry.Duration;
import org.ehcache.expiry.Expirations;
import org.ehcache.jsr107.Eh107Configuration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.cache.JCacheManagerCustomizer;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.annotation.PreDestroy;
import java.util.concurrent.TimeUnit;
#Configuration
#EnableCaching
public class CacheConfiguration {
private final Logger log = LoggerFactory.getLogger(CacheConfiguration.class);
private final javax.cache.configuration.Configuration<Object, Object> jcacheConfiguration;
#PreDestroy
public void destroy() {
log.info("Remove Cache Manager metrics");
log.info("Closing Cache Manager");
}
public CacheConfiguration(JHipsterProperties jHipsterProperties) {
jcacheConfiguration = Eh107Configuration.fromEhcacheCacheConfiguration(
CacheConfigurationBuilder.newCacheConfigurationBuilder(Object.class, Object.class,
ResourcePoolsBuilder.heap(2))
.withExpiry(Expirations.timeToLiveExpiration(Duration.of(3600, TimeUnit.SECONDS)))
.build()
);
}
#Bean
public JCacheManagerCustomizer cacheManagerCustomizer() {
log.debug("Starting Ehcache");
return cm -> {
cm.createCache("products", jcacheConfiguration);
};
}
}

Related

Liferay Kafka integration

Over internet I didn't got reference to implement Kafka in liferay.
Below are the requirements needs to be implemented
Push the message to Kafka topic
Poll and receive message from Kafka topic.
Tried below, but unable to receive message from kafka after pushed from kafka terminal
Dependencies :
compileInclude "org.springframework.kafka:spring-kafka:2.9.2"
compileInclude "org.apache.kafka:kafka-streams:3.3.1"
Code:
import org.apache.kafka.common.serialization.Serdes;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.kafka.annotation.EnableKafka;
import org.springframework.kafka.annotation.EnableKafkaStreams;
import org.springframework.kafka.annotation.KafkaStreamsDefaultConfiguration;
import org.springframework.kafka.config.KafkaStreamsConfiguration;
import java.util.HashMap;
import java.util.Map;
import static org.apache.kafka.streams.StreamsConfig.APPLICATION_ID_CONFIG;
import static org.apache.kafka.streams.StreamsConfig.BOOTSTRAP_SERVERS_CONFIG;
import static org.apache.kafka.streams.StreamsConfig.DEFAULT_KEY_SERDE_CLASS_CONFIG;
import static org.apache.kafka.streams.StreamsConfig.DEFAULT_VALUE_SERDE_CLASS_CONFIG;
#Configuration
#EnableKafka
#EnableKafkaStreams
public class KafkaConfig {
#Bean(name = KafkaStreamsDefaultConfiguration.DEFAULT_STREAMS_CONFIG_BEAN_NAME)
KafkaStreamsConfiguration kStreamsConfig() {
Map<String, Object> props = new HashMap<>();
props.put(APPLICATION_ID_CONFIG, "streams-app");
props.put(BOOTSTRAP_SERVERS_CONFIG, "localhost:9092");
props.put(DEFAULT_KEY_SERDE_CLASS_CONFIG, Serdes.String().getClass().getName());
props.put(DEFAULT_VALUE_SERDE_CLASS_CONFIG, Serdes.String().getClass().getName());
return new KafkaStreamsConfiguration(props);
}
}
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import org.osgi.service.component.annotations.Component;
import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.transaction.annotation.Transactional;
#Component(immediate = true)
public class KafkaMessageReceiver {
public static Log _log = LogFactoryUtil.getLog(KafkaMessageReceiver.class);
#Async
#KafkaListener(
topics = "liferay-topic",
concurrency = "2"
)
#Transactional
public void handleMessage(String payload) {
_log.info(payload);
}
}

I want to read YAML in the map form. How can I do it?

Sample yaml looks like
"mappings":
"name": "foo"
"aliases": "abc"
Trying to implement it using PropertySourceFactory, but unsuccessful.
import import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
#Configuration
//#ConfigurationProperties
#PropertySource(value = "classpath:order_config.yml", factory = YamlPropertySourceFactory.class)
public class ValidatorConfig {
#Value("${yaml.mappings}")
private Map<String, String> mappings = new HashMap<>();
#Value("${yaml.mappings.name}")
private String create;
public String getValidatorBean(String tenant, String requestType) {
System.out.println(mappings);
return "yes";
}
}
import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
import org.springframework.core.env.PropertiesPropertySource;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.support.EncodedResource;
import org.springframework.core.io.support.PropertySourceFactory;
import java.io.IOException;
import java.util.Properties;
public class YamlPropertySourceFactory implements PropertySourceFactory {
#Override
public PropertySource<?> createPropertySource(String name, EncodedResource encodedResource)
throws IOException {
YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
factory.setResources(encodedResource.getResource());
Properties properties = factory.getObject();
return new PropertiesPropertySource(encodedResource.getResource().getFilename(), properties);
}
}
Have tried using a bunch of methods using #Value, #ConfigurationProperties, but unsuccessful
Can we implement it using YamlMapFactoryBean. Have not been able to find its working demonstration.

Why does Camunda generate a numeric process instance ID, instead of UUID?

Camunda normally uses UUIDs (e. g. 98631715-0b07-11ec-ab3b-68545a6e5055) as process instance IDs. In my project a process instance ID like 124 is being generated which looks suspicious to me.
This behavior can be reproduced as described below.
Step 1
Check out this repository and start the process engines
core-processes,
core-workflow and
domain-hello-world
so that all of them use the same shared database.
Step 2
Login to the Camunda UI at http://localhost:8080 and navigate to the tasklist.
Start the Starter process in tasklist.
Step 3
Go to the cockpit and navigate to Running process instances (http://localhost:8080/camunda/app/cockpit/default/#/processes).
Click on DomainProcess.
In column ID you will see a numeric (135 in the screenshot above) process instance ID, not a UUID.
Probable cause of the error
In core-processs engine I have the following Config class:
import org.camunda.bpm.engine.impl.history.HistoryLevel;
import org.camunda.bpm.engine.impl.history.event.HistoryEvent;
import org.camunda.bpm.engine.impl.history.handler.CompositeHistoryEventHandler;
import org.camunda.bpm.engine.impl.history.handler.HistoryEventHandler;
import org.camunda.bpm.engine.spring.SpringProcessEngineConfiguration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.transaction.PlatformTransactionManager;
import javax.sql.DataSource;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import static org.apache.commons.lang3.ArrayUtils.addAll;
#Configuration
public class Config {
private static final Logger LOGGER = LoggerFactory.getLogger(Config.class);
#Autowired
#Qualifier("camundaBpmDataSource")
private DataSource dataSource;
#Autowired
#Qualifier("camundaTxManager")
private PlatformTransactionManager txManager;
#Autowired
private ResourcePatternResolver resourceLoader;
#Bean
public SpringProcessEngineConfiguration processEngineConfiguration() {
final SpringProcessEngineConfiguration config = new SpringProcessEngineConfiguration();
config.setDataSource(dataSource);
config.setTransactionManager(txManager);
config.setDatabaseSchemaUpdate("true");
config.setHistory(HistoryLevel.HISTORY_LEVEL_FULL.getName());
config.setJobExecutorActivate(true);
config.setMetricsEnabled(false);
final Logger logger = LoggerFactory.getLogger("History Event Handler");
final HistoryEventHandler testHistoryEventHandler = new HistoryEventHandler() {
#Override
public void handleEvent(final HistoryEvent evt) {
LOGGER.debug("handleEvent | " + evt.getProcessInstanceId() + " | "
+ evt.toString());
}
#Override
public void handleEvents(final List<HistoryEvent> events) {
for (final HistoryEvent curEvent : events) {
handleEvent(curEvent);
}
}
};
config.setHistoryEventHandler(new CompositeHistoryEventHandler(Collections.singletonList(testHistoryEventHandler)));
try {
final Resource[] bpmnResources = resourceLoader.getResources("classpath:*.bpmn");
final Resource[] dmnResources = resourceLoader.getResources("classpath:*.dmn");
config.setDeploymentResources(addAll(bpmnResources, dmnResources));
} catch (final IOException exception) {
exception.printStackTrace();
LOGGER.error("An error occurred while trying to deploy BPMN and DMN files", exception);
}
return config;
}
}
If I remove this configuration (or comment the #Configuration line), the error disappears.
Questions
Why does Camunda generate a numeric process instance ID in this case (and not a UUID as in other cases)?
After adding the line
config.setIdGenerator(new StrongUuidGenerator());
in the configuration class
#Bean
public SpringProcessEngineConfiguration processEngineConfiguration() {
final SpringProcessEngineConfiguration config = new SpringProcessEngineConfiguration();
config.setIdGenerator(new StrongUuidGenerator());
config.setDataSource(dataSource);
the process instance IDs became UUIDs again.
For details see Camunda documentation on ID generators.

Configuration in Resilience4J CircuitBreaker not working

I'm using a circuit breaker of Resilience4J and I need to ignore some custom exceptions so I need to change the default configuration. I'm working with microservices so I have a microservice connected to a database which have some basic requests like get by id and I also have an edge service which use these requests. I need, for example, if the id doesn't exist, the microservice throws a custom exception and the circuitbreaker doesn't open in this case.
Microservice with the database:
Get request
#GetMapping("/sales-rep/{id}")
#ResponseStatus(HttpStatus.OK)
public SalesRepDTO getSalesRep(#PathVariable Integer id) {
return salesRepService.getSalesRep(id);
}
Service
public SalesRepDTO getSalesRep(Integer id) {
if(salesRepRepository.existsById(id)) {
SalesRep salesRep = salesRepRepository.findById(id).get();
return new SalesRepDTO(salesRep.getId(), salesRep.getName());
} else {
throw new SalesRepNotFoundException("Sales rep not found");
}
}
Edge service:
Service
import com.ironhack.manageAllservice.client.AccountClient;
import com.ironhack.manageAllservice.client.LeadClient;
import com.ironhack.manageAllservice.client.SalesRepClient;
import com.ironhack.manageAllservice.controller.dtos.*;
import com.ironhack.manageAllservice.controller.dtos.report.OpportunityBySalesRepDTO;
import com.ironhack.manageAllservice.controller.dtos.report.ReportDTO;
import com.ironhack.manageAllservice.service.exceptions.SalesRepNotFoundException;
import com.ironhack.manageAllservice.controller.dtos.report.*;
import com.ironhack.manageAllservice.service.interfaces.IManageAllService;
import io.github.resilience4j.circuitbreaker.CircuitBreakerConfig;
import io.github.resilience4j.timelimiter.TimeLimiterConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.circuitbreaker.resilience4j.Resilience4JCircuitBreakerFactory;
import org.springframework.cloud.circuitbreaker.resilience4j.Resilience4JConfigBuilder;
import org.springframework.cloud.client.circuitbreaker.CircuitBreaker;
import org.springframework.cloud.client.circuitbreaker.CircuitBreakerFactory;
import org.springframework.cloud.client.circuitbreaker.Customizer;
import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.web.server.ResponseStatusException;
import java.time.Duration;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
#Service
public class ManageAllService implements IManageAllService {
#Autowired
private CircuitBreakerFactory circuitBreakerFactory;
#Bean
public Customizer<Resilience4JCircuitBreakerFactory> globalCustomConfiguration() {
CircuitBreakerConfig circuitBreakerConfig = CircuitBreakerConfig.custom()
.failureRateThreshold(50)
.waitDurationInOpenState(Duration.ofMillis(1000))
.slidingWindowSize(2)
.ignoreExceptions(SalesRepNotFoundException.class)
.build();
TimeLimiterConfig timeLimiterConfig = TimeLimiterConfig.custom()
.timeoutDuration(Duration.ofSeconds(4))
.build();
return factory -> factory.configureDefault(id -> new Resilience4JConfigBuilder(id)
.circuitBreakerConfig(circuitBreakerConfig)
.timeLimiterConfig(timeLimiterConfig)
.build());
}
public SalesRepDTO getSalesRepById(Integer id) {
CircuitBreaker circuitBreaker = circuitBreakerFactory.create("salesRep-service");
SalesRepDTO salesRepDTO = circuitBreaker.run(()->salesRepClient.getSalesRep(id),
throwable -> postSalesRepFallBack());
return salesRepDTO;
}
SalesRepNotFoundException.class is the exception I want to ignore, but the circuitbreaker isn't changing the configuration. Any suggestion?
I suggest that you have a look at our Spring Boot 2 starter: https://resilience4j.readme.io/docs/getting-started-3
Our Spring Boot starter allows you to extract the configuration into the config file and use annotations.

Querydsl + Spring + Transactional ignored

I want to confirm rollback behavior, but I'm having trouble getting it to work.
I have a postgres DB with the following tables:
select * from cat;
pkid | name
--------------------------------------+-------
c75d6e8b-6aff-4214-ad45-d17db254857b | Abbey
select * from toy;
pkid | name | description
--------------------------------------+---------------+-------------------------------------------
dda72782-a1aa-4c0e-9cf6-a408db58a1ae | Laser pointer | Red laser.
f4d7e67d-1b26-4d8d-bb98-1a5c69f3cb49 | String | Colored string attached to a plastic rod.
select * from cattoy;
pkid | fkcat | fktoy
------+-------+-------
I have created a CatService implementation with the idea being you can create a cat, toy, and associate that toy with that cat. If any one of the 3 operations fails I want them all to rollback.
DefaultCatService.java:
import java.util.List;
import java.util.UUID;
import javax.inject.Inject;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.bonkeybee.dao.CatDao;
import com.bonkeybee.dao.CatToyDao;
import com.bonkeybee.dao.ToyDao;
import com.bonkeybee.querydsl.Cat;
import com.bonkeybee.querydsl.Cattoy;
import com.bonkeybee.querydsl.Toy;
#Inject
private CatDao catDao;
#Inject
private CatToyDao catToyDao;
#Inject
private ToyDao toyDao;
#Override
#Transactional
public UUID createCat(final Cat cat){
LOG.debug("Creating cat");
UUID catPkid = catDao.createCat(cat);
Toy toy = new Toy();
toy.setName("Box");
toy.setDescription("Cardboard box.");
toy.setPkid(toyDao.createToy(toy));
Cattoy catToy = new Cattoy();
catToy.setFkcat(catPkid);
catToy.setFktoy(toy.getPkid());
catToyDao.createCatToy(catToy);
return catPkid;
}
I have created DAO's and their implementations for each table with basic CRUD operations.
CatDaoJdbc.java:
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.UUID;
import javax.inject.Inject;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import com.bonkeybee.querydsl.Cat;
import com.bonkeybee.querydsl.QCat;
import com.querydsl.core.BooleanBuilder;
import com.querydsl.core.types.Predicate;
import com.querydsl.core.types.dsl.SimplePath;
import com.querydsl.core.types.dsl.StringPath;
import com.querydsl.sql.SQLQueryFactory;
private static final QCat CAT = QCat.cat;
private static final SimplePath<Object> CAT_PKID = CAT.pkid;
private static final StringPath CAT_NAME = CAT.name;
#Inject
private SQLQueryFactory sqlQueryFactory;
#Override
public UUID createCat(final Cat cat) {
UUID catPkid = UUID.randomUUID();
sqlQueryFactory.insert(CAT)
.columns(CAT_PKID, CAT_NAME)
.values(catPkid, cat.getName())
.execute();
return catPkid;
}
ToyDaoJdbc.java
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.UUID;
import javax.inject.Inject;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import com.bonkeybee.querydsl.QToy;
import com.bonkeybee.querydsl.Toy;
import com.querydsl.core.BooleanBuilder;
import com.querydsl.core.types.Predicate;
import com.querydsl.core.types.dsl.SimplePath;
import com.querydsl.core.types.dsl.StringPath;
import com.querydsl.sql.SQLQueryFactory;
private static final QToy TOY = QToy.toy;
private static final SimplePath<Object> TOY_PKID = TOY.pkid;
private static final StringPath TOY_NAME = TOY.name;
private static final StringPath TOY_DESCRIPTION = TOY.description;
#Inject
private SQLQueryFactory sqlQueryFactory;
#Override
public UUID createToy(Toy toy) {
UUID toyPkid = UUID.randomUUID();
sqlQueryFactory.insert(TOY)
.columns(TOY_PKID, TOY_NAME, TOY_DESCRIPTION)
.values(toyPkid, toy.getName(), toy.getDescription())
.execute();
return toyPkid;
}
CatToyDaoJdbc.java:
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.UUID;
import javax.inject.Inject;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import com.bonkeybee.querydsl.Cattoy;
import com.bonkeybee.querydsl.QCat;
import com.bonkeybee.querydsl.QCattoy;
import com.bonkeybee.querydsl.QToy;
import com.bonkeybee.querydsl.Toy;
import com.querydsl.core.BooleanBuilder;
import com.querydsl.core.types.Predicate;
import com.querydsl.core.types.dsl.SimplePath;
import com.querydsl.sql.SQLQueryFactory;
#Override
public UUID createCatToy(Cattoy catToy) {
throw new RuntimeException("Simulating exception");
}
Main.java:
import java.util.UUID;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.transaction.annotation.Transactional;
import com.bonkeybee.querydsl.Cat;
import com.bonkeybee.querydsl.Cattoy;
import com.bonkeybee.querydsl.Toy;
import com.bonkeybee.service.CatService;
import com.bonkeybee.service.CatToyService;
import com.bonkeybee.service.ToyService;
public static void main(String[] args) {
try (ConfigurableApplicationContext applicationContext = new AnnotationConfigApplicationContext(ApplicationConfiguration.class)) {
CatService catService = applicationContext.getBean(CatService.class);
Cat newCat = new Cat();
newCat.setName(DORA);
newCat.setPkid(catService.createCat(newCat));
}
}
ApplicationConfiguration.java:
import java.beans.PropertyVetoException;
import javax.inject.Inject;
import javax.sql.DataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import com.querydsl.sql.PostgreSQLTemplates;
import com.querydsl.sql.SQLQueryFactory;
#Configuration
#EnableTransactionManagement
#ComponentScan("com.bonkeybee")
public class ApplicationConfiguration {
#Bean
public DataSource getDataSource() throws PropertyVetoException {
ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
comboPooledDataSource.setDriverClass(JDBC_DRIVER);
comboPooledDataSource.setJdbcUrl(JDBC_URL);
comboPooledDataSource.setUser(USER);
comboPooledDataSource.setPassword(PASSWORD);
comboPooledDataSource.setMinPoolSize(MIN_POOL_SIZE);
comboPooledDataSource.setInitialPoolSize(MIN_POOL_SIZE);
comboPooledDataSource.setMaxPoolSize(MAX_POOL_SIZE);
return comboPooledDataSource;
}
#Bean
#Inject
public PlatformTransactionManager getPlatformTransactionManager(final DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
#Bean
public com.querydsl.sql.Configuration getQueryDslConfiguration() {
return new com.querydsl.sql.Configuration(PostgreSQLTemplates.builder().build());
}
#Bean
#Inject
public SQLQueryFactory getSQLQueryFactory(final com.querydsl.sql.Configuration configuration, final DataSource dataSource) {
return new SQLQueryFactory(configuration, dataSource);
}
}
When Main calls catService.createCat() the cat and toy are created, then a RuntimeException is thrown as expected, however inspection of the tables afterward show the new cat and new toy created instead of being rolled back. Please SO, help me ensure no cat goes toyless >:3
EDIT: Adding imports as requested
Solved it after more searching, there were two configuration issues.
First: the transaction manager bean spring looks for by default should be named "transactionManager" otherwise you have to explicitly set the name.
Second: I added a dependency on "querydsl-sql-spring" artifact and changed my SQLQueryFactory to use a SpringConnectionProvider instead of the DataSource bean (found from this example from the querydsl people). Below is the final configuration:
#Configuration
#EnableTransactionManagement
#ComponentScan("com.bonkeybee")
public class ApplicationConfiguration {
#Bean
public DataSource getDataSource() throws PropertyVetoException {
ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
comboPooledDataSource.setDriverClass(JDBC_DRIVER);
comboPooledDataSource.setJdbcUrl(JDBC_URL);
comboPooledDataSource.setUser(USER);
comboPooledDataSource.setPassword(PASSWORD);
comboPooledDataSource.setMinPoolSize(MIN_POOL_SIZE);
comboPooledDataSource.setInitialPoolSize(MIN_POOL_SIZE);
comboPooledDataSource.setMaxPoolSize(MAX_POOL_SIZE);
return comboPooledDataSource;
}
#Inject
#Bean(name = "transactionManager")
public PlatformTransactionManager getPlatformTransactionManager(final DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
#Bean
public com.querydsl.sql.Configuration getQueryDslConfiguration() {
return new com.querydsl.sql.Configuration(PostgreSQLTemplates.builder().build());
}
#Inject
#Bean
public SQLQueryFactory getSQLQueryFactory(final com.querydsl.sql.Configuration configuration, final DataSource dataSource) {
Provider<Connection> provider = new SpringConnectionProvider(dataSource);
return new SQLQueryFactory(configuration, provider);
}
}
Thanks querydsl people for such a cool lib.
Since it is more than one database request involve in your transaction, you have to specify
the persistence context as PersistenceContextType.EXTENDED, which means that it can survive multiple requests.
You have to have a entity manager and then get transaction object from it.
After getting the transactionmanager, begin a new transaction, do all your database operations and then commit. Here is a sample below
EntityManagerFactory emf = ...
EntityManager em = emf.createEntityManager (PersistenceContextType.EXTENDED);
Magazine mag1 = em.find (Magazine.class, magId);
Magazine mag2 = em.find (Magazine.class, magId);
em.getTransaction().begin();
:
:
em.getTransaction().end();

Categories