Spring Batch Hibernate CursorItemReader - spring-batch

Trying to read data from DB using spring batch and hibernate reader getting org.hibernate.hql.internal.ast.QuerySyntaxException: Result is not mapped [from Result]
<import resource="/context-model.xml"/>
<batch:job id="MainJob">
<!-- File Load Step -->
<batch:step id="stepDataReadFromDB">
<batch:tasklet>
<batch:chunk reader="DataReaderDB" processor ="" dummyProcessor" writer="dummyWriter" commit-interval="2"></batch:chunk>
</batch:tasklet>
</batch:step>
</batch:job>
<bean id="DataReaderDB" class="org.springframework.batch.item.database.HibernateCursorItemReader">
<property name="sessionFactory" ref="sessionFactory" />
<property name="queryString" value="from Result" />
<property name="useStatelessSession" value="false" />
</bean>
<bean id="transactionManager" class="org.springframework.batch.support.transaction.ResourcelessTransactionManager"/>
<bean id="jobLauncher" class="org.springframework.batch.core.launch.support.SimpleJobLauncher">
<property name="jobRepository" ref="jobRepository"/>
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="DataSource" />
<property name="mappingLocations" value="classpath:META-INF/spring/batch/hibernate/*.hbm.xml" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect"> org.hibernate.dialect.OracleDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">true</prop>
</props>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager"/>
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean id="DataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="oracle.jdbc.OracleDriver"/>
<property name="url" value="jdbc:oracle:thin:#******"/>
<property name="username" value="UN"/>
<property name="password" value="PW"/>
</bean>
Hiber.hib.xml:
<hibernate-configuration>
<session-factory>
<mapping class="org.core.reader.Result"/>
</session-factory>
</hibernate-configuration>
Entity class
#Entity
#Table(name = "RESULT")
public class Result {
#Id
#Column(name = "SID", nullable = false)
int sID;
#Column(name = "COLUMN1")
String studentName;
I am unable to read data from DB.I need to fetch data from Oracle using hibernate corresponding to the data from the request. I configured like this but getting error above shown
Can someone please help me on this?
I have pasted above the code snippet from configuration file.

If your hibernate configuration file is named Hiber.hib.xml then definitely this won't work. Rename it to hibernate.cfg.xml.
Furthermore I see you are intermixing Annotation based Entity mapping and *.hbm.xml based Entity mapping. Don't do this and try to use one method.

Related

Mapping JPA entity to more than one entityManagers with SpringBatch program

I have developed SpringBatch application and deployed as Web Application in Websphere Liberty profile container. The batch program is designed to read records from a table and invokes HTTP service. Based on the service response a column named status is updated as RECORD_SENT/COMPLETE/ERROR type.
Objective is to reuse the same program for multiple datasources. The data source is passed in job parameter using client type. The datasources are in different schemas but having same datamodel.
Question: How does the transaction manager can be applied at run time inside Job Step or Tasklet?. Seeking help in this regard.
Configuration:
<bean id="entityManagerFactory1"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource1" />
<property name="persistenceUnitName" value="user" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="false" />
</bean>
</property>
<property name="jpaDialect">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
</property>
</bean>
<bean id="entityManagerFactory2"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource2" />
<property name="persistenceUnitName" value="user" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="false" />
</bean>
</property>
<property name="jpaDialect">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
</property>
</bean>
<bean id="entityManagerSelector" class="*com.spring.jpa.test.EntitymanagerSelector">
<property name="entityManagerFactory1" ref="entityManagerFactory1"></property>
<property name="entityManagerFactory2" ref="entityManagerFactory2"></property>
</bean>
job.xml snippet
<bean id="itemReader" class="org.springframework.batch.item.database.JpaPagingItemReader" scope="step">
<property name="entityManagerFactory" value="#{entityManagerSelector.getEntitymanagerForClient({jobParameters['client']})}" />
<property name="queryString" value="select u from User u where u.age > #{jobParameters['age']}" />
</bean>
Setting the job parameters during runtime to identify the client
JobParameters param = new JobParametersBuilder()
.addString("age", "20").addString("client", "client2")
.toJobParameters();
JobExecution execution = jobLauncher.run(job, param);
It will not be possible for you to set the transaction-manager of the Step/tasklet during runtime. You will be better off creating a separate Job's for each client and using their own transaction manager in the tasklet.
<bean id="transactionManager1" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory1" />
</bean>
<bean id="transactionManager2" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory2" />
</bean>
Now use these transaction manager when creating the batch job's
<job id="testJob1" xmlns="http://www.springframework.org/schema/batch">
<step id="client1step1">
<tasklet transaction-manager="transactionManager1">
<chunk reader="itemReader" writer="itemWriter" commit-interval="1" />
</tasklet>
</step>
</job>
<job id="testJob2" xmlns="http://www.springframework.org/schema/batch">
<step id="client2step2">
<tasklet transaction-manager="transactionManager2">
<chunk reader="itemReader" writer="itemWriter" commit-interval="1" />
</tasklet>
</step>
</job>
Let me know if this works out.

Use named parameters in queries Spring batch

I have a spring batch job in which a step is as follows:
<bean id="abstractReader" class="org.springframework.batch.item.database.JdbcCursorItemReader" abstract="true">
<property name="fetchSize" value="1000"/>
<property name="verifyCursorPosition" value="true"/>
<property name="rowMapper">
<bean class="org.springframework.jdbc.core.ColumnMapRowMapper"/>
</property>
</bean>
<bean id="masterReader" parent="abstractReader" abstract="true">
<property name="fetchSize" value="1000"/>
<property name="dataSource" ref="masterDataSource"/>
</bean>
<bean id="abstractWriter" class="org.springframework.batch.item.database.JdbcBatchItemWriter" abstract="true">
<property name="assertUpdates" value="false"/>
<property name="itemPreparedStatementSetter">
<bean class="org.springframework.batch.item.database.support.ColumnMapItemPreparedStatementSetter"/>
</property>
</bean>
<bean id="masterWriter" parent="abstractWriter" abstract="true">
<property name="dataSource" ref="masterDataSource"/>
</bean>
<bean id="tempWriter" parent="masterWriter" scope="step">
<property name="sql" value="${insert_query}"/>
</bean>
<bean id="tempReader" parent="masterReader" scope="step">
<property name="sql" value="${select_query}"/>
</bean>
<batch:step id="tempStep">
<batch:tasklet>
<batch:chunk commit-interval="100"
reader="tempReader"
writer="tempWriter"/>
</batch:tasklet>
</batch:step>
Is there a way to bring named parameter support in the queries? Currently JdbcCursorItemReader is using PreparedStatement. (Too many ? in queries now)
There isn't a way with the JdbcCursorItemReader however you can do it with the JdbcPagingItemReader. You can read more about that reader in the documentation here: https://docs.spring.io/spring-batch/apidocs/org/springframework/batch/item/database/JdbcPagingItemReader.html

Transaction rollback not working for CompositeItemWriter

Somehow transaction rollback not working for CompositeItemWriter.
I have 2 update queries inside CompositeItemWriter and commit-interval of 20.
Let's say after 15 records, if I get any issue with next update, then Ideally all earlier records should roll back to their earlier state. But I can see those records updated in DB.
Anyone has any idea about the same? I am using 3.0.5.RELEASE version of Spring batch.
Configuration is
<step id="step1" next="step2">
<tasklet transaction-manager="transactionManager" >
<chunk reader="reader" writer="customItemWriter" commit-interval="20"/>
<transaction-attributes propagation="REQUIRES_NEW" isolation="DEFAULT"/>
</tasklet>
</step>`
<bean id="customItemWriter" class="org.springframework.batch.item.support.CompositeItemWriter">
<property name="delegates">
<list>
<ref bean="updateTable1"/>
<ref bean="updateTable2"/>
<ref bean="fileWriter"/>
</list>
</property>
</bean>
<bean id="updateTable1" class="org.springframework.batch.item.database.JdbcBatchItemWriter">
<property name="assertUpdates" value="true"/>
<property name="dataSource" ref="dataSource"/>
<property name="itemPreparedStatementSetter">
<bean class="com.batch.jdbc.Table1PreparedStatementSetter" />
</property>
<property name="sql"
value="UPDATE TABLE1 SET STATUS = ? WHERE COLUMN1_ID = ?"/>
</bean>
<bean id="updateTable2" class="org.springframework.batch.item.database.JdbcBatchItemWriter">
<property name="assertUpdates" value="true"/>
<property name="dataSource" ref="dataSource"/>
<property name="itemPreparedStatementSetter">
<bean class="com.batch.jdbc.Table2PreparedStatementSetter" />
</property>
<property name="sql"
value="UPDATE TABLE2 SET STATUS = ? WHERE COLUMN2_ID = ?"/>
</bean>
<bean id="fileWriter" class="x.y.z.CustomFileWriter" />

Using spring cloud namespace and two DataSources

I have a Spring Integration WAR component that I'm updating to run in private PCF. I have two DataSources and a RabbitMQ connection factory defined in the application.
I see an article from Thomas Risberg on using the cloud namespace and handling multiple services of the same time - https://spring.io/blog/2011/11/09/using-cloud-foundry-services-with-spring-part-3-the-cloud-namespace. This is handled by using #Autowired and #Qualifier annotations.
I'm wondering how this can be achieved though when we're not #Autowired and #Qualifier annotations, e.g. wiring a DataSource into a JdbcTemplate. Here we do not have the ability to specify a #Qualifier annotation.
My application is Spring XML config based. I do have ability to use #Autowired and #Qualifier annotations on one of the DataSources, but the other is JPA entity manager. See code snippet.
Any help is much appreciated.
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="persistenceUnitName" value="activity-monitor" />
<property name="jpaVendorAdapter" ref="jpaVendorAdapter"/>
<property name="jpaProperties">
<value>
hibernate.format_sql=true
</value>
</property>
</bean>
<beans profile="cloud">
<cloud:data-source id="dataSource" service-name="actmon-db-service" />
</beans>
Java Build Pack: java_buildpack_offline java-buildpack-offline-v2.4.zip
Spring Auto-reconfiguration version 1.4.0.
UPDATE: This is the full config for both data sources, including PropertySourcesPlaceholderConfigurer with properties loaded from data source using DAO.
<bean id="cic.application.ppc" class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">
<property name="properties" ref="cic.application.properties"/>
<property name="locations" ref="cic.application.propertyLocations"/>
</bean>
<bean id="cic.application.properties" class="java.util.Properties">
<constructor-arg value="#{cicPropertiesService.properties}"></constructor-arg>
</bean>
<bean id="cic.properties.propertiesService" name="cicPropertiesService"
class="com.emc.it.eis.properties.service.DefaultPropertiesService">
<constructor-arg index="0"
ref="cic.properties.propertiesDao" />
</bean>
<bean id="cic.properties.propertiesDao" class="com.emc.it.eis.properties.dao.JdbcPropertiesDao">
<constructor-arg ref="cic.properties.dataSource" />
</bean>
<beans profile="default">
<jee:jndi-lookup id="cic.properties.dataSource"
jndi-name="jdbc/intdb" />
</beans>
<beans profile="cloud">
<cloud:data-source id="cic.properties.dataSource" service-name="oracle-cicadm-db-service" />
</beans>
<beans>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="actmonDataSource" />
<property name="persistenceUnitName" value="activity-monitor" />
<property name="jpaVendorAdapter" ref="jpaVendorAdapter"/>
<property name="jpaProperties">
<value>
hibernate.format_sql=true
</value>
</property>
</bean>
<bean id="transactionManager"
class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
</beans>
<beans profile="default">
<jee:jndi-lookup id="dataSource"
jndi-name="jdbc/actmon" />
</beans>
<beans profile="cloud">
<cloud:data-source id="actmonDataSource" service-name="postgres-actmon-db-service" />
</beans>
<beans profile="default,cloud">
<bean id="jpaVendorAdapter"
class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="database" value="POSTGRESQL" />
</bean>
</beans>
Output from CF when I deploy https://gist.github.com/anonymous/3986a1a7cea4f20c096e. Note it is skipping auto re-configuration of javax.sql.DataSources
First of all, the post from Thomas is pretty old, and references a deprecated support library. Instead of the org.cloudfoundry:cloudfoundry-runtime:0.8.1 dependency, you should use Spring Cloud Connectors dependencies instead.
You can then follow the instructions provided for using XML configuration with Spring Cloud Connectors. With multiple services of the same type, you will need to specify the name of the service for each bean. Following your example, and assuming you created two CF database services named inventory-db and customer-db, that might look something like this:
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="inventory-dataSource" />
<property name="persistenceUnitName" value="activity-monitor" />
<property name="jpaVendorAdapter" ref="jpaVendorAdapter"/>
<property name="jpaProperties">
<value>
hibernate.format_sql=true
</value>
</property>
</bean>
<beans profile="cloud">
<cloud:data-source id="inventory-dataSource" service-name="inventory-db">
<cloud:data-source id="customer-dataSource" service-name="customer-db">
</beans>
I've managed to resolve the issue by using the factory bean used by the spring cloud:data-source, CloudDataSourceFactory. Creating an instance of this and wiring up the config including the service-name of the CF service. This avoids the issue of our PropertySourcesPlaceholderConfigurer trying to use the data source before our the bean has even been defined.
<!--
configure cloud data source for using CloudDataSourceFactory; this is what spring cloud:data-source is using;
required to manually wire this data source bean as cloud:data-source bean gets defined in a phase after our
PropertySourcesPlaceholderConfigurer bean.
-->
<bean id="cic.properties.dataSource" class="org.springframework.cloud.service.relational.CloudDataSourceFactory">
<constructor-arg value="oracle-cicadm-db-service" />
<constructor-arg>
<!-- configuring minimal data source as it is used only to bootstrap properties on app start-up -->
<bean class="org.springframework.cloud.service.relational.DataSourceConfig">
<constructor-arg>
<bean class="org.springframework.cloud.service.PooledServiceConnectorConfig.PoolConfig">
<constructor-arg value="0" />
<constructor-arg value="2" />
<constructor-arg value="180" />
</bean>
</constructor-arg>
<!-- ConnectionConfig not required for cic.properties.dataSource so setting to null -->
<constructor-arg value="#{ null }" />
</bean>
</constructor-arg>
</bean>

JPATransactionManager and annotation driven transactions

I've a small spring3/Hibernate JPA application running and I've come a cropper when trying to use Transactional annotations. Basically they are being ignored by the TransactionManager.
I have a save method that I've amended to highlight that the Transactional attribute readOnly is being ignored. Basically I would have figured that the persist call would have resulted in an exception being thrown because the readOnly attribute is set to true however this is not the case and the entity persists happily to an in-memory HSQLDB.
#Transactional(readOnly=true)
public Product save(Product product) throws HibernateException {
getEntityManager().persist(product);
return product;
}
The JPATransaction manager is wired as follows...
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="org.hsqldb.jdbcDriver" />
<property name="url" value="jdbc:hsqldb:mem:testdb;shutdown=false" />
<property name="username" value="sa" />
<property name="password" value="" />
</bean>
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" id="jpaProperties">
<property name="ignoreUnresolvablePlaceholders" value="true" />
<property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE" />
<property name="searchSystemEnvironment" value="true" />
<property name="location" value="classpath:landingPage-hibernate.properties"/>
</bean>
<util:properties id="jpaHibernateProperties">
<prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop>
<prop key="hibernate.cache.provider_class">net.sf.ehcache.hibernate.EhCacheProvider</prop>
<prop key="hibernate.cache.use_query_cache">true</prop>
<prop key="hibernate.cache.use_second_level_cache">true</prop>
</util:properties>
<bean id="hibernateVendor" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="databasePlatform" value="${hibernate.dialect}"/>
<property name="showSql" value="${hibernate.show_sql}" />
<property name="generateDdl" value="${generateDdl}"/>
</bean>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="landingPagePersistence"/>
<property name="dataSource" ref="dataSource"/>
<property name="jpaVendorAdapter" ref="hibernateVendor"/>
<property name="jpaPropertyMap" ref="jpaHibernateProperties"/>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
Would anyone have an example of JPATransactionManager working with Transactional attributes or am I misunderstanding the usage of JPA entirely? I can see in the EntityManager constructor that the PersistenceContext is always EXTENDED as opposed to TRANSACTION which appears to have some bearing on whether or not the annotations are taken into consideration. Any help would be greatly appreciated.
Thanks,
Mark.
It's not a bug. It's a documented, expected behavior:
This just serves as a hint for the actual transaction subsystem; it will not necessarily cause failure of write access attempts. A transaction manager which cannot interpret the read-only hint will not throw an exception when asked for a read-only transaction.