I am attempting to turn off auto-commit on Hikari with multiple data sources, but I'm not having any luck. I'm using Spring Boot 2 (2.0.3.RELEASE). Here is my config:
application.properties
spring.datasource.primary.driver=com.mysql.cj.jdbc.Driver
spring.datasource.primary.url=jdbc:mysql://localhost:3306/spark?autoReconnect=true
spring.datasource.primary.username=xxxx
spring.datasource.primary.password=xxxx
spring.datasource.primary.max-active=100
spring.datasource.primary.max-idle=5
spring.datasource.primary.min-idle=1
spring.datasource.primary.test-while-idle=true
spring.datasource.primary.test-on-borrow=true
spring.datasource.primary.validation-query=SELECT 1
spring.datasource.primary.time-between-eviction-runs-millis=5000
spring.datasource.primary.min-evictable-idle-time-millis=60000
spring.datasource.ucm.driver=com.mysql.cj.jdbc.Driver
spring.datasource.ucm.url=jdbc:mysql://localhost:3306/usercentral?autoReconnect=true
spring.datasource.ucm.username=xxx
spring.datasource.ucm.password=xxx
spring.datasource.ucm.max-active=100
spring.datasource.ucm.test-while-idle=true
spring.datasource.ucm.test-on-borrow=true
spring.datasource.ucm.validation-query=SELECT 1
spring.datasource.ucm.time-between-eviction-runs-millis=5000
spring.datasource.ucm.min-evictable-idle-time-millis=60000
spring.datasource.ucm.hikari.auto-commit=false # <- Not working
Here's my configuration class where the data sources are setup
#Primary
#Bean
#ConfigurationProperties("spring.datasource.primary")
public DataSourceProperties primaryDataSourceProperties() {
return new DataSourceProperties();
}
#Bean
#Primary
#ConfigurationProperties("spring.datasource.primary")
public DataSource primaryDataSource() {
return primaryDataSourceProperties().initializeDataSourceBuilder().build();
}
#Bean
#ConfigurationProperties("spring.datasource.ucm")
public DataSourceProperties ucmDataSourceProperties() {
return new DataSourceProperties();
}
#Bean(name="ucmDataSource")
#ConfigurationProperties("spring.datasource.ucm")
public DataSource ucmDataSource() {
return ucmDataSourceProperties().initializeDataSourceBuilder().build();
}
Here is what is being output when the pool is created:
-2018-08-23 15:48:22.845 -DEBUG 21455 --- [nio-8081-exec-1] com.zaxxer.hikari.HikariConfig : 1151 : allowPoolSuspension.............false
-2018-08-23 15:48:22.846 -DEBUG 21455 --- [nio-8081-exec-1] com.zaxxer.hikari.HikariConfig : 1151 : autoCommit......................true
-2018-08-23 15:48:22.846 -DEBUG 21455 --- [nio-8081-exec-1] com.zaxxer.hikari.HikariConfig : 1151 : catalog.........................none
-2018-08-23 15:48:22.846 -DEBUG 21455 --- [nio-8081-exec-1] com.zaxxer.hikari.HikariConfig : 1151 : connectionInitSql...............none
How do I turn off auto-commit on this connection pool?
I know that this is very late but this issue exploded my brain for ~2 days and this post is at the top of google search so I will post here the solution for others.
It's actually quite simple, just that I missed it in the docs here https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#howto-two-datasources
long story short make sure that you add .type(HikariDataSource.class) before you build your class.
Also if you use jhipster you should also point your config to the hikari part like this #ConfigurationProperties("spring.datasource.other.hikari")
I am using Spring Boot 2.0.4.RELEASE, and faced the same problem. Spent hours with related posts showing non-working properties...
Removing .hikari worked for me.
spring.datasource.ucm.autocommit=false
Alternative solution to your problem, configure default-auto-commit property as false. It should also work.
spring.datasource.ucm.default-auto-commit=false
Spring Boot Ref 1
default.auto-commit
Make false default-auto-commit should work.
spring.datasource.ucm.default-auto-commit=false
Related
I'm trying to write a basic controller test in a micronaut (3.2.7) application. When I run it, it fails to start as it wants to create DB related beans too. micronaut-hibernate-jpa, flyway, etc. are in the pom.xml.
Can I configure the context somehow so it doesn't pick up hikaripool,flyway, and jpa realted beans?
11:46:23.820 [main] INFO i.m.context.env.DefaultEnvironment - Established active environments: [test]
11:46:24.112 [main] WARN i.m.c.h.j.JpaConfiguration$EntityScanConfiguration - Runtime classpath scanning is no longer supported. Use #Introspected to declare the packages you want to index at build time. Example #Introspected(packages="foo.bar", includedAnnotations=Entity.class)
11:46:24.133 [main] INFO com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Starting...
11:46:25.197 [main] ERROR com.zaxxer.hikari.pool.HikariPool - HikariPool-1 - Exception during pool initialization.
org.postgresql.util.PSQLException: FATAL: password authentication failed for user "postgres"
The code:
class HelloTest {
private static EmbeddedServer server;
private static HttpClient client;
#BeforeAll
public static void setupServer() {
server = ApplicationContext.run(EmbeddedServer.class);
client = server
.getApplicationContext()
.createBean(HttpClient.class, server.getURL());
}
#AfterAll
public static void stopServer() {
if (server != null) {
server.stop();
}
if (client != null) {
client.stop();
}
}
#Test
void testHelloWorldResponse() {
...
}
}
I tried to exclude configurations like this, but with no luck:
server = ApplicationContext.builder("test")
.exclude("io.micronaut.configuration.hibernate.jpa","io.micronaut.configuration.jdbc.hikari")
.run(EmbeddedServer.class);
Note: If I remove everything from application.yml then the test works. It looks like that in tests the default properties are resolved which turns on jpa,metrics, etc. So I guess the test needs to ignore the default settings too somehow.
You can override all of your (default) application.yml with (test-)environment specific property files: https://docs.micronaut.io/latest/guide/index.html#_included_propertysource_loaders
So you can just provide a dedicated application-mycustomtest.yml as part of your test resources, in which you override all default settings.
Then you can specify as part of the test, which environments shall be active:
#MicronautTest(environments={"mycustomtest"})
Asked the micronaut team on gitter and currenlty the only option is not having a default configuration and having multiple configuration files for controller, repo and e2e testing.
I've found a very strange behavior in Spring Boot when trying to serve static files with spaces (or any other special chars, like accents) in file names.
I'm using Spring Boot 2.6.1 with Spring Web MVC and the following customization:
#Configuration
public class MyConfig implements WebMvcConfigurer {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/repo/**")
.addResourceLocations("file:///srv/intranet/repo/");
}
}
I have two files under /srv/intranet/repo, named foo.txt and foo bar.txt (note the space in the second file name).
When I start my application, I can access the first file at http://localhost:8080/repo/foo.txt. But I cannot access the second file (the one with the space in the file name) at http://localhost:8080/repo/foo%20bar.txt (I get a 404 error).
BUT if I put the file foo bar.txt under src/main/resources/static, then I can acces the file at http://localhost:8080/foo%20bar.txt.
I'm aware that Spring Boot configures several directories by default to serve static content (one of them being classpath:/static/), so I'm wondering: what is the difference between the preconfigured directories and the one I'm adding in my #Configuration class via addResourceHandler().addResourceLocations()? Am I missing some details when adding the new resourceHandler?
WORKAROUND
You can set the following property in your application.properties (or equivalent .yml) to get the old behavior in Spring Boot (pre-v2.6.0):
spring.mvc.pathmatch.matching-strategy=ant-path-matcher
UPDATE
I believe this is probably a bug in PathPattern, which replaces AntPathMatcher, and was introduced in Spring Framework 5.3 and adopted in Spring Boot 2.6.0. I submitted a bug report.
UPDATE (2022-06-04)
The bug has been fixed. The fix will be included in Spring Framework 5.3.21.
I have found a workaround for this issue.
Just add the following in your Spring Boot configuration file application.properties:
spring.mvc.pathmatch.matching-strategy=ant-path-matcher
The documentation for this property states that ant-path-matcher is the default value, but it is not. The source code shows that the default value is path-pattern-parser. I submitted an issue.
I have following configuration with Spring Boot 2.6.1 and it successfully loads file with a space in name.
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = { "com.example.sw" })
public class WebConfig implements WebMvcConfigurer {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/files/**").addResourceLocations("file:D:/img/");
}
}
I have an image with name "SO 1.png" (note the space). When hitting the application I get the image
You can probably troubleshoot by putting Spring web on TRACE level where it emits below information while serving the file.
logging.level.org.springframework.web.servlet=TRACE
Below are the logs
2021-12-07 14:24:24.544 TRACE 17200 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : GET "/files/SO%201.png", parameters={}, headers={masked} in DispatcherServlet 'dispatcherServlet'
2021-12-07 14:24:24.568 TRACE 17200 --- [nio-8080-exec-1] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped to HandlerExecutionChain with [ResourceHttpRequestHandler [URL [file:D:/img/]]] and 3 interceptors
2021-12-07 14:24:24.580 TRACE 17200 --- [nio-8080-exec-1] o.s.w.s.r.ResourceHttpRequestHandler : Applying default cacheSeconds=-1
2021-12-07 14:24:24.626 TRACE 17200 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : No view rendering, null ModelAndView returned.
2021-12-07 14:24:24.626 DEBUG 17200 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed 200 OK, headers={masked}
in Spring 5 a new PathPatternParser was introduced
try replacing
registry.addResourceHandler("/files/**")
with:
registry.addResourceHandler("/files/{*path}")
I'm playing around with Spring Boot and the reactive jdbc driver called r2dbc. In my main application I'm using Postgres as a database and now I want to the use h2 for the tests. And the Flyway migration is working with the setup but when the Spring application is able to insert records.
Here is my setup and code
#SpringBootTest
class CustomerRepositoryTest {
#Autowired
CustomerRepository repository;
#Test
void insertToDatabase() {
repository.saveAll(List.of(new Customer("Jack", "Bauer"),
new Customer("Chloe", "O'Brian"),
new Customer("Kim", "Bauer"),
new Customer("David", "Palmer"),
new Customer("Michelle", "Dessler")))
.blockLast(Duration.ofSeconds(10));
}
}
Here is the error that I'm getting
:: Spring Boot :: (v2.3.4.RELEASE)
2020-10-14 15:59:18.538 INFO 25279 --- [ main] i.g.i.repository.CustomerRepositoryTest : Starting CustomerRepositoryTest on imalik8088.fritz.box with PID 25279 (started by imalik in /Users/imalik/code/private/explore-java/spring-example)
2020-10-14 15:59:18.540 INFO 25279 --- [ main] i.g.i.repository.CustomerRepositoryTest : No active profile set, falling back to default profiles: default
2020-10-14 15:59:19.108 INFO 25279 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data R2DBC repositories in DEFAULT mode.
2020-10-14 15:59:19.273 INFO 25279 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 160ms. Found 1 R2DBC repository interfaces.
2020-10-14 15:59:19.894 INFO 25279 --- [ main] o.f.c.internal.license.VersionPrinter : Flyway Community Edition 6.5.0 by Redgate
2020-10-14 15:59:20.052 INFO 25279 --- [ main] o.f.c.internal.database.DatabaseFactory : Database: jdbc:h2:mem:///DBNAME (H2 1.4)
2020-10-14 15:59:20.118 INFO 25279 --- [ main] o.f.core.internal.command.DbValidate : Successfully validated 1 migration (execution time 00:00.022s)
2020-10-14 15:59:20.131 INFO 25279 --- [ main] o.f.c.i.s.JdbcTableSchemaHistory : Creating Schema History table "PUBLIC"."flyway_schema_history" ...
2020-10-14 15:59:20.175 INFO 25279 --- [ main] o.f.core.internal.command.DbMigrate : Current version of schema "PUBLIC": << Empty Schema >>
2020-10-14 15:59:20.178 INFO 25279 --- [ main] o.f.core.internal.command.DbMigrate : Migrating schema "PUBLIC" to version 1.0.0 - schma
2020-10-14 15:59:20.204 INFO 25279 --- [ main] o.f.core.internal.command.DbMigrate : Successfully applied 1 migration to schema "PUBLIC" (execution time 00:00.036s)
2020-10-14 15:59:20.689 INFO 25279 --- [ main] i.g.i.repository.CustomerRepositoryTest : Started CustomerRepositoryTest in 2.466 seconds (JVM running for 3.326)
2020-10-14 15:59:21.115 DEBUG 25279 --- [ main] o.s.d.r2dbc.core.DefaultDatabaseClient : Executing SQL statement [INSERT INTO customer (first_name, last_name) VALUES ($1, $2)]
org.springframework.data.r2dbc.BadSqlGrammarException: executeMany; bad SQL grammar [INSERT INTO customer (first_name, last_name) VALUES ($1, $2)]; nested exception is io.r2dbc.spi.R2dbcBadGrammarException: [42102] [42S02] Tabelle "CUSTOMER" nicht gefunden
Table "CUSTOMER" not found; SQL statement:
INSERT INTO customer (first_name, last_name) VALUES ($1, $2) [42102-200]
My src/test/resources/application.yaml is looking like this:
spring:
r2dbc:
url: r2dbc:h2:mem:///DBNAME?options=DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
username: sa
password:
flyway:
url: jdbc:h2:mem:///DBNAME
baseline-on-migrate: true
user: sa
password:
Any ideas whats missing missing or whats wrong with the setup? If further information is needed please let me know.
Addition/Solution:
The url pattern is different between jdbc and r2dbc. The working solution for me is as follows:
url: r2dbc:h2:file:///./tmp/test-database
url: jdbc:h2:file:./tmp/test-database
And In order to setup Flyway you have to Configure Flyway:
// Flyway is not compatible with r2dbc yet, therefore this config class is created
#Configuration
public class FlywayConfig {
private final Environment env;
public FlywayConfig(final Environment env) {
this.env = env;
}
#Bean(initMethod = "migrate")
public Flyway flyway() {
return new Flyway(Flyway.configure()
.baselineOnMigrate(true)
.dataSource(
env.getRequiredProperty("spring.flyway.url"),
env.getRequiredProperty("spring.flyway.user"),
env.getRequiredProperty("spring.flyway.password"))
);
}
}
I've faced the same issue to setup and access to h2 database in memory for tests:
Liquibase for database migration using JDBC driver
Tests Reactive Crud Repository using R2DBC driver
Error encoutred:
org.springframework.data.r2dbc.BadSqlGrammarException: executeMany; bad SQL grammar [INSERT INTO MY_TABLE... Table "MY_TABLE" not found ...
Inspired by Chris's solution, i configured my src/testresources/application.properties file as follow:
spring.r2dbc.url=r2dbc:h2:mem:///~/db/testdb
spring.r2dbc.username=sa
spring.r2dbc.password=
spring.liquibase.url=jdbc:h2:mem:~/db/testdb;DB_CLOSE_DELAY=-1
spring.liquibase.user=sa
spring.liquibase.password=
spring.liquibase.enabled=true
I am currently having the same problem using r2dbc with liquibase. I am suspecting that the JDBC url points to a different database due to a slightly different syntax between R2DB and JDBC. I can manage to get h2 running from the file system though...
url: r2dbc:h2:file:///~/db/testdb
...
url: jdbc:h2:file:~/db/testdb
EDIT:
In non-reactive Spring Data I'd usually populate the Schema into the H2 memory database using a schema.sql/data.sql pair. This is also possible with R2DBC, but you have to configure the populator yourself.
It's also in the Getting Started R2DBC Tutorial. Basically you have to register a ConnectionFactoryInitializer bean.
#Bean
public ConnectionFactoryInitializer initializer(#Qualifier("connectionFactory") ConnectionFactory connectionFactory) {
var initializer = new ConnectionFactoryInitializer();
initializer.setConnectionFactory(connectionFactory);
var populator = new CompositeDatabasePopulator();
populator.addPopulators(new ResourceDatabasePopulator(new ClassPathResource("schema.sql")));
populator.addPopulators(new ResourceDatabasePopulator(new ClassPathResource("data.sql")));
initializer.setDatabasePopulator(populator);
return initializer;
}
I was able to get it working.
First of all I created following test configuration class (because I want to execute tests only agains H2, on production mode I am using PostgreSQL):
#TestConfiguration
public class TestConfig {
#Bean
#Profile("test")
public ConnectionFactory connectionFactory() {
System.out.println(">>>>>>>>>> Using H2 in mem R2DBC connection factory");
return H2ConnectionFactory.inMemory("testdb");
}
#Bean(initMethod = "migrate")
#Profile("test")
public Flyway flyway() {
System.out.println("####### Using H2 in mem Flyway connection");
return new Flyway(Flyway.configure()
.baselineOnMigrate(true)
.dataSource(
"jdbc:h2:mem:testdb",
"sa",
"")
);
}
}
As you can see in the code above, both beans are scoped to the "test" profile only. As you can imagine I have pretty much the same beans in a regular ApplicationConfiguration class but annotated as a #Profile("default") and configured to use a PostgreSQL.
Second thing is that I created annotation which combines several other annotations to not repeat myself and to easily pickup beans declared in the TestConfig class:
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.RUNTIME)
#Documented
#Inherited
#SpringBootTest
#ActiveProfiles("test")
#Import(TestConfig.class)
public #interface IntegrationTest {
}
Now the test itself:
#IntegrationTest
class CartsIntegrationTest {
// test methods here ....
}
I believe the main hint is to use H2ConnectionFactory.inMemory("testdb");
Flyway currently only supports the blocking JDBC APIs, and it is not compatible with the reactive r2dbc if possbile do not mix them in the same application.
Try to register a ConnectionFactoryInitializer to initiate the database schema and data as #Chris posted, my working example can be found here.
Try nkonev/r2dbc-migrate which is trying to migrate the flyway to the R2dbc world.
There were 2 issues I was experiencing in my project.
I needed to include the dependency:
<dependency>
<groupId>io.r2dbc</groupId>
<artifactId>r2dbc-h2</artifactId>
<scope>test</scope>
</dependency>
I needed to change the value for spring.r2dbc.url to r2dbc:h2:mem:///test_db
With these changes, rd2bc worked with an in memory h2 database for testing. See also:
https://github.com/r2dbc/r2dbc-h2
I have a problem and after two days of research, I was not able to find a solution. I have a simple app so far just read all data from table and wanted to write an integration test for it.
Here is my test:
#Transactional
#SpringBootTest
#ActiveProfiles("integrationTest")
class StockFacadeIT extends Specification {
#Autowired
StockFacadeImpl stockFacade
#Autowired
DSLContext dslContext
#Sql(scripts = "/add_sample_stocks.sql")
def 'should return list of ticker in correct order'() {
when:
def tickers = stockFacade.loadAllTickers(dslContext)
println "when cluase"
then:
println "then cluase"
tickers.getAt(0) == 'abc'
tickers.getAt(1) == 'gpw'
tickers.getAt(2) == 'kgh'
tickers.getAt(3) == 'tpe'
}
}
In log I see:
2017-11-06 21:30:09.478 INFO 21124 --- [ main] o.s.t.c.transaction.TransactionContext : Began transaction (1) for test context [DefaultTestContext#6a01e23 testClass = StockFacadeIT, testInstance = com.gpw.radar.stock.StockFacadeIT#455cbf18, testMethod = $spock_feature_0_0#StockFacadeIT, [...] rollback [true]
2017-11-06 21:30:09.478 INFO 21124 --- [ main] o.s.jdbc.datasource.init.ScriptUtils : Executing SQL script from class path resource [add_sample_stocks.sql]
2017-11-06 21:30:09.478 INFO 21124 --- [ main] o.s.jdbc.datasource.init.ScriptUtils : Executed SQL script from class path resource [add_sample_stocks.sql] in 0 ms.
2017-11-06 21:30:09.712 INFO 21124 --- [ main] org.jooq.Constants :
when cluase
then cluase
2017-11-06 21:30:09.869 INFO 21124 --- [ main] o.s.t.c.transaction.TransactionContext : Rolled back transaction for test context [DefaultTestContext#6a01e23 testClass = StockFacadeIT, testInstance = com.gpw.radar.stock.StockFacadeIT#455cbf18, testMethod = $spock_feature_0_0#StockFacadeIT, testException = Condition not satisfied:
So from log perspective I see that transaction begin before test and rolback is run after test ("then clause"). But test doesn't pass beacuase database is empty. When I delete the #Transactional annotation, it passed but inserted records stayed at DB. What am I doing wrong here?
I found where the problem was. As I added spring framework after jooq. My final configuration for jooq looks like:
#Bean
#Profile("integrationTest")
public DSLContext TestDslContext(DataSource dataSource) {
return DSL.using(new DefaultConfiguration()
.set(dataSource)
.set(new Settings().withRenderNameStyle(RenderNameStyle.AS_IS))
.set(SQLDialect.H2)
.set(getRecordMapperProvider())
);
}
So when I remove this part and use auto config of spring boot the transactions works, however, I have checked how DSLContext config looks when is created by spring I have TransactionProvider and ExecuteListenerProvider missing. When I inject it and set to my custom config the transactions still does not work.
Is there anyway I can know in my program, the full path of file loaded through #PropertySource annotation of Spring.
I need it to show in logs so that one can know which property file is being used in the application
This information is logged already by StandardServletEnvironment. You can set log level to DEBUG for org.springframework.web.context.support.StandardServletEnvironment class to show details in your logs.
If you use spring-boot you can simply add following line into your application.properties file.
logging.level.org.springframework.web.context.support.StandardServletEnvironment = DEBUG
Below seems to be working, though I am not sure if the instance is always of type ConfigurableEnvironment
#Component
public class MyListener implements ApplicationListener<ContextRefreshedEvent>{
#Autowired
private Environment env;
private static final Logger log = LoggerFactory.getLogger(MyListener.class);
#Override
public void onApplicationEvent(ContextRefreshedEvent event) {
if(env instanceof ConfigurableEnvironment){
MutablePropertySources propertySources = ((ConfigurableEnvironment)env).getPropertySources();
for(PropertySource ps : propertySources){
log.info(ps.getName()); //if only file based needed then check if instanceof ResourcePropertySource
}
}
}
}
Edit: don't really need all this. As already answered by Selim, enabling the proper logs does the trick
log4j.logger.org.springframework.core.env.MutablePropertySources=DEBUG
in current ('21) versions of Spring Boot, neither of the two above suggestions for the logging level seem to work. moreover - if the file is actually NOT loaded, because it is NOT found or for whatever other reason, nothing is printed anyway.
at the moment when i have my ROOT logger set to DEBUG (logging.level.root=DEBUG in application.properties), the only thing I see in the log file, when the file is loaded correctly and the #Value annotated property is resolved successfully is:
2021-07-23 11:06:10.299 DEBUG 16776 --- [ restartedMain]
o.s.b.f.s.DefaultListableBeanFactory : Creating shared instance of
singleton bean 'bahblahService'
2021-07-23 11:06:10.302 DEBUG 16776 --- [ restartedMain]
o.s.c.e.PropertySourcesPropertyResolver : Found key
'blahblah.username' in PropertySource 'class path
resource [custom-local.properties]' with value of type String