I have a SpringBatch project where I want to catch an exception thrown when the application cannot find the datasource. I've already by-passed this, so it will use 'in memory DAO objects' instead of tables.. but it still throws an exception when datasource is not found.
I want to catch that exception and throw my own error code, but I have no idea where the try/catch block must be placed.
Here is a piece of the error log:
2016-11-24 09:25:36.171 INFO 36770 --- [main] c.d.d.e.config.ReaderConfiguration : Configuring FlatFileItemReader for [MAP]
2016-11-24 09:25:51.664 ERROR 36770 --- [main] o.a.tomcat.jdbc.pool.ConnectionPool : Unable to create initial connections of pool.
com.microsoft.sqlserver.jdbc.SQLServerException: The TCP/IP connection to the host [***], port 1433 has failed. Error: "null. Verify the connection properties. Make sure that an instance of SQL Server is running on the host and accepting TCP/IP connections at the port. Make sure that TCP connections to the port are not blocked by a firewall.".
at com.microsoft.sqlserver.jdbc.SQLServerException.makeFromDriverError(SQLServerException.java:190) ~[sqljdbc4.jar:na]
This is overridden to bypass table creation. Also, I use two datasources and this class needed to be here anyway.
#Component
public class MyBatchConfigurer extends DefaultBatchConfigurer {
//Spring batch needs this in order to allow to use more than one datasource
#Override
public JobRepository createJobRepository() throws Exception {
return new MapJobRepositoryFactoryBean().getObject();
}
}
To be noted that I even tried to place try/catch on "the main" method.. and it still throws the exception above.. and then gets to the breakpoint inside catch.
Also, I tried creating the datasource manually.. but to no avail. Even more, ApplicationEvent doesn't seem to work either.
This is a log where datasource is found:
2016-10-25 16:05:13 [main] INFO c.d.d.e.config.CompanyConfiguration - Configure FlatFileItemReader for [IW]
2016-10-25 16:05:13 [main] INFO o.s.jdbc.datasource.init.ScriptUtils - Executing SQL script from class path resource [org/springframework/batch/core/schema-sqlserver.sql]
2016-10-25 16:05:13 [main] INFO o.s.jdbc.datasource.init.ScriptUtils - Executed SQL script from class path resource [org/springframework/batch/core/schema-sqlserver.sql] in 49 ms.
2016-10-25 16:05:13 [main] INFO o.s.b.f.config.PropertiesFactoryBean - Loading properties file from URL [jar:file:/home/etl/d-d/d-e-1.0.4-SNAPSHOT.jar!/lib/spring-integration-core-4.2.5.RELEASE.jar!/META-INF/spring.integration.default.properties]
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 want to create a microservice with Spring Boot. For persistence i use a mariadb database. To wait for the database which is running in a docker container, i implemented the following code like shown here:
#Bean
public DatabaseStartupValidator databaseStartupValidator(DataSource dataSource) {
var dsv = new DatabaseStartupValidator();
dsv.setDataSource(dataSource);
dsv.setTimeout(60);
dsv.setInterval(7);
dsv.setValidationQuery(DatabaseDriver.MYSQL.getValidationQuery());
return dsv;
}
The code is working very well, my application is now waiting for the database connection. But i get an exception at startup of the application:
java.sql.SQLNonTransientConnectionException: Could not connect to Host ....
...
...
...
In the next line i get an information, that it will wait for the database:
021-04-07 21:29:40.816 INFO 16569 --- [ main] o.s.j.support.DatabaseStartupValidator : Database has not started up yet - retrying in 7 seconds (timeout in 57.65 seconds)
After that the application is starting as expected. So i think everything is working fine, but what i have to do to suppress the Exception? In the linked article it should work without an exception. Do i have to implement the "dependsOnPostProcessor" function? Which dependency i have to use? Sorry, possible a dumb question, i am new to spring boot.
to get rid of that exception you can state the below directive in your application.properties file:
logging.level.com.zaxxer.hikari=OFF
Keep in mind that if the application will not be able to get in contact with the db your spring crashes after a while due to that exception. In addition the above directive prevent you to see any logging activity related to Hikari.
In summary you hide the appearance of the exception until it is possible before the application dies due to timeout.
hoping I clarified a bit the case
Yes indeed you need to add the "depends-on" for the beans that rely on the data source. Note the following part of the documentation:
To be referenced via "depends-on" from beans that depend on database startup, like a Hibernate SessionFactory or custom data access objects that access a DataSource directly.
If I understand it well, this means that beans such as an EntityManagerFactory which rely on the database will now have to go through the DatabaseStartupValidator bean and wait for the DB startup. I don't know what caused your exception, but usually there is an EntityManagerFactory involved, so try adding the DependsOn on this object at least.
This is how the linked article is doing it:
#Bean
public static BeanFactoryPostProcessor dependsOnPostProcessor() {
return bf -> {
// Let beans that need the database depend on the DatabaseStartupValidator
// like the JPA EntityManagerFactory or Flyway
String[] flyway = bf.getBeanNamesForType(Flyway.class);
Stream.of(flyway)
.map(bf::getBeanDefinition)
.forEach(it -> it.setDependsOn("databaseStartupValidator"));
String[] jpa = bf.getBeanNamesForType(EntityManagerFactory.class);
Stream.of(jpa)
.map(bf::getBeanDefinition)
.forEach(it -> it.setDependsOn("databaseStartupValidator"));
};
}
You may not necessarily have Flyway configured, but the main thing to note is the dependency itself is referenced by the bean name databaseStartupValidator which is the name of the method that creates the bean.
I am using Spring JDBC template to query SQL Server db. I have a scheduled task configured to execute once every week, below is the implementation:
#Autowired
private JdbcTemplate jdbcTemplate;
public void importData(){
try{
logger.debug("Importing Data");
jdbcTemplate.query(...) // Fails
catch(DataAccessException e){
//Log the error
}
}
I am getting the below exception when the task is executed (i.e. once every week):
org.springframework.jdbc.support.MetaDataAccessException: Error while extracting DatabaseMetaData; nested exception is java.sql.SQLException: Invalid state, the Connection object is closed.
at org.springframework.jdbc.support.JdbcUtils.extractDatabaseMetaData(JdbcUtils.java:305)
at org.springframework.jdbc.support.JdbcUtils.extractDatabaseMetaData(JdbcUtils.java:329)
at org.springframework.jdbc.support.SQLErrorCodesFactory.getErrorCodes(SQLErrorCodesFactory.java:214)
at org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator.setDataSource(SQLErrorCodeSQLExceptionTranslator.java:134)
at org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator.<init>(SQLErrorCodeSQLExceptionTranslator.java:97)
at org.springframework.jdbc.support.JdbcAccessor.getExceptionTranslator(JdbcAccessor.java:99)
at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:660)
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:695)
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:727)
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:737)
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:787)
Below is the driver class:
spring.datasource.driver-class-name=net.sourceforge.jtds.jdbc.Driver
I guess Spring (or jdbc driver) closes the connection if it's idle for configured amount of time. Looking at the implementation of 'query' method, it seems it does not create a new connection. In this case, do I need to use a different method (e.g. execute)?
It's not Spring that closes the connection but the database that closes it, if inactive for an amount of time. Or perhaps due to a network glitch.
Any connection pool is able to test the connection before giving it to the data-source asking for it. Generally it is done with a test query.
So check if the connection pool is rightly configured.
In your dispatcher-servlet.xml add the following line :
<context:mbean-export registration="ignoreExisting" />
or, If you use annotation, add :
#EnableMBeanExport(registration=RegistrationPolicy.IGNORE_EXISTING)
Or, you can add in server.xml (in case of tomcat) singleton="false" in your resource :
<GlobalNamingResources>
<Resource singleton="false" ..... />
</GlobalNamingResources>
A little background:
I am using Spring and Camel together with Java 8.
public static void main(String[] args) throws Exception {
AbstractApplicationContext _context = new ClassPathXmlApplicationContext(
"application-context.xml");
_context.registerShutdownHook();
MessageRoute _messageRoute = (MessageRoute) _context.getBean("messageRoute");
SpringCamelContext _camelContext = _context.getBean(SpringCamelContext.class);
_messageRoute.setContext(_camelContext);
_camelContext.addRoutes(_messageRoute);
Object lock = new Object();
synchronized (lock) {
lock.wait();
}
((ClassPathXmlApplicationContext) _context).close();
}
[main] DEBUG o.s.c.e.PropertySourcesPropertyResolver - Searching for key 'spring.liveBeansView.mbeanDomain' in [systemProperties]
[main] DEBUG o.s.c.e.PropertySourcesPropertyResolver - Searching for key 'spring.liveBeansView.mbeanDomain' in [systemEnvironment]
[main] DEBUG o.s.c.e.PropertySourcesPropertyResolver - Could not find key 'spring.liveBeansView.mbeanDomain' in any property source. Returning [null]
[main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'messageRoute'
[main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'org.apache.camel.spring.SpringCamelContext#0'
[main] DEBUG o.a.camel.spring.SpringCamelContext - Adding routes from builder: Routes: []
[main] DEBUG o.a.camel.spring.SpringCamelContext - Adding routes from builder: Routes: []
I have tried using DefaultCamelContext as well but the problem is it's just not adding the route class. The MessageRoute class is a simple class extending the RouteBuilder. My observation tells me the line containing: _context.getBean("messageRoute") might have an issue because it's not really passing any route to the RouteBuilder reference.
Never mind I fixed it! Camel wasn't adding an instance of the Route class sitting inside the spring container because in the configure method, one needs an actual path saying from().to().
Pretty funny though that it wasn't throwing any error and even refused the add the ApplicationContext bean to routes.
To add Java routes in XML, just use <routeBuilder ref="myBeanName"/> inside <camelContext>
See the Camel documentation: http://camel.apache.org/spring.html at the section Using Java Code
I'm using the latest spring (4.0.4) and Hibernate (4.3.5) and spring-data-jpa (1.6.0) for the first time and am having trouble getting the repository to work on a MySQL table to write or delete data. It's reading data fine, but when I try to delete, nothing happens. Things work fine if I use an H2 database, but when I switch my data source to be a MySQL server, delete() stops working.
Question 1: Why isn't the CrudRepository sub-class able to delete rows from my table entity when I use a MySQL data source, but it works with the same code if I use an H2 data source?
I can delete data if I create functions like this in my sub-class of CrudRepository:
public interface MyEntityRepository extends CrudRepository<MyEntity, Long> {
#Modifying
#Query("delete from MyEntity where entity_id = ?1")
void delete(Long entityId);
#Modifying
#Query("delete from StageTeacher")
void deleteAll();
}
I am hoping I'm missing something simple. But in my unit test class, I've got this autowired repository reference:
#Autowired
MyEntityRepository myEntityRepository;
When I'm using the MySQL data source these commands do nothing (they don't even case a run-time error):
myEntityRepository.deleteAll();
myEntityRepository.delete(myEntity.getId());
Here's the 2 data sources (H2 is commented out) and the entity manager factory I create using this code:
#Bean
public EntityManagerFactory entityManagerFactory() throws SQLException {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://<host name>:3306/<schema name>");
dataSource.setUsername("<username>");
dataSource.setPassword("<password>");
/*
EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
DriverManagerDataSource dataSource = builder.setType(EmbeddedDatabaseType.H2).build();
*/
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
// used when I have H2 enabled
//vendorAdapter.setGenerateDdl(true);
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setJpaVendorAdapter(vendorAdapter);
Properties properties = new Properties();
properties.setProperty("hibernate.show_sql", "true");
properties.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQLMyISAMDialect");
factory.setJpaProperties(properties);
factory.setPackagesToScan("<package with table entity classes>");
factory.setDataSource(dataSource);
factory.afterPropertiesSet();
return factory.getObject();
}
EDIT: I've added the following to my log4j.xml:
<logger name="org.hibernate">
<level value="DEBUG"/>
</logger>
<logger name="org.springframework.data">
<level value="DEBUG"/>
</logger>
I get this in the console when I have my methods un-commented in the Repository sub-class:
DEBUG [main] IntegrationTests.delete(54) | >>>>>>>>>> delete all??
DEBUG [main] AbstractTransactionImpl.begin(160) | begin
DEBUG [main] LogicalConnectionImpl.obtainConnection(226) | Obtaining JDBC connection
DEBUG [main] LogicalConnectionImpl.obtainConnection(232) | Obtained JDBC connection
DEBUG [main] JdbcTransaction.doBegin(69) | initial autocommit status: true
DEBUG [main] JdbcTransaction.doBegin(71) | disabling autocommit
Hibernate: delete from stage_teacher
DEBUG [main] AbstractTransactionImpl.commit(175) | committing
DEBUG [main] JdbcTransaction.doCommit(113) | committed JDBC Connection
DEBUG [main] JdbcTransaction.releaseManagedConnection(126) | re-enabling autocommit
DEBUG [main] LogicalConnectionImpl.releaseConnection(246) | Releasing JDBC connection
DEBUG [main] LogicalConnectionImpl.releaseConnection(264) | Released JDBC connection
and the delete succeeds!
However, if I comment the repository sub-class methods out, I'll get this in the console:
DEBUG [main] IntegrationTests.delete(54) | >>>>>>>>>> delete??
DEBUG [main] AbstractTransactionImpl.begin(160) | begin
DEBUG [main] LogicalConnectionImpl.obtainConnection(226) | Obtaining JDBC connection
DEBUG [main] LogicalConnectionImpl.obtainConnection(232) | Obtained JDBC connection
DEBUG [main] JdbcTransaction.doBegin(69) | initial autocommit status: true
DEBUG [main] JdbcTransaction.doBegin(71) | disabling autocommit
Hibernate: select stageteach0_.entity_id as entity_i1_0_0_, stageteach0_.active as active2_0_0_, stageteach0_.alias as alias3_0_0_, stageteach0_.allow_marketing_emails as allow_ma4_0_0_, stageteach0_.allow_password_resets as allow_pa5_0_0_, stageteach0_.console_setting_id as console_6_0_0_, stageteach0_.date_created as date_cre7_0_0_, stageteach0_.date_deactivated as date_dea8_0_0_, stageteach0_.date_modified as date_mod9_0_0_, stageteach0_.default_role_id as default10_0_0_, stageteach0_.district_teacher_id as distric11_0_0_, stageteach0_.email_address as email_a12_0_0_, stageteach0_.first_name as first_n13_0_0_, stageteach0_.first_name_localized as first_n14_0_0_, stageteach0_.iid as iid15_0_0_, stageteach0_.last_name as last_na16_0_0_, stageteach0_.last_name_localized as last_na17_0_0_, stageteach0_.main_teacher_id as main_te18_0_0_, stageteach0_.password as passwor19_0_0_, stageteach0_.pref_language_id as pref_la20_0_0_, stageteach0_.rest_id as rest_id21_0_0_, stageteach0_.salutation_id as salutat22_0_0_, stageteach0_.school_teacher_id as school_23_0_0_, stageteach0_.status_id as status_24_0_0_, stageteach0_.tcd as tcd25_0_0_, stageteach0_.teacher_type_id as teacher26_0_0_, stageteach0_.username as usernam27_0_0_ from stage_teacher stageteach0_ where stageteach0_.entity_id=?
DEBUG [main] ResultSetProcessorImpl.extractResults(127) | Starting ResultSet row #0
DEBUG [main] EntityReferenceInitializerImpl.resolveEntityKey(142) | On call to EntityIdentifierReaderImpl#resolve, EntityKey was already known; should only happen on root returns with an optional identifier specified
DEBUG [main] TwoPhaseLoad.doInitializeEntity(160) | Resolving associations for [org.mind.gen40.domain.gen40.StageTeacher#10956]
DEBUG [main] TwoPhaseLoad.doInitializeEntity(286) | Done materializing entity [org.mind.gen40.domain.gen40.StageTeacher#10956]
DEBUG [main] AbstractLoadPlanBasedEntityLoader.load(208) | Done entity load : org.mind.gen40.domain.gen40.StageTeacher#10956
DEBUG [main] AbstractTransactionImpl.commit(175) | committing
DEBUG [main] JdbcTransaction.doCommit(113) | committed JDBC Connection
DEBUG [main] JdbcTransaction.releaseManagedConnection(126) | re-enabling autocommit
DEBUG [main] LogicalConnectionImpl.releaseConnection(246) | Releasing JDBC connection
DEBUG [main] LogicalConnectionImpl.releaseConnection(264) | Released JDBC connection
Does the failure to delete have something to do with this message?
On call to EntityIdentifierReaderImpl#resolve, EntityKey was already known; should only happen on root returns with an optional identifier specified
I'm not sure what that means...
Question 2: Do I have to sub-class CrudRepository for each table that I need basic CRUD operations on, or can I use a reference to the table entity class to create a CrudRepository at run-time for a given table?
Question 3: If I need to manually create my delete and insert methods on a large number of CrudRepository sub-classes, are there any suggestions on generating table entities and DAO or repository classes given tables in MySQL?
I've discovered that the problem was rooted in the fact that I was running my code using a unit test. Apparently unit tests are setup as transactions that are automatically rolled back, but I can't find documentation to support that. My unit test was creating a row in a table and then deleting the row based on it's ID. It was always failing because it was always rolling back the transaction.
If you need unit tests that actually do a delete then add the rollback(false) annotation so your unit test method looks like this:
#Autowired
MyEntityRepository myEntityRepository;
#Test
#Rollback(false)
public void createAndThenDeleteRow() {
MyEntity testRecord = new TestRecord( "fake", "data" );
TestRecord savedRecord = myEntityRepository.save( testRecord );
Long id = savedRecord.getId();
TestRecord loadedRecord = myEntityRepository.findOne( id );
assertNotNull( loadedRecord );
myEntityRepository.delete( id );
TestRecord reloadedRecord = myEntityRepository.findOne( id );
assertNull( reloadedRecord );
}