#Transactional doesn't open Hibernate Transaction - java

I declared Spring Beans in my beans.xml:
<context:annotation-config />
<context:component-scan base-package="com.pack"/>
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
<property name="dataSource" ref="dataSource"></property>
</bean>
dataSource and sessionFactory beans:
#Bean(name = "dataSource")
public DriverManagerDataSource dataSource() {
DriverManagerDataSource ds = new DriverManagerDataSource();
ds.setUsername(userName);
ds.setPassword(password);
ds.setDriverClassName(driverName);
ds.setUrl(url);
return ds;
}
#Bean(name = "sessionFactory")
public LocalSessionFactoryBean localSessionFactoryBean() {
LocalSessionFactoryBean factory = new LocalSessionFactoryBean();
factory.setDataSource(dataSourceConfiguration.dataSource());
Properties props = new Properties();
props.put("hibernate.dialect", "org.hibernate.dialect.MySQLDialect");
props.put("hibernate.hbm2ddl.auto", "update");
props.put("hibernate.current_session_context_class", "thread");
factory.setHibernateProperties(props);
factory.setMappingResources("com/pack/Item.hbm.xml");
return factory;
}
If I use sessionFactory and dataSource beans separately they work well. A also have DAO class:
#Repository(value = "itemDaoHibernateImpl")
public class ItemDaoHibernateImpl implements ItemDao {
#Resource(name = "sessionFactory")
private SessionFactory factory;
public void setFactory(SessionFactory factory) {
this.factory = factory;
}
public Session session() {
return factory.getCurrentSession();
}
#Override
public void create(Item item) {
session().save(item);
}
I don't open the sessions because I want to force Spring to do this. I have Service class with method:
#Override
#Transactional
public void create(Item item) {
dao.create(item);
}
When I call it, I have the exception:
org.hibernate.HibernateException: save is not valid without active transaction
I've done like this tutorial tells. Where is my mistake?

Try to remove props.put("hibernate.current_session_context_class", "thread") from your sessionFactory configuration. When you are using Spring managed transactions, you don't need it. Let me know if that works.

When I have come across this before it is due to whether Spring is using CGLib or Javassist to augment your class to provide transactionality. if I remember correctly if you only have Javassist in then the class that Spring needs to create the proxy on in order to implement the Transactional annotation must implement an interface.

Related

Spring + Jboss7 #Transactional Not working

I am upgrading my JBoss server from 5 to 7 and am now incorporating Spring 4. I am having some trouble using Spring's #Transactional annotation. It does not appear to be working. I am also trying to use a java based configuration file instead of an xml file (I believe I can get away without using any xml, but correct me if I am wrong). The problem is that nothing is being saved in my db, leading me to believe that the #Transactional isn't working. Here is my config file:
#Configuration
#ComponentScan
#EnableTransactionManagement
public class SpringBeanConfiguration {
#Bean
public FirstTestBean firstTestBean() {
return new FirstTestBean();
}
#Bean
public TestService testService() {
return new TestServiceImpl();
}
#Bean
public SomethingDAO somethingDAO(){
return new SomethingDAOImpl();
}
#Bean
public GeneralDAO generalDAO(){
return new GeneralDAOImpl();
}
Here is a test class with the #Transactional method:
//#RequestScoped
#ManagedBean(name="firstTestBean")
#Component
public class FirstTestBean {
private EntityManager em;
private EntityManagerFactory emf;
#Transactional
public String transactionalTest() {
//ApplicationContext context = new AnnotationConfigApplicationContext(SpringBeanConfiguration.class);
Something something = new Something();
getEntityManager().persist(something);
return "dkljs";
}
public EntityManager getEntityManager() {
if (em == null) {
emf = Persistence.createEntityManagerFactory("xxx");
em = emf.createEntityManager();
}
return em;
}
I am also using Hibernate 4, which is compatible with Spring. I commented out the ApplicationContext because I have that running separately on the start up of JBoss. I was using that earlier to access a bean, but I have since simplified things in order to get the #Transactional working and thus do not need it here. The #ComponentScan does not need parameters because these classes are in the same package.
Any help would be greatly appreciated. Thanks!
Updates
I've made some of the changes suggested. Things appear to be moving in the right direction.
Here are my updated files:
#ManagedBean(name="firstTestBean")
public class FirstTestBean {
public String getTestString() {
ApplicationContext context = new AnnotationConfigApplicationContext(SpringBeanConfiguration.class);
TestService testService = context.getBean(TestService.class);
testService.transactionalTest();
return "adfs";
}
public String test() {
return "firstTestBean works";
}
}
Note - some of these classes will be run outside of the Jboss application server as standalone applications, so for that reason, I am staying away from FacesContext when instantiating the TestService in FirstTestBean, as Spring beans work in standalone, but FacesContext beans do not.
#Component
#Transactional
public class TestServiceImpl implements TestService {
public GeneralDAO generalDAO;
//#Autowired
private EntityManager em;
//#Autowired
private EntityManagerFactory emf;
public TestServiceImpl(){}
public String transactionTest() {
Something something = new Something();
getEntityManager().persist(something);
return "dkljs";
}
#autowired on the EntityManager and EntityManagerFactory did not work - I received an error saying No Qualified Bean of type EntityManager when it was annotated with the #autowired like suggested.
#Configuration
#ComponentScan
#EnableTransactionManagement
public class SpringBeanConfiguration implements TransactionManagementConfigurer {
#Override
public PlatformTransactionManager annotationDrivenTransactionManager() {
String hibernatePropsFilePath = "/[path]/hibernate.cfg.xml";
File hibernatePropsFile = new File(hibernatePropsFilePath);
org.hibernate.cfg.Configuration cfg = new org.hibernate.cfg.Configuration().configure(hibernatePropsFile);
SessionFactory sessionFactory = cfg.buildSessionFactory();
HibernateTransactionManager txManager = new HibernateTransactionManager(sessionFactory);
txManager.setNestedTransactionAllowed(true);
return txManager;
}
}
The error I am getting now is:Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.context.event.internalEventListenerProcessor': Initialization of bean failed
; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration':
Injection of autowired dependencies failed; nested exception is org.hibernate.service.UnknownUnwrapTypeException: Cannot unwrap to requested type [javax.sql.DataSource]
I take it this means that the #Transactional is at least being recognized, but I'm having some issues getting this to work. Any further advice would be greatly appreciated.
More Updates
Found this article: http://www.baeldung.com/the-persistence-layer-with-spring-and-jpa#javaconfig
and followed it. My new config file:
#Configuration
#ComponentScan
#EnableTransactionManagement
public class SpringBeanConfiguration { //implements TransactionManagementConfigurer {
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(dataSource());
em.setPackagesToScan(new String[] { "xxx.xxx.xxx" });
JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
// em.setJpaProperties(additionalProperties());
return em;
}
#Bean
public DataSource dataSource(){
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/jboss_test");
dataSource.setUsername( "root" );
dataSource.setPassword( "root" );
return dataSource;
}
#Bean
public PlatformTransactionManager transactionManager(EntityManagerFactory emf){
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(emf);
return transactionManager;
}
#Bean
public PersistenceExceptionTranslationPostProcessor exceptionTranslation(){
return new PersistenceExceptionTranslationPostProcessor();
}
Good news is that I am no longer having deployment issues. The logging also suggests that my changes are having some effect on the server. Unfortunately, nothing is being saved, so it is still not quite working.
The first thing that draws my attention is the use of #Transactional and #Component on a ManagedBean.
JSF and Spring are definately made to work together but i never saw them used this way on many projects i was working on.
Im not sure if that is the cause of your problems but please consider changing that.
I would do like this:
a) Define some service layer where you would wrap your calls with transactions and inject the JPA classes:
#Component
#Transactional
class Service{
#Autowired
private EntityManager em;
#Autowired
private EntityManagerFactory emf;
public String serviceMethod(..){ .. }
}
b) Inject that to Jsf's ManagedBean while removing the unnecessary annotations:
#ManagedBean(name="firstTestBean")
public class FirstTestBean {
#ManagedProperty("#{service}")
private Service service;
public String transactionalTest() {
return service.serviceMethod();
}
}
Ok, so I finally got it (Check out my OP for all updates that led me to this point).
Here's my final config file:
#Configuration
#ComponentScan
#EnableTransactionManagement
public class SpringBeanConfiguration {
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setPersistenceUnitName("myPersistenceContext");
em.setDataSource(dataSource());
em.setPackagesToScan(new String[] { "xxx.xxx.xxx" });
JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
// em.setJpaProperties(additionalProperties());
return em;
}
#Bean
public DataSource dataSource(){
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/jboss_test");
dataSource.setUsername( "root" );
dataSource.setPassword( "root" );
return dataSource;
}
#Bean
public PlatformTransactionManager transactionManager(EntityManagerFactory emf){
JtaTransactionManager transactionManager = new JtaTransactionManager();
// transactionManager.setEntityManagerFactory(emf);
return transactionManager;
}
#Bean
public PersistenceExceptionTranslationPostProcessor exceptionTranslation(){
return new PersistenceExceptionTranslationPostProcessor();
}
So first, I added in
em.setPersistenceUnitName("myPersistenceContext");
This gave me the error:
Spring IllegalStateException: A JTA EntityManager cannot use getTransaction()
From here, I did some research (Spring IllegalStateException: A JTA EntityManager cannot use getTransaction())
and changed
JpaTransactionManager transactionManager = new JpaTransactionManager();
to
JtaTransactionManager transactionManager = new JtaTransactionManager();
Also, my persistence.xml file is:
<persistence-unit name="myPersistenceContext">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<jta-data-source>java:jboss/datasources/myDS</jta-data-source>
<class>xxx.xxx.xxx.Something</class>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties>
<property name="hibernate.cache.use_second_level_cache" value="true" />
<property name="hibernate.id.new_generator_mappings" value="false"/>
<property name="hibernate.classloading.use_current_tccl_as_parent" value="false"/>
<property name="hibernate.transaction.jta.platform" value="org.hibernate.service.jta.platform.internal.JBossAppServerJtaPlatform" />
<property name="hibernate.show_sql" value="true" />
<property name="hibernate.archive.autodetection" value="class, hbm" />
</properties>
</persistence-unit>
Thanks to Maciej Kowalski for your help - you pushed me in the right direction.

How to use #Autowired instead of manually loading Spring beans?

I have a small Java application which connects to a MySQL database. For database connectivity ONLY, I'd like to use Spring to manage a JNDI based connection pool.
I have a working implementation for the above but this requires manually loading the JNDI connection bean, whereas I'd like to use #Autowired.
How can I convert my working code to one that uses #Autowired to get the JNDI connection ?
This is my beans.xml file (inside src/main/resources folder):
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns= ....>
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:comp/env/jdbc/Database"/>
</bean>
<bean id="databaseMapper2Impl"
class="com.dataaccess.DatabaseMapper2Impl">
<property name="dataSource" ref="dataSource" />
</bean>
</beans>
The is a section of my DatabaseMapper2Impl class:
public class DatabaseMapper2Impl {
private DataSource dataSource;
private JdbcTemplate jdbcTemplateObject;
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
this.jdbcTemplateObject = new JdbcTemplate(dataSource);
}
public OrderDTO getOrder(String orderNumber, String envToUse) {
String getOrderSql = "SELECT * FROM REPORTING.ORDER where ORDER_NUMBER = ? limit 1";
List<OrderDTO> orders = jdbcTemplateObject.query(getOrderSql, new Object[] { orderNumber }, new OrderMapper());
if (orders == null || orders.isEmpty()) {
return null;
} else {
return orders.get(0);
}
}
}
This is the class where the JNDI connection bean is manually instantiated:
public class DataDelegateImpl {
public OrderDTO getOrder(String orderNumber, String envToUse) {
ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
DatabaseMapper2Impl x = (DatabaseMapper2Impl) context.getBean("databaseMapper2Impl");
return x.getOrder(orderNumber, envToUse);
}
}
In order for Spring to manage the instantiation and injection of your DatabaseMapper2Implbean, you will have to create an ApplicationContext, and declare the bean in that context, exactly as you have done.
If the question is just how to avoid using XML for that declaration, you could annotate DatabaseMapper2Impl with #Component and instead use
ApplicationContext context = new AnnotationConfigApplicationContext(DatabaseMapper2Impl.class);
to create the context.
If you really need to have the DatabaseMapper2Impl #Autowired into an instance of DataDelegateImpl, then that instance would also have to be controlled by Spring, so you'd have to create the context at a higher level and make the DataDelegateImpl a bean as well.

How to use spring transaction manager in case of dynamic data source?

I have a scenario where datasource are dynamically created using Datasource Factory. So depending upon who accesses the system, DatasourceFacory(custom datasource factory) returns a corresponding datasource.
Now, with this strategy, how do I maintain Spring Transaction? Using a #Transactional annotation needs a fixed datasource with transaction manager configured.
I would like to continue to use #Transactional in a service method and not worry about having to maintain transaction myself.
I would think that I would have to extend some spring class and inject the datasource when the system starts.
I am using Spring and JdbcTemplate in my project. No Hibernate. Any help would be appreciated.
You have to use AbstractRoutingDataSource to link it with your transaction manager, this kind of datasource allows you use different datasources choosing them in runtime.
After that spring handles the transaction properly. You can check this kind of DataSource in the Spring Documentation.
The other option is has different transactionManagers.
For no-xml lovers
#Bean(name = "mysqldatasource1")
public DataSource dataSource() {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName(classname);
dataSource.setUrl(url);
dataSource.setUsername(usernmae);
dataSource.setPassword(password);
return dataSource;
}
#Bean(name = "mySqlJdbcTemplate1")
public JdbcTemplate jdbcTemplate() {
JdbcTemplate jdbcTemplate = new JdbcTemplate();
jdbcTemplate.setDataSource(dataSource());
return jdbcTemplate;
}
#Bean(name="mysqlTransaction1")
#Autowired
DataSourceTransactionManager tm1(#Qualifier ("mysqldatasource") DataSource datasource) {
DataSourceTransactionManager txm = new DataSourceTransactionManager(datasource);
return txm;
}
#Bean(name = "mysqldatasource2")
public DataSource dataSource() {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName(classname);
dataSource.setUrl(url);
dataSource.setUsername(usernmae);
dataSource.setPassword(password);
return dataSource;
}
#Bean(name = "mySqlJdbcTemplate2")
public JdbcTemplate jdbcTemplate() {
JdbcTemplate jdbcTemplate = new JdbcTemplate();
jdbcTemplate.setDataSource(dataSource());
return jdbcTemplate;
}
#Bean(name="mysqlTransaction2")
#Autowired
DataSourceTransactionManager tm1(#Qualifier ("mysqldatasource2") DataSource datasource) {
DataSourceTransactionManager txm = new DataSourceTransactionManager(datasource);
return txm;
}
You can create multiple Transaction Managers with different datasources and then access them in #Transactional annotation as follows:
<bean id="txManager1" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource1"/>
<qualifier value="txManager1"/>
</bean>
Access it as:
#Transactional("txManager1")
Similarly,
<bean id="txManager2" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource2"/>
<qualifier value="txManager2"/>
</bean>
Access it as:
#Transactional("txManager2")
As there can be only one annotation-driven TxManager, do not forget to remove this:
<tx:annotation-driven transaction-manager="transactionManager" />

How to inject multiple JPA EntityManager (persistence units) when using Spring

I need to use one database for queries (non-modifying) and one for commands (modifying). I am using Spring Data JPA, so I have two configuration classes:
#Configuration
#EnableJpaRepositories(value = "com.company.read",
entityManagerFactoryRef = "readingEntityManagerFactory",
transactionManagerRef = "readingTransactionManager")
#EnableTransactionManagement
public class SpringDataJpaReadingConfiguration {
#Bean(name = "readingEntityManagerFactory")
public EntityManagerFactory readingEntityManagerFactory() {
return Persistence.createEntityManagerFactory("persistence.reading");
}
#Bean(name = "readingExceptionTranslator")
public HibernateExceptionTranslator readingHibernateExceptionTranslator() {
return new HibernateExceptionTranslator();
}
#Bean(name = "readingTransactionManager")
public JpaTransactionManager readingTransactionManager() {
return new JpaTransactionManager();
}
}
#Configuration
#EnableJpaRepositories(value = "com.company.write",
entityManagerFactoryRef = "writingEntityManagerFactory",
transactionManagerRef = "writingTransactionManager")
#EnableTransactionManagement
public class SpringDataJpaWritingConfiguration {
#Bean(name = "writingEntityManagerFactory")
public EntityManagerFactory writingEntityManagerFactory() {
return Persistence.createEntityManagerFactory("persistence.writing");
}
#Bean(name = "writingExceptionTranslator")
public HibernateExceptionTranslator writingHibernateExceptionTranslator() {
return new HibernateExceptionTranslator();
}
#Bean(name = "writingTransactionManager")
public JpaTransactionManager writingTransactionManager() {
return new JpaTransactionManager();
}
}
In my repository I sometimes need to decide with EntityManager to use like so:
#Repository
public class UserReadingRepository {
#PersistenceContext(unitName = "persistence.reading")
private EntityManager em;
// some useful queries here
}
I am using persistence unit's name as defined in my persistence.xml:
<persistence xmlns="http://java.sun.com/xml/ns/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">
<persistence-unit name="persistence.reading" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<non-jta-data-source>ReadingDS</non-jta-data-source>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect" />
<property name="hibernate.show_sql" value="true" />
</properties>
</persistence-unit>
<persistence-unit name="persistence.writing" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<non-jta-data-source>WritingDS</non-jta-data-source>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect" />
<property name="hibernate.show_sql" value="true" />
</properties>
</persistence-unit>
</persistence>
Spring throws org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'persistence.reading' is defined. Oddly, it looks like Spring tries to instantiate a bean with persistence unit name? Did I misconfigure something?
UPDATE: When I remove unitName = "persistence.reading" from #PersistenceContext annotation, I will get following error instead:
org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [javax.persistence.EntityManagerFactory] is defined: expected single matching bean but found 2: readingEntityManagerFactory,writingEntityManagerFactory
UPDATE 2: Rohit suggested (in the comment) to wire EntityManagerFactory instead. So I tried to do the following:
#PersistenceUnit(unitName = "persistence.reading")
private EntityManagerFactory emf;
but Spring only reports: org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'persistence.reading' is defined
FINAL FIX:
Thanks to Vlad's answer, I was able to update the code to use the following (just make sure you define your dataSource bean as well):
#Bean(name = "readingEntityManagerFactory")
public EntityManagerFactory readingEntityManagerFactory() {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setPersistenceUnitName("persistence.reading");
em.setDataSource(dataSource());
em.setPackagesToScan("com.company");
em.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
em.afterPropertiesSet();
return em.getObject();
}
The EntityManageFactory is not properly configured. You should use a LocalContainerEntityManagerFactoryBean instead:
#Bean(name = "readingEntityManagerFactory")
public EntityManagerFactory readingEntityManagerFactory() {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setPersistenceUnitName("persistence.reading");
em.setDataSource(dataSource());
em.setPackagesToScan("com.company");
em.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
em.afterPropertiesSet();
return em.getObject();
}
Also the JpaTransactionManager is miss-configured too. It should be something like:
#Bean(name = "readingTransactionManager")
public PlatformTransactionManager readingTransactionManager(){
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(readingEntityManagerFactory());
return transactionManager;
}
You need to do the same for both the reading and the writing EntityManager configurations.

Spring 4, JBoss 7, #Configuration Bean equivalent XML - Spring Transactions

It seem like EntityManager is NOT flushing out the changes to the database. What makes this problem harder is that there is no exception thrown. I am using declarative transactions to define my transaction boundaries with the following flow:
SignUpController --> #Transactional: Tx.Start --> AccountServiceImpl.createAccount --> AccountDAOImpl.createAccount --> Tx.Commit --> SignUpController
From my investigation it seems like:
1.Spring is properly defining the Transaction Boundaries using #Transactional. Hence Transaction are being created
2.Also please Note the I am using the SharedEntityManagerBean, which means I CANNOT explicitly define my transaction boundaries e.g:
em.getTransaction().begin();
em.persist(entity);
em.getTransaction().commit();
The above code results in the following exception: Not allowed to create transaction on shared EntityManager - use Spring transactions or EJB CMT instead
Below is the relevant code and configuration. Any assistance will be greatly appreciated. Thanks.
MainConfig.java:
#Configuration
#ComponentScan(basePackages="com",excludeFilters= {#Filter(Configuration.class)})
#EnableTransactionManagement
public class MainConfig {
#Bean
public DataSource dataSource() {
DataSource ds = (DataSource)getFromInitialContext("java:jboss/datasources/PrimaryDB");
return ds;
}
#Bean
public PlatformTransactionManager transactionManager() {
return new DataSourceTransactionManager(dataSource());
}
#Bean
public EntityManagerFactory entityManagerFactory() {
EntityManagerFactory emf = (EntityManagerFactory) getFromInitialContext("java:jboss/entityManagerFactory");
return emf;
}
private Object getFromInitialContext(String jndiValue) {
Context ctx = null;
Object object = null;
try {
ctx = new InitialContext();
object = ctx.lookup(jndiValue);
} catch (NamingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return object;
}
}
persistance.xml:
<persistence-unit name="PrimaryDB" transaction-type="JTA">
<jta-data-source>java:jboss/datasources/PrimaryDB</jta-data-source>
<class>com.domain.entities.Account</class>
<properties>
<!-- Bind entity manager factory to JNDI at java:jboss/myEntityManagerFactory -->
<property name="jboss.entity.manager.factory.jndi.name"
value="java:jboss/entityManagerFactory" />
<!-- Properties for Hibernate -->
<property name="hibernate.hbm2ddl.auto" value="create-drop" />
<property name="hibernate.show_sql" value="true" />
<property name="hibernate.use_sql_comments" value="true" />
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect" />
</properties>
</persistence-unit>
AccountServiceImpl:
#Service
public class AccountServiceImpl implements AccountService {
#Inject
AccountDAO accountDAOImpl;
#Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
public Account createAccount(SignupForm form, BindingResult formBinding) {
TransactionDebugUtil.transactionRequired("AccountServiceImpl.createAccount");
Account account =
new Account(form.getUsername(), form.getPassword(),form.getFirstName(), form.getLastName());
try {
accountDAOImpl.createAccount(account);
} catch (Exception ex) {
formBinding.rejectValue("username", "user.duplicateUsername",
"already in use: " + ex.getMessage());
return null;
}
return account;
}
}
AccountDAOImpl.java:
#Repository
public class AccountDAOImpl extends GenericJpaDAO<Account> implements AccountDAO {
#Override
#PersistenceContext
public void setEntityManager(EntityManager entityManager) {
this.entityManager = entityManager;
entityManager.setFlushMode(FlushModeType.COMMIT);
}
#Override
public void createAccount(Account account) throws UsernameAlreadyInUseException {
entityManager.persist(account);
}
Hi the confusion was caused due to using annotations for configuring the transaction manager rather then XML.
Typical XML Configuration for SpringTransaction:
1.
<tx:annotation-driven />
^It scans all beans in the application context and creates AOP interceptor for those which are annotated.This is done via the SpringTransactionAnnotationParser, which is used by TransactionInterceptor.
#EnableTransactionManagement
^This is the equivalent configuration bean annotation to allow transactional support
2
. JTA datasource is defined in the persistence.xml. JBoss 7 automatically creates a JTA Transaction Manager and binds it to the following JNDI Location: java:/TransactionManager by default. This Transaction Manager is automatically discovered in spring with the following xml configuration:
<tx:jta-transaction-manager />
The equivalent annotation configuration for this is:
#Bean
public PlatformTransactionManager transactionManager() {
JtaTransactionManager txManager = new JtaTransactionManager();
return txManager;
}
This resolved my issue. Thanks #geoand for your help.
this kind of behaviour usually happens when we dont have #transactional
on the persistent method.
so add #Transactional on top of method like below
#Override
#Transactional
public void createAccount(Account account) throws UsernameAlreadyInUseException {
entityManager.persist(account);
}
You are not handling transaction management correctly. Replace your transaction manager bean with:
#Bean
public PlatformTransactionManager transactionManager() {
final JpaTransactionManager txManager = new JpaTransactionManager();
txManager.setEntityManagerFactory(entityManagerFactory());
return txManager;
}

Categories