Flyway & MyBatis: Java Configuration for Spring-Boot - spring-boot

I'm trying to code a web-app using Spring-Boot, HSQLDB, Flyway and MyBatis. I started without MyBatis and Flyway happily created the database every time I had removed the HSQLDB.
After I added MyBatis all was fine until I had to make changes in the initial SQL-file and removed the database. Now I'm failing to start the web-app. It seems as if Flyway and MyBatis somehow depend on each other.
My database configuration:
#Configuration
public class DatabaseConfiguration {
#Bean
public DataSource dataSource() { ... }
#Bean
public DataSourceTransactionManager transactionManager() { ... }
#Bean
public static MapperScannerConfigurer mapperScannerConfigurer() { ... }
#Bean
public DataSourceInitializer dataSourceInitializer() throws Exception { ... }
#Bean
public SqlSessionFactoryBean sqlSessionFactoryBean() throws Exception { ... }
#Bean
public SqlSessionTemplate sqlSessionTemplate() throws Exception { ... }
}
I fully understand that MapperScannerConfigurer, SqlSessionFactoryBean and SqlSessionTemplate are coming from MyBatis, all Flyway-stuff is done by Spring-Boot. From what I can tell Flyway needs a DataSource and MyBatis needs a database where the Flyway scripts ran already to allow the initialisation of the mappers.
The error I get is
### Error querying database. Cause: java.sql.SQLSyntaxErrorException: user lacks privilege or object not found: MY_TABLE
### The error may exist in file [/home/work/Eclipse/com.sjngm.hs/target/classes/sqlmap/MyTableMapper.xml]
### The error may involve com.sjngm.hs.dao.mapper.MyTableMapper.getByName
### The error occurred while executing a query
### SQL: SELECT * FROM MY_TABLE WHERE Name = ?
### Cause: java.sql.SQLSyntaxErrorException: user lacks privilege or object not found: MY_TABLE
Note that there is no indication in the entire log-file that Flyway already did something. Also I can't find any CREATE TABLE in HSQLDB's files, which makes the above error saying that it can't find table MY_TABLE.
I already tried moving dataSource() to a new configuration class, but that didn't help.
What do I need to do to solve that indirect dependency?

What helped was making dataSource() a #FlywayDataSource.

Related

How to prevent HSQLDB from persisting data between applications runs when using Spring Boot?

I am run a Spring Boot/Web application and I am using an embedded HSQLDB during prototyping. As part of this I do not want to persist data between runs. I would like the only data in the system to be that from those scripts.
How can I modify my configuration to achieve that?
#Configuration
public class RepoConfig {
#Bean
public DataSource dataSource() {
EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
EmbeddedDatabase db = builder.setType(EmbeddedDatabaseType.HSQL)
.addScript("classpath:table.sql")
.addScript("classpath:data.sql")
.build()
;
return db;
}
#Bean
public JdbcTemplate jdbcTemplate(DataSource dataSource) {
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
return jdbcTemplate;
}
}
I tried adding a script to drop the tables before creating them, like
DROP TABLE mytablename ;
but I kept getting the error:
user lacks privilege or object not found: MYTABLENAME
PS:
Spring Boot 2.5.0
HSQLDB 2.6.0
You can do that with the following configuration:
spring.jpa.hibernate.ddl-auto = create-drop
You can find more detail on Initialize a Database Using Hibernate
Or also you can set this property spring.datasource.data
spring.datasource.data=drop.sql,data.sql
then those files should be in
src/main/resources/drop.sql
src/main/resources/data.sql

Am trying to do simple JDBC call in a spring boot application is not working

I am looking forward to creating a service using spring boot application where I like to use JDBC prepared statement call which executes the stored procedure get me the required result.
I like to have connection pooling but unfortunately, I don’t know implement
Summary
(services using spring boot --->Simple JDBC with connection pooling---->Mysql)
For this, I have tried to create a data source and execute jdbc statement but not working
#Controller
public class ExampleController {
#Autowired
private ExampleRepository repo;
#RequestMapping("/")
public #ResponseBody String getDataBaseData() throws SQLException{
return repo.getDataBaseData();
}
}
#Configuration
public class DataSources {
#Bean(name = "primary")
#Primary
#ConfigurationProperties(prefix="spring.datasource")
public DataSource primaryDataSource() {
return DataSourceBuilder.create().build();
}
}
#Component
public class ExampleRepository {
#Autowired
private DataSource ds;
public String getDataBaseData() throws SQLException {
Connection con = ds.getConnection();
System.out.println(con);
Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery("select * from emp");
while (rs.next())
System.out.println(rs.getInt(1) + " " + rs.getString(2) + " " + rs.getString(3));
con.close();
return rs.toString();
}
}
getting errors like below
com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: Could not create connection to database server.
com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: Could not create connection to database server.
Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaAutoConfiguration.class]: Invocation of init method failed; nested exception is org.hibernate.HibernateException: Access to DialectResolutionInfo cannot be null when 'hibernate.dialect' not set
Expected Result : Database data should display in web browser
This is my github repo https://github.com/PradeepKumarHE/SpringBootWithSimpleJDBC/tree/master
where i have DBscript file to create
What I can see from your pom.xml, you are using spring-boot-starter-data-jpa. It fetches unneccessary dependencies, which triggers SpringBoot jpa autoconfiguration.
If you want to use pure jdbc with spring boot, replace spring-boot-starter-data-jpa with spring-boot-starter-jdbc (https://mvnrepository.com/artifact/org.springframework.boot/)
In this case you need to
have mysql jdbc driver declared in maven dependencies
define spring.datasource.url, spring.datasource.username, spring.datasource.password in your properties or yaml (you don't need to define spring.datasource.driver if you have only one jdbc driver in your maven deps)
remove your DataSources configuration, since springboot will autoconfigure it for you

Spring Boot auto reconnect to PostgreSQL using JdbcTemplate and multiple datasources

I have a Spring Boot v 1.5.1.RELEASE app which uses PostgreSQL 9.6 as a datasource. My app remains connected to Postgres even when idle, but if the connection is lost then the app does not reconnect and instead throws:
org.springframework.jdbc.support.MetaDataAccessException: Error while extracting DatabaseMetaData; nested exception is org.postgresql.util.PSQLException: This connection has been closed.
at org.springframework.jdbc.support.JdbcUtils.extractDatabaseMetaData(JdbcUtils.java:342) ~[spring-jdbc-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.jdbc.support.JdbcUtils.extractDatabaseMetaData(JdbcUtils.java:366) ~[spring-jdbc-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.jdbc.support.SQLErrorCodesFactory.getErrorCodes(SQLErrorCodesFactory.java:212) ~[spring-jdbc-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator.setDataSource(SQLErrorCodeSQLExceptionTranslator.java:134) [spring-jdbc-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator.<init>(SQLErrorCodeSQLExceptionTranslator.java:97) [spring-jdbc-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.jdbc.support.JdbcAccessor.getExceptionTranslator(JdbcAccessor.java:99) [spring-jdbc-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:649) [spring-jdbc-4.3.6.RELEASE.jar:4.3.6.RELEASE]
Although I am not using JPA and I believe I am using the Tomcat pool that comes with spring-boot-starter, I have read and tried the suggestions discussed here and here with no luck. In my properties file, I have tried:
#spring.datasource.tomcat.test-on-borrow=true
#spring.datasource.tomcat.validation-query=SELECT 1
#spring.datasource.tomcat.test-while-idle=true
#spring.datasource.tomcat.time-between-eviction-runs-millis=3600000
#spring.datasource.tomcat.validation-query=SELECT 1
#spring.datasource.dbcp2.test-on-borrow=true
#spring.datasource.dbcp2.validation-query=SELECT 1
spring.datasource.test-on-borrow=true
spring.datasource.validation-query=SELECT 1
However, I am using two data sources, configured like this:
#Configuration
public class DatabaseConfiguration
{
#Bean
#Primary
#ConfigurationProperties(prefix = "spring.ds_pgsql_rtmain")
public DataSource rtmainDataSource()
{
DataSource dataSource = DataSourceBuilder.create().build();
return dataSource;
}
#Bean
#ConfigurationProperties(prefix = "spring.ds_pgsql_pdns")
public DataSource pdnsDataSource()
{
return DataSourceBuilder.create().build();
}
#Bean
#Primary
public JdbcTemplate rtmainJdbcTemplate(DataSource rtmainDataSource)
{
return new JdbcTemplate(rtmainDataSource);
}
#Bean
public JdbcTemplate pdnsJdbcTemplate(#Qualifier("pdnsDataSource") DataSource pdnsDataSource) {
return new JdbcTemplate(pdnsDataSource);
}
}
I'm not sure if the problem is that I did not configure the data pool correctly or because the pool does not work when I manually configure the data sources. Or something else. Assistance would be greatly appreciated, thank you.
Yes since you're not using an auto configured data source it is not working.
Since you're applying properties from your own prefix you just have to put test-on-borrow and validation-query on your own prefix. Try this:
spring.ds_pgsql_rtmain.test-on-borrow=true
spring.ds_pgsql_rtmain.validation-query=SELECT 1
spring.ds_pgsql_pdns.test-on-borrow=true
spring.ds_pgsql_pdns.validation-query=SELECT 1

Spring Boot 1.2.5.RELEASE & Spring Security 4.0.2.RELEASE - How to load configuration file before security context initialization?

I'm facing a problem with Spring: I'm migrating from Spring Security ver. 3.2.7.RELEASE to 4.0.2.RELEASE. Everything was working fine in older version, however a problem occured when it came to loading DataSource.
Let me describe the architecture:
Application is secured with both SAML and LDAP mechanisms (SAML configuration is pretty similar to config given here: https://github.com/vdenotaris/spring-boot-security-saml-sample/blob/master/src/main/java/com/vdenotaris/spring/boot/security/saml/web/config/WebSecurityConfig.java).
They both need to connect to database in order to get some required data. We use MyBatis with Spring Mybatis to get needed data. That's, where the problem begins.
My DAO configuration class looks like this:
#Configuration
#EnableConfigurationProperties
#MapperScan(basePackages = { "pl.myapp" })
public class DaoConfiguration {
#Bean
#Primary
#ConfigurationProperties(prefix = "spring.datasource")
public DataSource dataSource() {
return DataSourceBuilder.create().build();
}
#Bean
#Primary
public JdbcTemplate jdbcTemplate() {
return new JdbcTemplate(dataSource());
}
#Bean
#Primary
public SqlSessionFactoryBean sqlSessionFactoryBean() {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSource());
// some stuff happens here
return sqlSessionFactoryBean;
}
#Bean
#Primary
public DataSourceTransactionManager transactionManager() {
return new DataSourceTransactionManager(dataSource());
}
#Bean
#ConfigurationProperties(prefix = "liquibase.datasource")
#ConditionalOnProperty(name="liquibase.enabled")
public DataSource liquibaseDataSource() {
DataSource liquiDataSource = DataSourceBuilder.create().build();
return liquiDataSource;
}
}
In previous version it worked like a charm, but now it has a problem loading mappers, resulting in Bean creation exception on FactoryBean type check: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'someMapper' defined in file [<filename>]: Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Property 'sqlSessionFactory' or 'sqlSessionTemplate' are required
over and over again (it's not my problem, it's a known Spring/MyBatis bug).
I did some debugging and discovered something interesting: it looks like DaoConfiguration is not treated like a configuration here! I mean: if I add
#Bean
public SqlSessionFactory sqlSessionFactory() throws Exception {
return sqlSessionFactoryBean().getObject();
}
to this config, "normal" call of #Bean annotated method should result in calling proper interceptor, here it lacks this funcionality.
My prediction is that: this config class has not been properly wrapped yet and Spring Security already needs beans produced by it.
Is there any solution to properly load this configuration before Spring Security is initialized? Or am I just wrong and missing something (maybe not so) obvious?

Spring OAuth2 Requiring PlatformTransactionManager

I'm working on integrating Spring Security OAuth2 with JWT tokens into a Spring Boot project. My authentication server is configured similar to what is found in this sample project.
When the OAuth2 client performs the POST on /oauth/token it is unable to create the access token. The specific error logged is:
o.s.s.o.provider.endpoint.TokenEndpoint : Handling error: NoSuchBeanDefinitionException, No qualifying bean of type [org.springframework.transaction.PlatformTransactionManager] is defined
I've debugged it down to AbstractTokenGranter line 70 at the call to tokenServices.createAccessToken. I've not been able to easily debug further than that because this call actually goes through a proxy. It seems something in the configuration is wanting to make this transactional. Creating access tokens shouldn't be transactional in JWT. I could see why retrieving the access code would be transactional, but the code successfully gets past that point.
Why might this be requiring the PlatformTransactionManager and how can I supply one?
Problem is that you configured in your application a usage of a in-memory database with new InMemoryTokenStore(), but your spring-boot application contains no in-memory database.
Solution: add in your spring-boot pom or gradle dependency a in-memory database.
Example for H2 and Maven pom:
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.4.187</version>
</dependency>
I had the same problem
tokenServices.createAccessToken use #Transactional .
As i use mongo DB i don't need transactions .
i solved the problem by adding a PseudoTransactionManager bean .
#Bean
public PlatformTransactionManager annotationDrivenTransactionManager() {
return new PseudoTransactionManager();
}
The problem is that methods in DefaultTokenServices are annotated with #Transactional. So even if you're not using a database, you'll need to add a transaction manager bean like this in your authorization server configuration:
#Bean
public PlatformTransactionManager annotationDrivenTransactionManager() {
return new ResourceTransactionManager() {
#Override
public Object getResourceFactory() {
return null;
}
#Override
public TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException {
return null;
}
#Override
public void commit(TransactionStatus status) throws TransactionException {
}
#Override
public void rollback(TransactionStatus status) throws TransactionException {
}
};
}
I faced similar issue of PlatformTransactionManager and resolved it by the following steps:
Added H2 database to pom.xml (to enable storage of clients in memory)
Using Mongo DB as application backend. (ensured application uses MongoRepository instead of CrudRepository)
Removed exclude class in #EnableAutoConfiguration annotation (I had earlier added DataSourceAutoConfiguration.class in exclusion)
Point 1 and Point 3 are mutual. H2 configuration should have DataSourceAutoConfiguration.class enabled.
Thanks.

Resources