Environment: Eclipse Keppler, jetty 7.5.1,
Spring 3.2.1, Hibernate 4.2.5, Oracle 11
Problem: hibernate entity saves does not apply to database physically
Cause of problem may be: no active transaction
Question: Why does not transaction start?
Note: if I change openSession() to getCurrentSession(), everything works. Transaction starts & entity saves to DB physically.
GenericDaoImpl:
#Transactional(propagation = Propagation.REQUIRED, readOnly = false,
value = "transactionManager")
public abstract class GenericDaoImpl<T, ID extends Serializable> implements GenericDao<T, ID> {
private Class<T> persistentClass;
protected SessionFactory sessionFactory;
#Override
public T addEntity(T entity) {
Session session = null;
try {
session = sessionFactory.openSession();
session.save(entity);
} catch (Exception e) {
e.printStackTrace();
} finally {
if(session != null){
Transaction t = session.getTransaction();
System.out.println("Transaction().isActive()......." + session.getTransaction().isActive());
System.out.println("before: session.isOpen() " + session.isOpen() + " trx wasCommitted " + t.wasCommitted());
session.close();
System.out.println("after: session.isOpen() " + session.isOpen() + " trx wasCommitted" + t.wasCommitted());
}
}
return entity;
}
UserDaoImpl extending GenericDaoImpl:
#Component
#Scope("prototype")
#Transactional(propagation = Propagation.REQUIRED, readOnly = false, value = "transactionManager")
public class UserDaoImpl extends GenericDaoImpl<User, Long> implements UserDao {
.
.
}
After following code executed called:
userDao.addEntity(user);
logs printed below:
Transaction().isActive().......false
before: session.isOpen() true trx wasCommitted false
after: session.isOpen() false trx wasCommittedfalse
transaction logs:
[2016-07-15 10:42:04,567][DEBUG] Adding transactional method 'addEntity' with attribute: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; 'transactionManager'
databaseContext.xml:
<bean class="com.blabla.dao.local.implementations.UserDaoImpl"
scope="prototype" name="userDao">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<tx:annotation-driven />
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan"
value="com.blabla.model.local,com.blabla.model.authorization, com.blabla.model.authentication" />
<property name="entityInterceptor">
<bean class="com.blabla.listeners.EntityInterceptor" />
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.transaction.flush_before_completion">true</prop>
<prop key="hibernate.cache.provider_class">org.hibernate.cache.HashtableCacheProvider</prop>
<prop key="hibernate.connection.driver_class">${jdbc.driver}</prop>
<prop key="hibernate.connection.url">${jdbc.url}</prop>
<prop key="hibernate.connection.username">${jdbc.user}</prop>
<prop key="hibernate.connection.password">${jdbc.password}</prop>
</props>
</property>
</bean>
<bean id="dataSource" class="org.apache.tomcat.jdbc.pool.DataSource"
destroy-method="close">
<property name="driverClassName" value="${jdbc.driver}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.user}" />
<property name="password" value="${jdbc.password}" />
<property name="initialSize" value="5" />
<property name="maxActive" value="10" />
</bean>
In your example it's pretty much obvious that spring handles hibernate session and transaction:
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
So you cannot use this:
session = sessionFactory.openSession();
Because you are opening new hibernate session and spring does not know nothing about this.
Using: sessionFactory.getCurrentSession() means that spring will handle everything behind the scene with your proper configuration.
Related
I have a problem with transaction auto committed after call another dao native query.
Both service and dao signed as #Transactional.
What am I doing wrong here?
Spring 4.2.x
Hibernate 5.1.0
Atomikos 3.9.3
This is my setup:
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="jtaPlatformAdapter" class="com.xxx.JtaPlatformAdapter">
<property name="jtaTransactionManager" ref="transactionManager" />
</bean>
<bean class="com.atomikos.icatch.jta.UserTransactionManager" destroy-method="close" id="atomikosTransactionManager" init-method="init">
<property name="forceShutdown" value="true" />
<property name="startupTransactionService" value="true" />
</bean>
<bean class="com.atomikos.icatch.jta.UserTransactionImp" id="atomikosUserTransaction" />
<bean class="org.springframework.transaction.jta.JtaTransactionManager" id="transactionManager">
<property name="transactionManager" ref="atomikosTransactionManager" />
<property name="userTransaction" ref="atomikosUserTransaction" />
</bean>
<bean id="datasouce" class="com.jolbox.bonecp.BoneCPDataSource" destroy-method="close">
...
</bean>
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" id="JPAVendorAdapter">
...
</bean>
<bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="emf" depends-on="transactionManager,jtaPlatformAdapter">
<property name="persistenceXmlLocation" value="classpath:META-INF/persistence.xml" />
<property name="packagesToScan" value="com.xxx.server"/>
<property name="dataSource" ref="datasouce" />
<property name="persistenceUnitName" value="pun" />
<property name="jpaVendorAdapter" ref="JPAVendorAdapter" />
<property name="jpaPropertyMap">
<map>
<entry key="hibernate.connection.release_mode" value="on_close" />
<entry key="hibernate.transaction.jta.platform" value="com.xxx.server.JtaPlatformAdapter" />
</map>
</property>
</bean>
persistence.xml
<persistence-unit name="pun" transaction-type="JTA">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
service
#Transactional
#Scope("prototype")
public synchronized void save(EntityObj model) throws Exception {
model.setX(30);
model.setY(40);
EntityObj oldModel = entityObjDAO.findById(model.getId());
// after call findById, the model had been commit to DB
...
...
...
entityObjDAO.store(model); // this will call entityManager.merge(model)
entityObjDAO.flush();
}
DAO
#Transactional
public EntityObj findById(String id) {
EntityObj model = null;
String sql = "select id,x,y from EntityObj where id = :id"; // this is a native sql query
Query query = this.entityManager.createNativeQuery(sql);
query.setParameter("id", id);
Object[] rs = (Object[]) query.getSingleResult();
if (rs != null) {
model = new EntityObj();
model.setId(id);
model.setX(rs[1] == null ? null : (Integer) rs[1]);
model.setY(rs[2] == null ? null : (Integer) rs[2]);
}
return model;
}
thanks!
If you are using #Transactional in your code, Spring creates a proxy object for your Dao object (wrapper).
So it looks like this if your application is running:
public EntityObj proxyMethodForFindById(String id) {
try {
// 1. start transaction
startTransaction();
// 2. execute your code
return yourDaoObject.findById(id);
} finally { // [!] PSEUDO CODE: NO EXCEPTION HANDLING
// commit transaction
commitTransaction();
}
}
So what happens in your code?
Your save method is marked also as #Transactional. So if you are changing your object by setting:
model.setX(30);
model.setY(40);
Spring creates two proxies. One for Service and one four your Dao. On the End of the findById-Transaction this changes will be commited. Nested transactions is the keyword.
You should remove #Transaction in your findById-Method or better in the whole Dao object. Service should be transactional, not Dao-layer.
I'm trying to implement LDAP transaction using Spring.I have configured the spring xml based on the spring Doc, but while running the program i'm getting below mentioned error:
java.lang.IllegalStateException: No value for key [org.springframework.ldap.core.support.LdapContextSource#27bd27bd] bound to thread [main]
at org.springframework.transaction.support.TransactionSynchronizationManager.unbindResource(TransactionSynchronizationManager.java:199)
at org.springframework.transaction.compensating.support.AbstractCompensatingTransactionManagerDelegate.doCleanupAfterCompletion(AbstractCompensatingTransactionManagerDelegate.java:122)
at org.springframework.ldap.transaction.compensating.manager.ContextSourceTransactionManager.doCleanupAfterCompletion(ContextSourceTransactionManager.java:135)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.cleanupAfterCompletion(AbstractPlatformTransactionManager.java:1011)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processRollback(AbstractPlatformTransactionManager.java:877)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.rollback(AbstractPlatformTransactionManager.java:822)
at org.springframework.transaction.interceptor.TransactionAspectSupport.completeTransactionAfterThrowing(TransactionAspectSupport.java:411)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:114)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)
at $Proxy11.createUser(Unknown Source)
Note:I'm trying to rollback LDAP as well as DB.
Code snippet:
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.apps.ldap.manager.UserManger;
import com.apps.ldap.model.UserBean;
public class SpringFrameworkLDAPClient {
private static ApplicationContext context = null;
public static void main(String[] args) {
try {
context = new ClassPathXmlApplicationContext("conf/springldap.xml");
UserManger userservice = (UserManger)context.getBean("userManger");
UserBean userbean = new UserBean();
userbean.setCommonName("Santhosh5");
userbean.setLastName("Rajendran5");
userbean.setEmail("rsanthoshkumarr#gmail.com");
userbean.setFirstName("Santhosh5");
userbean.setUserID("Santhosh5");
userservice.createuser(userbean);
} catch (Exception e) {
System.out.println("Error occured " + e);
e.printStackTrace();
}
}
}
UserService
#Transactional
public void createuser(UserBean contactDTO) {
Attributes personAttributes = new BasicAttributes();
BasicAttribute personBasicAttribute = new BasicAttribute("objectclass");
personBasicAttribute.add("person");
personAttributes.put(personBasicAttribute);
personAttributes.put("cn", contactDTO.getCommonName());
personAttributes.put("sn", contactDTO.getLastName());
DistinguishedName newContactDN = new DistinguishedName("ou=users");
newContactDN.add("cn", contactDTO.getCommonName());
ldapTemplate.bind(newContactDN, null, personAttributes);
}
XML:
<bean id="contextSourceTarget" class="org.springframework.ldap.core.support.LdapContextSource">
<property name="url" value="ldap://xxxx:389" />
<property name="base" value="dc=xxx" />
<property name="userDn" value="cn=xxx" />
<property name="password" value="xxx" />
</bean>
<bean id="contextSource" class="org.springframework.ldap.transaction.compensating.manager.TransactionAwareContextSourceProxy">
<constructor-arg ref="contextSourceTarget" />
</bean>
<bean id="ldapTemplate" class="org.springframework.ldap.core.LdapTemplate">
<constructor-arg ref="contextSource" />
</bean>
<bean id="transactionManager" class="org.springframework.ldap.transaction.compensating.manager.ContextSourceTransactionManager">
<property name="contextSource" ref="contextSource" />
</bean>
<bean id="contactDao" class="com.apps.ldap.daos.impl.Userservice">
<property name="ldapTemplate" ref="ldapTemplate" />
</bean>
<bean id="myDataAccessObject" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager" ref="transactionManager" />
<property name="target" ref="contactDao" />
<property name="transactionAttributes">
<props>
<prop key="*">PROPAGATION_REQUIRES_NEW</prop>
</props>
</property>
</bean>
JARs used:
apache-commons-lang.jar
commons-logging-1.1.1.jar
ibatis-2.3.0.677.jar
jt400.jar
ldapbp-1.0.jar
org.springframework.aop-3.0.5.RELEASE.jar
org.springframework.asm-3.0.5.RELEASE.jar
org.springframework.beans-3.0.5.RELEASE.jar
org.springframework.context-3.0.5.RELEASE.jar
org.springframework.expression-3.0.5.RELEASE.jar
org.springframework.jdbc-3.0.5.RELEASE.jar
org.springframework.oxm-3.0.5.RELEASE.jar
org.springframework.test-3.0.5.RELEASE.jar
org.springframework.transaction-3.0.5.RELEASE.jar
org.springframework.web-3.0.5.RELEASE.jar
spring-core-3.0.4.RELEASE.jar
spring-ldap-1.1.2.jar
spring-ldap-core-1.3.2.RELEASE.jar
spring.jar
SpringUtils-0.2.jar
I have created a oracle datasource in weblogic with the name jdbc/myDS.
Weblogic created a xml file in mydomain/config/jdbc and the configuration works from the weblogic admin console. Test connection is working. My spring context file details are:
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="jdbc/myDS"/>
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="hibernateProperties">
<util:map>
<entry key="hibernate.hbm2ddl.auto" value="update" />
<entry key="hibernate.show_sql" value="true" />
</util:map>
</property>
</bean>
<bean id="myDAO" class ="com.example.MyDAOImpl">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
My Java class is:
public class MyDAOImpl implements MyDAO{
private SessionFactory sessionFactory;
public void setSessionFactory(SessionFactory sessionFactory){
this.sessionFactory = sessionFactory;
}
public SessionFactory getSessionFactory() {
return sessionFactory;
}
public void persistPerson(Person person) {
Session session = getSessionFactory().openSession();
try {
session.beginTransaction();
session.save(person);
session.getTransaction().commit();
}catch(HibernateException he) {
he.printStackTrace();
} finally {
session.close();
}
}
}
An error occurred during activation of changes, please see the log for
details.
Message icon - Error weblogic.application.ModuleException:
Message icon - Error While trying to lookup 'jdbc.myDS' didn't find subcontext 'jdbc'. Resolved ''; remaining name 'jdbc/myDS'
The following provides a Spring XML configuration to obtain a datasource by a JNDI name and inject it into Springs AnnotationSessionFactoryBean.
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="jdbc/YourJndi"/>
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource">
<ref bean="dataSource" />
</property>
<property name="annotatedClasses">
<list>
<value>com.java.model.Employee</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
<prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop>
</props>
</property>
</bean>
This example has been sucessfully tested on Weblogic 10.3.4 with Oracle 11g.
I am new to Spring but in general I am aware of it's features so I decided to use it in one of my projects. Main problem however is with Hibernate. Before this idea of introducing spring the premise is this:
My application (not web) had to connect to a DB and gather information from it using "persistence_1.xml" with it's own set of entity classes. In other words everything related to "persistence_1.xml" was read only so that no tragedies would occur. Also "persistence_1.xml" with persistence-unit of name "p1" came from web-app dependencies. So picture is this: my app (not-web) written with the support of maven, took dependencies of the other application to access database and gather information.
And the other "persistence_2.xml" with persistence-unit name of "p2" and it's own subset of entities was created by me to store gathered and processed information into the same database.
So originally I had two entity managers one responsible for "p1" another for "p2".
I have seen some material on the internet where they show how to configure two entity managers with different dataSources but I can not figure out how to create two entity managers in SPRING using their own set of ENTITIES.
Let's say "test" is only associated with "UserEntity" and "dummy" is only associted with "DumbEntity".
Now everything get's mashed up along the way and no matter which PU name I type in in #PersistenceContext(name = "test") - it can query for any entity in database.
This is example of persistence.xml:
<persistence-unit name="test" type="RESOURCE_LOCAL">
<class>org.test.db.UserEntity</class>
</persistence-unit>
<persistence-unit name="dummy" type="RESOURCE_LOCAL">
<class>org.test.db.DumbEntity</class>
</persistence-unit>
Bean definition:
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="url" value="jdbc:mysql://localhost:3306/spring"/>
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="username" value="root"/>
<property name="password" value=""/>
</bean>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="persistenceUnitName" value="test" />
<property name="persistenceXmlLocation" value="classpath:META-INF/persistence.xml" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="generateDdl" value="true" />
<property name="showSql" value="true" />
<property name="databasePlatform" value="org.hibernate.dialect.MySQL5Dialect" />
</bean>
</property>
</bean>
<bean id="entityManagerFactory2" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="persistenceUnitName" value="dummy" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="generateDdl" value="true" />
<property name="showSql" value="true" />
<property name="databasePlatform" value="org.hibernate.dialect.MySQL5Dialect" />
</bean>
</property>
</bean>
<tx:annotation-driven/>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<bean id="transactionManager2" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory2"/>
</bean>
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>
<bean name="userDao" class="org.test.services.UserDaoImpl" />
My UserDaro service
public class UserDaoImpl implements UserDao {
#PersistenceContext(unitName = "test")
private EntityManager entityManager;
public UserDaoImpl() {
}
public UserDaoImpl(EntityManager entityManager) {
this.entityManager = entityManager;
}
#Transactional(propagation = Propagation.REQUIRES_NEW)
#Override
public void saveUser(UserEntity user) {
entityManager.persist(user);
}
#Transactional(propagation = Propagation.REQUIRES_NEW)
#Override
public void saveUser(DumbEntity user) {
entityManager.persist(user);
}
#Override
public List<UserEntity> fetchAllUsers() {
String sql = "FROM UserEntity";
Query query = entityManager.createQuery(sql);
return query.getResultList();
}
#Override
public List<DumbEntity> fetchAllUsers2() {
String sql = "FROM DumbEntity";
Query query = entityManager.createQuery(sql);
return query.getResultList();
}
public void setEntityManager(EntityManager entityManager) {
this.entityManager = entityManager;
}
}
In any way whether or not I use fetchAllUsers() or fetchAllUsers2() I get the result, but I would like that each of these would only work with entityManager that only has the knowledge about about specific entities.
I would like you to share your thoughts on this one. Thank You.
<bean id="configProperties" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="placeholderPrefix" value="${" />
<property name="placeholderSuffix" value="}" />
<property name="locations">
<value>classpath:ddes/config.properties</value>
</property>
</bean>
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="${datasource}"/>
<property name="resourceRef" value="true"/>
</bean>
<context:load-time-weaver weaver-class="org.springframework.instrument.classloading.weblogic.WebLogicLoadTimeWeaver"/>
<bean id="PersistenceUnit" class="org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager">
<property name="defaultDataSource" ref="dataSource"/>
<property name="class">
<!--LIST BEANS-->
<value>....</value>
</property>
</bean>
<bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter">
<property name="databasePlatform" value="org.eclipse.persistence.platform.database.OraclePlatform"/>
<property name="generateDdl" value="true"/>
<property name="showSql" value="true"/>
</bean>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="jpaVendorAdapter" ref="jpaVendorAdapter"/>
<property name="persistenceUnitManager" ref="PersistenceUnit"/>
<property name="persistenceUnitName" ref="Persistence-ejbPU"/>
<property name="persistenceProvider" ref="org.eclipse.persistence.jpa.PersistenceProvider"/>
</bean>
<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="transactionManager" ref="entityManagerFactory"/>
</bean>
implement
#CallByReference
#Stateless(mappedName = "cliente")
public class ClienteDAOBean implements ClienteDAOLocal, ClienteDAORemote {
#PersistenceUnit(unitName = "Persistence-ejbPU")
private EntityManagerFactory emf;
public Clientes find(Integer codCliente) throws Exception {
Clientes cliente = null;
EntityManager em = emf.createEntityManager();
try {
javax.persistence.Query q = em.createNamedQuery("Clientes.findByCodCliente").setParameter("codCliente", codCliente);
cliente = (Clientes) q.getSingleResult();
} catch (Exception e) {
throw e;
} finally {
em.close();
return cliente;
}
}
}
Pero al iniciar la aplicaciĆ³n el log arroja este error:
No persistence unit named 'Persistence-ejbPU' is available in scope Persistence-ejbPU.jar
was previously using a persistence.xml file but needed the name of the datasource out dynamic
Simply replace ref with value. Use:
<property name="persistenceUnitName" value="Persistence-ejbPU" />
instead of:
<property name="persistenceUnitName" ref="Persistence-ejbPU"/>
If you are having still problem then I would implement my own LocalContainerEntityManagerFactoryBean class which extends from AbstractEntityManagerFactoryBean so you can override setPersistenceUnitName then see what is going on.