I want to update address.
#Modifying
#Query("update UserInfo u set u.address = ?1 where u.username = ?2")
void setAddress(String address, String username);
But it doesn't work.
org.springframework.web.util.NestedServletException: Request processing failed;
nested exception is org.springframework.dao.InvalidDataAccessApiUsageException:
|Exception Description: No transaction is currently active; nested exception is
javax.persistence.TransactionRequiredException: |Exception Description: No transaction
is currently active
And it says my query string is an unknown source
Which reason occupy this exception?
How to update mutiple fields in an update Query?
#Query("update UserInfo u set u.address = ?1, u.phoneNumber = ?2 where u.username = ?3")
No transaction is currently active, so just add an annotation to tell the spring, this is transaction
#Modifying
#Transactional
#Query("update UserInfo u set u.address = ?1 where u.username = ?2")
void setAddress(String address, String username);
First you should create a context as kind of below, you can change db and ORM vendor.Now you have transaction manager. Then use #Transactional annotation on your method.
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="generateDdl" value="true" />
<property name="database" value="HSQL" />
</bean>
</property>
<property name="persistenceUnitName" value="jpa.sample" />
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<jdbc:embedded-database id="dataSource" type="HSQL" />
Related
I've a requirement where it is a dynamic query and JobParameters are build using JobParametersBuilder by setting String, Date, Long etc, but able to read only String values in JdbcCursorItemReader. How can we read other than String in JdbcCursorItemReader so it can be set in PreparedStatement query. Thanks in Advance
With a step-scoped bean and a SpEL expression you can inject and use any type of parameter in your query. Here is an example with a non string parameter from one of the samples:
<bean id="itemReader" scope="step" autowire-candidate="false" class="org.springframework.batch.item.database.JdbcPagingItemReader">
<property name="dataSource" ref="dataSource" />
<property name="rowMapper">
<bean class="org.springframework.batch.sample.domain.trade.internal.CustomerCreditRowMapper" />
</property>
<property name="queryProvider">
<bean class="org.springframework.batch.item.database.support.SqlPagingQueryProviderFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="fromClause" value="CUSTOMER"/>
<property name="selectClause" value="ID,NAME,CREDIT"/>
<property name="sortKeys">
<map>
<entry key="ID" value="ASCENDING"/>
</map>
</property>
<property name="whereClause" value="ID >= :minId and ID <= :maxId"/>
</bean>
</property>
<property name="parameterValues">
<map>
<entry key="minId" value="#{stepExecutionContext[minValue]}"/>
<entry key="maxId" value="#{stepExecutionContext[maxValue]}"/>
</map>
</property>
</bean>
EDIT: Add example with Java configuration style
#Bean
#StepScope
public JdbcCursorItemReader<Person> personReader(#Value("#{jobParameters['id']}") Long id) {
JdbcCursorItemReader<Person> itemReader = new JdbcCursorItemReader<>();
itemReader.setSql("select * from person where id = " + id);
// set other properties on the reader
return itemReader;
}
I want separate the sql from the batch.xml file, so I defined the sql statement into a properties file. Inside the batch.xml I bind the property-placeholder bean then point to the properties file.
For simple select statement should not be a problem. But if I want to pass the parameter as where clause condition is it possible to do that?
<context:property-placeholder
location="classpath:batch-sql.properties/>
<bean id="secondReader"
class="org.springframework.batch.item.database.JdbcCursorItemReader"
scope="step">
<property name="dataSource" ref="dataSource" />
<property name="sql" value="${sql1}" />
<property name="rowMapper">
<bean class="com.test.batchjob.process.TestPersonMapper" />
</property>
</bean>
This is my sql statment in properties file:
SELECT * FROM Person WHERE id = ?
Can the id pass from jobparameter?
To set the parameters of the query in a JdbcPagingItemReader, you have to use the property parametersValue. This property takes a Map<String,Object> where the key is either the named parameter or the index of the parameter (if you use ?).
<bean id="secondReader"
class="org.springframework.batch.item.database.JdbcPagingItemReader"
scope="step">
<property name="queryProvider">
<bean class="org.springframework.batch.item.database.support.SqlPagingQueryProviderFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="selectClause" value="select *" />
<property name="fromClause" value="from persons" />
<property name="whereClause" value="where id = ?" />
</bean>
</property>
<property name="parametersValue">
<map>
<entry key="1" value="#{jobParameters['id']}" />
</map>
</property>
<property name="rowMapper">
<bean class="com.test.batchjob.process.TestPersonMapper" />
</property>
</bean>
See documentation : JdbcPagingItemReader
UPDATE
You have to use a QueryProvider instead of sql and datasource properties.
You can replace the text of the query by values of the properties file.
To set the parameters of the query in a JdbcCursorItemReader, you have to use the property preparedStatementSetter. This property takes a PreparedStatementSetter which you have to implement yourself to set either named or index-based parameters.
<bean id="secondReader"
class="org.springframework.batch.item.database.JdbcCursorItemReader"
scope="step">
<property name="sql" value="${sql1}" />
<property name="itemPreparedStatementSetter">
<bean class="xx.xx.xx.YourPreparedStatementSetter">
<property name="id" value="#{jobParameters['id']}" />
</bean>
</property>
<property name="rowMapper">
<bean class="com.test.batchjob.process.TestPersonMapper" />
</property>
An example implementation of a PreparedStatementSetter :
public class YourPreparedStatementSetter implements PreparedStatementSetter {
private String id;
#Override
public void setValues(PreparedStatement ps) throws SQLException {
ps.setString(1, this.id);
}
public setId(String id) {
this.id = id;
}
}
For JdbcCursorItemReader, you can take a look at answer here : Using Spring Batch JdbcCursorItemReader with NamedParameters
I'm currently trying to get Spring Data JPA to work with two DataSources and thus two EntityManagers. My Repositories all inherit from a custom base class "BaseRepositoryImpl".
Problem:
I always get the following exception:
org.springframework.beans.factory.NoSuchBeanDefinitionException:
No unique bean of type [javax.persistence.EntityManagerFactory] is defined:
expected single bean but found 2: entityManagerFactory1,entityManagerFactory2
Question:
How can I tell my custom RepositoryFactory which EntityManagerFactory to use?
Here's my Spring configuration:
<jpa:repositories base-package="package1" transaction-manager-ref="..."
factory-class="MyFactoryBean"
entity-manager-factory-ref="entityManagerFactory1"/>
<bean id="dataSource1" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="..." />
</bean>
<bean id="entityManagerFactory1" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource1" />
<property name="persistenceUnitName" value="unit1" />
...
</bean>
<jpa:repositories base-package="package2" transaction-manager-ref="..."
factory-class="MyFactoryBean"
entity-manager-factory-ref="entityManagerFactory2"/>
<bean id="dataSource2" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="..." />
</bean>
<bean id="entityManagerFactory2" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource2" />
<property name="persistenceUnitName" value="unit2" />
...
</bean>
The class "MyFactoryBean" is implemented exactly as described at http://docs.spring.io/spring-data/jpa/docs/1.4.x/reference/htmlsingle/#repositories.custom-behaviour-for-all-repositories.
The configuration "entity-manager-factory-ref" seems to be ignored by Spring, at least when using a custom RepositoryFactory.
Any hints?
Entity manager factory is used to create entity managers for different persistence units. You declare your entity manager bean and then give entity manager factory bean as it's class.
This is what worked for me:
<tx:annotation-driven transaction-manager="transactionManager" />
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="defaultEntityManager"/>
</bean>
<bean id="defaultDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${hibernate.connection.driver_class}"/>
<property name="url" value="${db.default.url}"/>
<property name="username" value="${db.default.username}"/>
<property name="password" value="${db.default.password}"/>
</bean>
<bean id="defaultEntityManager" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="defaultDataSource"/>
<property name="persistenceUnitName" value="defaultPersistenceUnit"/>
</bean>
<bean id="otherDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${hibernate.connection.driver_class}"/>
<property name="url" value="${db.other.url}"/>
<property name="username" value="${db.other.username}"/>
<property name="password" value="${db.other.password}"/>
</bean>
<bean id="otherEntityManager" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="otherDataSource"/>
<property name="persistenceUnitName" value="otherPersistenceUnit"></property>
</bean>
Then when you are implementing your data access classes just declare:
#Repository
#Transactional
public class MyDAOImpl implements MyDAO
{
#PersistenceContext(unitName = "defaultPersistenceUnit")
private EntityManager entityManager;
}
and for DAO that uses other persistence unit:
#Repository
#Transactional
public class MyOtherDAOImpl implements MyOtherDAO
{
#PersistenceContext(unitName = "otherPersistenceUnit")
private EntityManager entityManager;
}
I am trying to update the user_info table with the new password using EntityManager.merge(), but it is not getting committed. Below is my code:
app-cofig.xml:
<!-- Application Message Bundle -->
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basename" value="/WEB-INF/messages" />
<property name="cacheSeconds" value="300" />
</bean>
<bean id="loginValidator" class="com.sbi.llms.validator.LoginValidator"/>
<bean id="loginProcessor" class="com.sbi.llms.processor.LoginProcessor">
<property name="userDao" ref="userDao"/>
</bean>
<!-- Resolves view names to protected .jsp resources within the /WEB-INF/views directory -->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
<bean id="forgetProcessor" class="com.test.ForgetPasswordProcessor">
<property name="forgetDao" ref="forgetDao"/>
</bean>
<bean name="/popup_forgot_password.html" class="com.test.ForgetPasswordController">
<property name="processor" ref="forgetProcessor"/>
<property name="commandClass" value="com.test.ForgetPasswordDTO"/>
<property name="commandName" value="btn_reset"/>
<property name="formView" value="popup_forgot_password"/>
<property name="successView" value="popup_forgot_password"/>
<property name="validator">
<bean class="com.test.LoginValidator"/>
</property>
</bean>
<bean id="myDataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="oracle.jdbc.OracleDriver"/>
<property name="url" value="jdbc:oracle:thin:#10.0.27.105:1521/LLMSDB1"/>
<property name="username" value="llms"/>
<property name="password" value="llms12"/>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager" p:entityManagerFactory-ref="entityManagerFactory" />
<bean id="entityManager" class="org.springframework.orm.jpa.support.SharedEntityManagerBean" p:entityManagerFactory-ref="entityManagerFactory" />
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="myDataSource" />
<property name="persistenceUnitName" value="cccPersistenceUnit" />
<property name="jpaDialect" ref="jpaDialect" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter">
<property name="databasePlatform" value="org.eclipse.persistence.platform.database.OraclePlatform"/>
<property name="showSql" value="true"/>
</bean>
</property>
<property name="loadTimeWeaver">
<bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver" />
</property>
</bean>
<bean id="baseJPADao" class="com.sbi.llms.dao.jpa.BaseJPADAO">
<property name="entityManager" ref="entityManager"/>
</bean>
<bean id="userDao" class="com.sbi.llms.dao.UserDAO">
<property name="entityManager" ref="entityManager"/>
</bean>
<bean id="forgetDao" class="com.test.ForgetPasswordDAO">
<property name="entityManager" ref="entityManager"/>
</bean>
<bean id="jpaDialect" class="org.springframework.orm.jpa.vendor.EclipseLinkJpaDialect" />
persistance.xml
<?xml version="1.0" encoding="UTF-8" ?>
<persistence xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
version="2.0" xmlns="http://java.sun.com/xml/ns/persistence">
<persistence-unit name="cccPersistenceUnit" transaction-type="RESOURCE_LOCAL"> <!-- "RESOURCE_LOCAL" -->
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<mapping-file>META-INF/LoginModel.xml</mapping-file>
<mapping-file>META-INF/eclipselink-orm.xml</mapping-file>
<class>com.sbi.llms.model.LoginModel</class>
<class>com.test.ForgetPasswordModel</class>
<properties>
<!-- Configure cache size. -->
<property name="eclipselink.cache.size.default" value="1000" />
<!-- Configure simple SQL logging for demonstration. -->
<property name="eclipselink.logging.level" value="FINE" />
<property name="eclipselink.logging.thread" value="false" />
<property name="eclipselink.logging.session" value="false" />
<property name="eclipselink.logging.exceptions" value="false" />
<property name="eclipselink.logging.timestamp" value="false" />
</properties>
</persistence-unit>
</persistence>
Here is my DAO
public class ForgetPasswordDAO {
private Vector loginResult = null;
private int resultTrue = 1;
private int resultFalse = 0;
protected EntityManager entityManager;
JpaEntityManager jpaEntityManager;
public ForgetPasswordDAO() {
}
public EntityManager getEntityManager() {
return entityManager;
}
public void setEntityManager(EntityManager entityManager) {
this.entityManager = entityManager;
}
public Integer fetchUser(ForgetPasswordModel model) throws Exception {
try {
ForgetPasswordDTO DTO ;
if(model == null) {
throw new Exception("102");
}
Integer result = 0;
String userName = model.getUser_id();
String dob = model.getDob();
System.out.println("UserDTO " + model.getUser_id() + " "
+ model.getDob());
ForgetPasswordModel forgetModel = null;
System.out.println(entityManager.isOpen()+">>");
forgetModel = entityManager.find(ForgetPasswordModel.class, model.getUser_id());
entityManager.close();
System.out.println("UserDAO " + forgetModel.getUser_id() + " DOB "
+ forgetModel.getDob()+" EMAIL_ID "+forgetModel.getEmail_id()+" PASSWORD "+forgetModel.getPasswd());
if(model.getDob().equals(forgetModel.getDob())) {
System.out.println("USER VALID , CAN PROCEED WITH PASSWORD RESET");
String passwd = GenerateRandomPassword.generateRandomPassword();
System.out.println("generated password is" +passwd);
entityManager.getTransaction().begin();
forgetModel.setPasswd(passwd);
entityManager.merge(forgetModel);
entityManager.getTransaction().commit();
System.out .println("updated password is "+forgetModel.getPasswd());
String email=forgetModel.getEmail_id();
ForgetPasswordSendMail.SendMail( email, passwd);
result=1;
}
else
{
System.out.println("USER InVALID , Please Provide Valid Data");
}
return result;
} catch (Exception e) {
throw new Exception("103", e);
}
}
}
When I run the above code I get the following error:
java.lang.IllegalStateException: Not allowed to create transaction on shared EntityManager - use Spring transactions or EJB CMT instead
org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:198)
com.sun.proxy.$Proxy6.getTransaction(Unknown Source)
com.test.ForgetPasswordDAO.fetchUser(ForgetPasswordDAO.java:81)
com.test.ForgetPasswordProcessor.execute(ForgetPasswordProcessor.java:52)
com.test.ForgetPasswordController.onSubmit(ForgetPasswordController.java:56)
org.springframework.web.servlet.mvc.SimpleFormController.processFormSubmission(SimpleFormController.java:272)
org.springframework.web.servlet.mvc.AbstractFormController.handleRequestInternal(AbstractFormController.java:268)
org.springframework.web.servlet.mvc.AbstractController.handleRequest(AbstractController.java:153)
org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter.handle(SimpleControllerHandlerAdapter.java:48)
org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:790)
org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:719)
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:644)
org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:560)
javax.servlet.http.HttpServlet.service(HttpServlet.java:641)
javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
Since you are using Spring, you need to use Spring transactions, not JPA transactions.
You need to declare the transaction in Spring, or access the EntityManager directly, not through Spring.
I have problem with simple spring mvc controller written in scala:
#Controller
class HelloWorldController {
implicit def sessionFactory2Session(sf: SessionFactory) = sf.getCurrentSes
#Autowired
var sessionFactory: SessionFactory = null
#Transactional
#RequestMapping(value=Array("/hello.html"),method = Array(RequestMethod.GET,RequestMethod.POST))
def showHello = {
val document = new CustomDocument("name","custom")
sessionFactory.save(document)
sessionFactory.flush
"helloPage"
}
}
When I tried to access /hello.html I received exception:
javax.servlet.ServletException: No adapter for handler: Does your handler implement a supported interface like Controller?
at org.springframework.web.servlet.DispatcherServlet.getHandlerAdapter(DispatcherServlet.java:951)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:758)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:717)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:644)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:549)
But when I removed #Transactional annotation - everything works!!. Spring can't find request mapping with two annotations? My applicationContext.xml fragment:
<bean id="openSessionInViewInterceptor"
class="org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
<property name="interceptors">
<list><ref bean="openSessionInViewInterceptor"/></list>
</property>
<property name="alwaysUseFullPath" value="true" />
</bean>
<context:component-scan base-package="scala.hibernate"/>
<bean id="viewResolver" class="org.springframework.web.servlet.view.UrlBasedViewResolver">
<property name="viewClass"
value="org.springframework.web.servlet.view.JstlView"/>
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
<!-- for transaction -->
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManaager">
<property name="sessionFactory" ref="sessionFactory"/>
<property name="dataSource" ref="dataSource"/>
</bean>
<tx:annotation-driven/>
EDIT
Transactional aspect is applied using dynamic proxy, and it prevents Spring MVC from accessing the #RequestMapping annotations on the target class
Solution:
<tx:annotation-driven proxy-target-class="true"/>
Try adding <context:annotation-config /> to your applicationContext.xml and see if that fixes the problem.
declare following bean . this should solve the problem
<bean id="simpleHandler" class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
will update you once find out the root cause..