Commit/rollback transactions manually with multiple datasources in Micronaut - jdbc

I need to commit/rollback transactions manually with multiple datasources in micronaut-data. But when commits second transaction(db2TransactionManager.commit(db2Transaction)) it throws below exception. How can I solve this problem or is there any other way, also I tried with defining #Repository and #Transactional etc., but there is other problem that commits transactions separately?
java.lang.IllegalStateException: Transaction synchronization is not active
at io.micronaut.transaction.support.TransactionSynchronizationManager.getSynchronizations(TransactionSynchronizationManager.java:334)
at io.micronaut.transaction.support.TransactionSynchronizationUtils.triggerBeforeCompletion(TransactionSynchronizationUtils.java:100)
at io.micronaut.transaction.support.AbstractSynchronousTransactionManager.triggerBeforeCompletion(AbstractSynchronousTransactionManager.java:1011)
at io.micronaut.transaction.support.AbstractSynchronousTransactionManager.processCommit(AbstractSynchronousTransactionManager.java:863)
at io.micronaut.transaction.support.AbstractSynchronousTransactionManager.commit(AbstractSynchronousTransactionManager.java:807)
DemoService.java
#Singleton
public class DemoService {
private final SynchronousTransactionManager<Connection> db1TransactionManager;
private final SynchronousTransactionManager<Connection> db2TransactionManager;
private final SynchronousTransactionManager<Connection> db3TransactionManager;
#Inject
public LogsterSynchronizerService(#Named("db1") SynchronousTransactionManager<Connection> db1TransactionManager,
#Named("db2") SynchronousTransactionManager<Connection> db2TransactionManager,
#Named("db3") SynchronousTransactionManager<Connection> db3TransactionManager) {
this.db1TransactionManager = db1TransactionManager;
this.db2TransactionManager = db2TransactionManager;
this.db3TransactionManager = db3TransactionManager;
}
public void processRecords() {
TransactionStatus<Connection> db1Transaction = db1TransactionManager.getTransaction(null);
db1TransactionManager.executeWrite(status -> insertDb1(status.getConnection()));
TransactionStatus<Connection> db2Transaction = db2TransactionManager.getTransaction(null);
db2TransactionManager.executeWrite(status -> insertDb2(status.getConnection()));
TransactionStatus<Connection> db3Transaction = db3TransactionManager.getTransaction(null);
db3TransactionManager.executeWrite(status -> insertDb3(status.getConnection()));
db1TransactionManager.commit(db1Transaction);
db2TransactionManager.commit(db2Transaction);
db3TransactionManager.commit(db3Transaction);
}
private int insertDb1(Connection db1Connection) throws SQLException {
String sql = "INSERT INTO tbl_demo(dt) VALUES (SYSTIMESTAMP)";
PreparedStatement ps = db1Connection.prepareStatement(sql);
return ps.executeUpdate();
}
private int insertDb2(Connection db2Connection) throws SQLException {
String sql = "INSERT INTO tbl_demo(dt) VALUES (SYSTIMESTAMP)";
PreparedStatement ps = db2Connection.prepareStatement(sql);
return ps.executeUpdate();
}
private int insertDb3(Connection db3Connection) throws SQLException {
String sql = "INSERT INTO tbl_demo(dt) VALUES (SYSTIMESTAMP)";
PreparedStatement ps = db3Connection.prepareStatement(sql);
return ps.executeUpdate();
}
}
application.yml
micronaut:
application:
name: demo-app
datasources:
db1:
url: jdbc:oracle:thin:#db1.demo.com:1521:db1
driverClassName: oracle.jdbc.OracleDriver
username: test
password: test
schema-generate: none
dialect: ORACLE
auto-commit: false
maximum-pool-size: 3
minimum-idle: 1
idle-timeout: 5
db2:
url: jdbc:oracle:thin:#db2.demo.com:1522:db2
driverClassName: oracle.jdbc.OracleDriver
username: test
password: test
schema-generate: none
dialect: ORACLE
auto-commit: false
maximum-pool-size: 3
minimum-idle: 1
idle-timeout: 5
db3:
url: jdbc:oracle:thin:#db3.demo.com:1522:db3
driverClassName: oracle.jdbc.OracleDriver
username: test
password: test
schema-generate: none
dialect: ORACLE
auto-commit: false
maximum-pool-size: 3
minimum-idle: 1
idle-timeout: 5
netty:
default:
allocator:
max-order: 3
pom.xml
...
<properties>
<packaging>jar</packaging>
<jdk.version>11</jdk.version>
<release.version>11</release.version>
<micronaut.version>3.4.2</micronaut.version>
<micronaut.data.version>3.3.0</micronaut.data.version>
<exec.mainClass>com.demo.Application</exec.mainClass>
<micronaut.runtime>netty</micronaut.runtime>
</properties>
...
<dependency>
<groupId>io.micronaut.data</groupId>
<artifactId>micronaut-data-jdbc</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>io.micronaut.sql</groupId>
<artifactId>micronaut-jdbc-hikari</artifactId>
<scope>compile</scope>
</dependency>
...

Related

Why does 'ConversionException' occur in 'TrackingEventProcessor' of Axon framework?

with Axon 4.5
with Spring Boot 2.5.2
with Spring JPA
I wrote Saga management as below
#Saga
class OrderSagaManagement {
#Autowired
private lateinit var eventGateway: EventGateway
#StartSaga
#SagaEventHandler(associationProperty = "orderId")
fun handle(orderCreatedEvent: OrderCreatedEvent) {
val paymentId = Random().nextInt(10000)
SagaLifecycle.associateWith("paymentId", paymentId)
eventGateway.publish(PaymentEvent(paymentId, orderCreatedEvent.orderId))
}
...
}
When I dispatch OrderCreateEvent, ConversionException occurs in TokenEventProcessor#processingLoop() as below.
application.yml is as below.
spring:
application:
name: order-service
datasource:
url: mysql
username: mysql
password:
driver-class-name: com.mysql.jdbc.Driver
jpa:
hibernate:
ddl-auto: update
axon:
serializer:
general: xstream
axonserver:
servers: localhost:8124
bulid.gradle
implementation("org.axonframework:axon-spring-boot-starter:4.5")
Why does 'ConversionException' occur in 'TrackingEventProcessor' of Axon framework?

AS400 Spring Boot Java Connection

I am having following exeption trying to connect to db
HikariPool-1 - Driver does not support get/set network timeout for connections. (Receiver class com.ibm.as400.access.AS400JDBCConnectionImpl does not define or inherit an implementation of the resolved method abstract setNetworkTimeout(Ljava/util/concurrent/Executor;I)V of interface java.sql.Connection.)
This is my pom
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>net.sf.jt400</groupId>
<artifactId>jt400</artifactId>
<version>10.5</version>
</dependency>
</dependencies>
And application yaml
spring.datasource:
url: jdbc:as400://xxx/xxx
username: xxx
password: xxx
driver-class-name: com.ibm.as400.access.AS400JDBCDriver
hikari.connection-test-query: values 1
spring.jpa:
database-platform: org.hibernate.dialect.DB2400Dialect
hibernate.ddl-auto: none
You are using the wrong version of jt400.jar. The default version is compiled with JDK 4. The setNetworkTimeout method requires the Executor class which wasn't added until JDK 1.6. You'll need to use the version from java6/jt400.jar or java8/jt400.jar in the download package.
In Maven, you need to specify the jt400_jdk6 classifier.
<dependency>
<groupId>net.sf.jt400</groupId>
<artifactId>jt400</artifactId>
<classifier>jt400_jdk6</classifier>
<version>10.5</version>
</dependency>
I have investigated that AS400JDBCConnectionImpl and AS400JDBCConnection do not have setNetworkTimeout(Executor executor, int milliseconds) method. Maybe you can create a class from it and define the missing function. I couldn't test it, I hope it can be run.
Note: package location is important you should put in com.ibm.as400.access for accessing constructor of base class. Package can be located in your workspace like below picture.
package com.ibm.as400.access;
import java.sql.SQLException;
import java.util.concurrent.Executor;
public class CustomAs400JDBCConnection extends AS400JDBCConnectionImpl {
#Override
public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException {
synchronized (this) {
this.setNetworkTimeout(milliseconds);
}
}
#Override
public void setClientInfo(Properties properties) {
try {
super.setClientInfo(properties);
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
#Override
public void setClientInfo(String s, String s1) {
try {
super.setClientInfo(s, s1);
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
}
application.yaml
spring.datasource:
url: jdbc:as400://xxx/xxx
username: xxx
password: xxx
driver-class-name: com.ibm.as400.access.CustomAs400JDBCConnection
hikari.connection-test-query: values 1
spring.jpa:
database-platform: org.hibernate.dialect.DB2400Dialect
hibernate.ddl-auto: none

Get Query is not working when using HQL in Hibernate Spatial

I am using Spring boot along with Hibernate for a Spatial query.
Libraries used:
1. Spring boot - 2.1.3.RELEASE
2. Hibernate Spatial - 5.3.7.Final
3. MariaDB - mysql Ver 15.1 Distrib 10.1.36-MariaDB
Whenever I use HQL as depicted below in Query, I am getting the following error during application startup however when I try using native query it works.
I have tried with different dialects. Also, tried using columnDefinition with value as geometry, geolatte-geometry.
pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-spatial</artifactId>
<exclusions>
<exclusion>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
application.yml
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
jpa:
hibernate:
ddl-auto: none
properties:
hibernate:
jdbc:
lob:
non_contextual_creation: true
physical_naming_strategy: com.orange.alc.polygon.dao.config.DefaultNamingStrategy
format_sql: false
dialect: org.hibernate.spatial.dialect.mysql.MySQLSpatialDialect
#Entity
public class PolygonMasterEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
// Here we have used Geolatte library
private Polygon geometry;
#Column(name = "is_active")
private Boolean active;
#Column(name = "is_deleted")
private Boolean deleted;
}
#Repository
public interface PolygonMasterRepository extends JpaRepository<PolygonMasterEntity, Long>,
JpaSpecificationExecutor<PolygonMasterEntity> {
#Query("select master from #{#entityName} master WHERE"
+ " and within(master.geometry, :point)")
List<PolygonMasterEntity> findCostUsingPointForLLME(
#Param("point") Point point);
}
Currently, I am getting the following error during startup:
Caused by: org.hibernate.hql.internal.ast.QuerySyntaxException: unexpected AST node: ( near line 1, column 164 [select master from com.orange.alc.polygon.dao.entity.PolygonMasterEntity master WHERE within(master.geometry, :point)]
~~~~~~~~~ at org.hibernate.hql.internal.ast.ErrorTracker.throwQueryException(ErrorTracker.java:93)
~~~~~~~~~ at org.hibernate.hql.internal.ast.QueryTranslatorImpl.analyze(QueryTranslatorImpl.java:277)
~~~~~~~~~ at org.hibernate.hql.internal.ast.QueryTranslatorImpl.doCompile(QueryTranslatorImpl.java:191)
~~~~~~~~~ at org.hibernate.hql.internal.ast.QueryTranslatorImpl.compile(QueryTranslatorImpl.java:143)
~~~~~~~~~ at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:119)
~~~~~~~~~ at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:80)
~~~~~~~~~ at org.hibernate.engine.query.spi.QueryPlanCache.getHQLQueryPlan(QueryPlanCache.java:153)
~~~~~~~~~ at org.hibernate.internal.AbstractSharedSessionContract.getQueryPlan(AbstractSharedSessionContract.java:595)
~~~~~~~~~ at org.hibernate.internal.AbstractSharedSessionContract.createQuery(AbstractSharedSessionContract.java:704)
~~~~~~~~~ ... 100 common frames omitted
You have and right behind WHERE in your query.
I don't think that is legit HQL and you should drop the and.
The properties under spring.jpa.properties are used as is and directly passed to JPA as a Map. As Spring (Boot) doesn't parse these you cannot use the normal YAML syntax but have to include the property names as is with a .. This is also explained in this Github issue and the Spring Boot Documentation.
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
jpa:
hibernate:
ddl-auto: none
properties:
hibernate.jdbc.lob.non_contextual_creation: true
hibernate.physical_naming_strategy: com.orange.alc.polygon.dao.config.DefaultNamingStrategy
hibernate.format_sql: false
hibernate.dialect: org.hibernate.spatial.dialect.mysql.MySQLSpatialDialect
Should work and set the proper dialect.

Error resolving template on deploy jar or war on spring boot

when i run my application on embedded tomcat server all thing is good.
but when i deploy jar or war on other server or container, server on some url give me error:
Error resolving template "/shop/index", template might not exist or might not be accessible by any of the configured Template Resolvers
this is my application.yml:
server:
port: 8080
logging:
level:
com.mousavi007.shop: debug
spring:
datasource:
url: jdbc:mysql://localhost:3306/shop2
username: *******
password: *******
platform: mysql
jpa:
hibernate:
ddl-auto: update
database-platform: org.hibernate.dialect.MySQL5InnoDBDialect
database: mysql
show-sql: true
thymeleaf:
mode: LEGACYHTML5
shop controller:
#Slf4j
#Controller
#RequestMapping("/shop")
public class ShopController {
#GetMapping({"","/"})
public String Shop(Model model, #RequestParam("pageSize") Optional<Integer> pageSize,
#RequestParam("page") Optional<Integer> page){
****
****
****
****
return "/shop/index";
}
}
change
return "/shop/index";
to
return "shop/index";

2 Hikari CPs with different datasource configurations?

Has anyone successfully configured two hikari connection pools with different datasources in a spring boot application? How do I do it using application.properties?
I know that this was asked a long time ago, but I think that it might help others.
In addition, I don't think that the "possible duplicates" mentioned above answer the question.
I'm using spring boot 2.0.4 with maven.
Instead of having a dedicated scope for hikary, as you would if you use one db, e.g.
datasource:
hikari:
connection-test-query: SELECT 1 FROM DUAL
minimum-idle: 1
maximum-pool-size: 2
pool-name: some-pool-name
You can take the settings that you want and put the directly inside the db scope, e.g.:
spring:
datasource:
db1:
type: com.zaxxer.hikari.HikariDataSource
maximum-pool-size: 2
minimum-idle: 1
pool-name: db1-pool
connection-test-query: SELECT 1 FROM DUAL
jdbc-url: jdbc:mysql://${host1}:${port1}/${db1}
username: ${db1-user}
password: ${db1-pass}
driver-class-name: com.mysql.cj.jdbc.Driver
db2:
type: com.zaxxer.hikari.HikariDataSource
maximum-pool-size: 2
minimum-idle: 1
pool-name: db2-pool
connection-test-query: SELECT 1 FROM DUAL
jdbc-url: jdbc:mysql://${host2}:${port2}/${db2}
username: ${db2-user}
password: ${db2-pass}
driver-class-name: com.mysql.cj.jdbc.Driver
As you can see the pool-name and size were set inside that scope.
Then in a java configuration file:
#Configuration
public class AppConfiguration {
....
#Bean("db1")
#ConfigurationProperties(prefix = "spring.datasource.db1")
public DataSource firstDataSource() {
return DataSourceBuilder.create().build();
}
#Bean("db2")
#ConfigurationProperties(prefix = "spring.datasource.db1")
public DataSource secondDataSource() {
return DataSourceBuilder.create().build();
}
}

Resources