I used to have a tomcat connection pool configuration restricting the initial pool size: spring.datasource.tomcat.initial-size=2
Now switching to hikaricp: what is the equivalent to restrict the initially started connections?
Sidenote: spring.datasource.hikari.minimumIdle does not prevent initializing 10 connections at startup.
You can use these properties provided in spring boot:
spring.datasource.hikari.minimumIdle=5
spring.datasource.hikari.maximumPoolSize=8
and then:
spring.datasource.hikari.idleTimeout=120000
to limit the life of idle connections, but hikari doesn't give you such property for initial number of connections.
With spring boot, set these properties in your application.properties.
spring.jpa.hibernate.hikari.minimumIdle=5
spring.datasource.hikari.maximum-pool-size=10
I just found out it had to do with my configuration of multiple datasources.
In general, the property spring.datasource.hikari.minimum-idle=2 automatically restricts the startup pool size correctly!
But if having multiple data sources, there was a configuration property missing, as follows:
#Bean
#ConfigurationProperties("spring.datasource.secondary.hikari")
public DataSource secondatyDataSource() {
return ...
}
Before I just had "spring.datasource.secondary", and there by my property "spring.datasource.secondary.hikari.*" was not taken into account.
This is probably wrong documented in
https://docs.spring.io/spring-boot/docs/current/reference/html/howto-data-access.html
Related
I have a spring boot application which I have configured most of the properties through the properties file. However, I was looking if there is a way to set the TRANSACTION_ISOLATION_LEVEL through the Spring boot properties. Could someone help me on this.
I'm initializing the data source bean in the following way:
#Bean
#ConfigurationProperties(prefix="spring.datasource")
public DataSource dataSource() {
return buildDataSource("spring.datasource");
}
private DataSource buildDataSource(String propPrefix) {
Stirng driverClassName = env.getProperty(propPrefix + ".driver-class-name");
return DataSourceBuilder.create()
.driverClassName(driverClassName)
.build();
}
Could someone please help me on how to specify the TRANSACTION_ISOLATION_LEVEL either through properties or during the data source initialization.
So, the javax.sql.DataSource does not provide a way to set default Transaction Isolation Level. Still, you can do it, but you must strict to particular implementation. Let me give you c couple of examples:
In case you use Apache BasicDataSource implementation of DataSource, then you can use this. This is for DBCP.
If you are using Apache BasicDataSource, but for DBCP2, you can do something like this.
But in most cases, if we are talking about Spring, we use Hikari Connection Pool. So, in case of HikariCP, you can use this method.
The same is applicable to Spring Boot. Let me explain - using Spring Boot properties file, you can set default transaction isolation level, but for specific DataSource, I mean this property:
spring.datasource.hikari.transaction-isolation
as you probably noticed, let you set default transaction isolation level for HikariCP (if you are using one) And this property:
spring.datasource.dbcp2.default-transaction-isolation
allow you to configure default isolation level for DBCP2.
Hope it helped, have a nice day! :)
I have used ActiveMQ as JMS implementation (activemq-spring 5.12.1) and Spring JMS integration (spring-jms 4.2.3.RELEASE), all wrapped in Spring Boot web application, being deployed on Tomcat.
I have following Spring configuration (code reduced for the verbosity of code sample):
#Configuration
#EnableJms
public class AppConfiguration {
#Bean
public XAConnectionFactory jmsXaConnection(String activeMqUsername, String activeMqPassword) {
ActiveMQXAConnectionFactory activeMQXAConnectionFactory = new ActiveMQXAConnectionFactory(activeMqUsername, activeMqPassword, activeMqUrl);
ActiveMQPrefetchPolicy prefetchPolicy = new ActiveMQPrefetchPolicy();
prefetchPolicy.setAll(0);
activeMQXAConnectionFactory.setPrefetchPolicy(prefetchPolicy);
return activeMQXAConnectionFactory;
}
#Bean
public DefaultJmsListenerContainerFactory jmsListenerContainerFactory(ConnectionFactory connectionFactory, JtaTransactionManager jtaTransactionManager) {
DefaultJmsListenerContainerFactory containerFactory = new DefaultJmsListenerContainerFactory();
containerFactory.setConnectionFactory(connectionFactory);
containerFactory.setTransactionManager(jtaTransactionManager);
containerFactory.setSessionTransacted(true);
containerFactory.setTaskExecutor(Executors.newFixedThreadPool(2));
containerFactory.setConcurrency("2-2");
containerFactory.setCacheLevel(DefaultMessageListenerContainer.CACHE_CONSUMER);
return containerFactory;
}
}
My target was to configure two consumers (hence concurrecny set to 2-2) and to prevent any messages caching (hence prefetch policy set to 0).
It works, but causes very unpleasent side effect:
When I try to undeploy the application via Tomcat Manager, it hangs for a while and then indefinitely, every second produces following DEBUG message:
"DefaultMessageListenerContainer:563 - Still waiting for shutdown of 2 Message listener invokers".
Therefore, I am forced to kill Tomcat process every time. What have I done wrong?
One of my lucky shots (documentation both ActiveMQ and Spring JMS was not that helpful), was to set prefetch policy to 1 instead of 0. Then it undeploys gracefully, but I cannot see how it can relate.
Also I am curious, why having cache level set to CACHE_CONSUMER is required for the ActiveMQ to create two consumers. When default setting was left (CACHE_NONE while using external transaction manager), only one consumer was created (while concurrency was still set two 2-2, and so was TaskExecutor).
If it matters, for connection factory and transaction manager, Atomikos is used. I can paste its configuration also, but it seems irrelevant.
Most likely this means the consumer threads are "stuck" in user code; take a thread dump with jstack to see what the container threads are doing.
I have a web application that currently uses c3p0 and Hibernate to connect to a Firebird 1.5 database.
I am facing a problem from time to time where the database just stops responding, even trying to manually restart the service doesn't have any effect, and it doesn't generate any logs, so I have to manually reboot the machine to get it working again.
I think that maybe Firebird hangs when the pool tries to acquire a specific number of connections or something like that. So, I need to test my app without connection pooling, to check if this is or is not the problem.
I can't simply remove c3p0 configs from persistence because this way Hibernate would use its own integrated connection pool. So how to do it?
The most flexible solution is to use an explicit DataSource, instead of configuring the connection pooling through Hibernate. One option to configure a non-pooling DataSource is by using DriverManagerDataSource:
#Override
protected Properties getProperties() {
Properties properties = new Properties();
properties.put("hibernate.dialect", "org.hibernate.dialect.HSQLDialect");
//log settings
properties.put("hibernate.hbm2ddl.auto", "update");
//data source settings
properties.put("hibernate.connection.datasource", newDataSource());
return properties;
}
protected ProxyDataSource newDataSource() {
DriverManagerDataSource actualDataSource = new DriverManagerDataSource();
actualDataSource.setUrl("jdbc:hsqldb:mem:test");
actualDataSource.setUsername("sa");
actualDataSource.setPassword("");
ProxyDataSource proxyDataSource = new ProxyDataSource();
proxyDataSource.setDataSource(actualDataSource);
proxyDataSource.setListener(new SLF4JQueryLoggingListener());
return proxyDataSource;
}
This way you can choose a pooling or a non-pooling DataSource.
To get a better understanding of you connection pooling resources usage, you can configure FlexyPool to collect metrics for:
concurrent connections
concurrent connection requests
data source connection acquiring time
connection lease time
maximum pool size
total connection acquiring time
overflow pool size
retries attempts
I found documentation for hibernate 3.3 and 4.3 that says:
Just replace the hibernate.connection.pool_size property with
connection pool specific settings. This will turn off Hibernate's
internal pool.
Hibernate will use its org.hibernate.connection.C3P0ConnectionProvider
for connection pooling if you set hibernate.c3p0.* properties
So remove hibernate.connection.pool_size and any hibernate.c3p0... properties from configuration, than connection pooling is disabled.
Adding to Vlad's answer:
If somebody still faces this:
Be sure to remove "hibernate-c3p0" from your classpath, if exists, since this will automatically enable MChange c3p0 connection pool.
Another option that, you can close the connection manually when closing the entity manager:
....
SessionImpl ses = (SessionImpl) session;
close(ses.connection());
try {
session.close();
} catch (Exception e) {
logger.error(e);
}
........
Note: the above manual closing will work with the default pool of hibernate, not hibernate default one.
Good Luck
In my ActiveMQ configuration I would like to change the default DB lock transaction isolation level to TRANSACTION_REPEATABLE_READ.
API documentation writes:
public void setTransactionIsolation(int transactionIsolation)
set the Transaction isolation level to something other that
TRANSACTION_READ_UNCOMMITTED This allowable dirty isolation level may
not be achievable in clustered DB environments so a more restrictive
and expensive option may be needed like TRANSACTION_REPEATABLE_READ
see isolation level constants in Connection
In the XML configuration, the jdbcPersistenceAdapter's transactionIsolation attribute accepts only integer-type values, so I cannot use the Connection.TRANSACTION_REPEATABLE_READ constant directly, but only it's value (4) instead:
<persistenceAdapter>
<jdbcPersistenceAdapter dataDirectory="${activemq.data}" dataSource="#mysql-ds" transactionIsolation="4" lockKeepAlivePeriod="5000">
<locker>
<lease-database-locker lockAcquireSleepInterval="10000"/>
</locker>
</jdbcPersistenceAdapter>
</persistenceAdapter>
Is there a way, that I could specify the constant instead of hardcoding number "4"?
As ActiveMQ is Spring-based, I thought I could try to assign it somehow via using <util:constant>, but could not find how to do it...
Try that way:
<util:constant id="transactionType" static-field="java.sql.Connection.TRANSACTION_REPEATABLE_READ" />
EDIT:
The problem is not in spring but in activemq XML Schema:
<xs:attribute name="transactionIsolation" type="xs:integer">
So it wont accept any other value than hardcoded int - you can try put property placeholder here:
transactionIsolation="#{myproperty}"
but i'm not sure if this will work.
Work around to this problem is to somehow configure activemq by pure spring beans (bean id=...) without using dedicated amq tags.
EDIT2: here you have sample config with pure spring tags http://activemq.apache.org/jms-and-jdbc-operations-in-one-transaction.html
I'm using a Connection via severals pools :
DataSource ds = initialContext.lookup("poolname1");
Connection cn = ds.getConnection();
submethod1(cn);
submethod2(cn);
void submethod1(Connection cn)
{
// using connection
// ..
}
My question is: how to log "poolname" in submethods ? or similar informations about DataSource.
Perhaps this will help
getClientInfo()
or
getMetaData()
as mentionned in the Official Java Doc
The poolname in your example is actually a JNDI Name. This is generally a configuration which is configured in resource definition (e.q under in tomcat config).
For your problem as #sourlcheck mentioned, its not possible as connection are not aware of their datasource.
Once way to solve your problem is to give label to the datasource. Most of the Pooled datasource implementations (e.q. C3P0) offer a setter for setting up a name to the datasource. In C3P0 the datasournce class is ComboPooledDataSource and the method is getDataSourceName(). Once you get this name, it remains the same throughout its life cycle. But off course you need to introduce third party library
You can't log "poolname" in methods that receive Connection. Connections don't know if they are pooled or served directly from non-pooling DataSource.
Also you can create and access your pool in many different ways, not all of them guaranteeing existence of "poolname".