1

I need to implement Spring's @Transactional annotation but I'm not being able to do so.

I had tried a lot of methods in the past 3 weeks but none of them worked.

I'm also need to use EntityManager. To test if Spring's was working, I tried to inject the EntityManager using @PersistenceContext (I also tried using @PersistenceUnit and/with EntityManagerFactory) but always I got nullPointerException.

 @PersistenceContext(unitName = "sistema")
 protected EntityManager entityManager;

Basically I need to know how to make spring's annotations to work and how to implement a Transaction manager using those technologies:

persitence.xml

<?xml version="1.0" encoding="UTF-8"?>
<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="sistema" transaction-type="RESOURCE_LOCAL"> 
    <provider>org.hibernate.ejb.HibernatePersistence</provider>
    <class>com.sis.vo.Person</class>

        <properties>
            <property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver" />
            <property name="hibernate.connection.autocommit" value="false" />

            <property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5Dialect"/>
            <property name="hibernate.enable_lazy_load_no_trans" value="false"/>
            <property name="hibernate.show_sql" value="false" />
            <property name="hibernate.format_sql" value="false"/>

            <!-- do I need those? -->
            <property name="hibernate.connection.url" value="jdbc:mysql://localhost/myDatabase?autoReconnect=true&amp;useSSL=false" />
            <property name="hibernate.connection.username" value="myUser" />
            <property name="hibernate.connection.password" value="myPass" />

        </properties>
   </persistence-unit>
</persistence>

spring.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:jee="http://www.springframework.org/schema/jee"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                    http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
                    http://www.springframework.org/schema/context
                    http://www.springframework.org/schema/context/spring-context-4.3.xsd
                    http://www.springframework.org/schema/mvc
                    http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
                    http://www.springframework.org/schema/jee
                    http://www.springframework.org/schema/jee/spring-jee-4.3.xsd
                    http://www.springframework.org/schema/tx
                    http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">


    <context:annotation-config />
    <mvc:annotation-driven />

     <bean id="hikariConfig" class="com.zaxxer.hikari.HikariConfig">
        <property name="poolName" value="sisHikariCP" />
        <property name="connectionTestQuery" value="SELECT 1" />
        <property name="dataSourceClassName" value="com.mysql.jdbc.jdbc2.optional.MysqlDataSource" />
        <property name="minimumIdle" value="3" />
        <property name="maximumPoolSize" value="100" />
        <property name="idleTimeout" value="740000" />
        <property name="maxLifetime" value="1740000" />
        <property name="leakDetectionThreshold" value="30000" />
        <property name="dataSourceProperties">
            <props>
                <prop key="url">jdbc:mysql://localhost/myDatabase?autoReconnect=true&amp;useSSL=false</prop>
                <prop key="user">myUser</prop>
                <prop key="password">myPass</prop>

                <prop key="prepStmtCacheSize">350</prop>
                <prop key="prepStmtCacheSqlLimit">2048</prop>
                <prop key="cachePrepStmts">true</prop>
                <prop key="useServerPrepStmts">true</prop>
                <prop key="useLocalSessionState">true</prop>
                <prop key="useLocalTransactionState">true</prop>
                <prop key="rewriteBatchedStatements">true</prop>
                <prop key="cacheResultSetMetadata">true</prop>
                <prop key="cacheResultSetMetadata">true</prop>
                <prop key="cacheServerConfiguration">true</prop>
                <prop key="elideSetAutoCommits">true</prop>
                <prop key="maintainTimeStats">false</prop> 
            </props>
        </property>
    </bean>

    <bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource" destroy-method="close">
        <constructor-arg ref="hikariConfig" />
    </bean>

    <bean id="myJpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />

    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="jpaVendorAdapter" ref="myJpaVendorAdapter" />

    </bean>

    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory" />
    </bean>

    <tx:annotation-driven transaction-manager="transactionManager"  />


</beans>

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
    id="WebApp_ID" version="3.0">
    <display-name>sis</display-name>

    <context-param>
        <param-name>javax.faces.INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL</param-name>
        <param-value>true</param-value>
    </context-param>
    <welcome-file-list>
        <welcome-file>index.jsf</welcome-file>
    </welcome-file-list>
    <servlet>
        <servlet-name>Faces Servlet</servlet-name>
        <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>Faces Servlet</servlet-name>
        <url-pattern>*.jsf</url-pattern>
    </servlet-mapping>


    <!--  SPRING  -->

    <servlet>
        <servlet-name>Spring Servlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
                <param-name>contextConfigLocation</param-name>
            <param-value>
                    /WEB-INF/spring.xml
            </param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
</web-app>

DAO

@Repository
public class GenericListDAO<E> {

    @PersistenceContext(unitName = "sistema")
    protected EntityManager entityManager;

    public EntityManager getEntityManager() {
        return entityManager;
    }

    public GenericListDAO() {
    }

    //rest of the code (persist, find, etc)
}

Versions:

  • Spring Version: 4.3.12
  • Hibernate Version: 5.1.10.Final
  • HikariCP Version: 2.7.3
  • JDK Version: 1.8.0_121
  • Tomcat version: 8.5.23

Thank you!

jNewbie
  • 334
  • 1
  • 15

1 Answers1

0

This is what i use to configure my transaction manager

<bean id="myDatasource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
    <property name="driverClassName" value="${jdbc.driverClassName}"/>
    <property name="url" value="${jdbc.url}"/>
    <property name="username" value="${jdbc.username}"/>
    <property name="password" value="${jdbc.password}"/>
</bean>

<bean id="myJpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />

<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="dataSource" ref="myDatasource" />
    <property name="jpaVendorAdapter" ref="myJpaVendorAdapter" />

</bean>

<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>

<tx:annotation-driven transaction-manager="transactionManager"  />

entityManagerFactory bean will use your persistence.xml from classpath to create the persistance unit.

update get your persistence context like this

@PersistenceContext(unitName="sistema")
protected EntityManager em;

also make sure the class that is using the persistence context is annotated with @Repository

update can you add this to your web.xml

<!-- The definition of the Root Spring Container shared by all Servlets 
    and Filters -->
<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>
    classpath:/WEB-INF/spring-root-context.xml
    </param-value>
</context-param>

<!-- Creates the Spring Container shared by all Servlets and Filters -->
<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

now create a new file spring-root-context.xml next to spring.xml and move all the DB and transaction related stuff to spring-root-context.xml.

So spring.xml will be your servlet context and spring-root-context.xml will be your root context.

anything related to controllers will go to spring.xml all other beans will go to spring-root-context.xml

also add <context:component-scan base-package="package.for.genericdao" /> to both spring.xml and spring-root-context.xml and replace package.for.genericdao with your base package name.

Zeronex
  • 434
  • 1
  • 3
  • 8
  • Hi @Zeronex , thank you for answering it! Using this configuration I'm still not able to use: `@PersistenceContext protected EntityManager entityManager;` Any tips? – jNewbie Dec 03 '17 at 23:59
  • I'm still not being able to use springs annotations. =/ – jNewbie Dec 05 '17 at 01:38
  • If i move all the DB and transaction related stuff to `spring-root-context.xml`, my spring.xml will only have the beans header and `` ``. Is that correct? – jNewbie Dec 05 '17 at 01:40
  • @jNewbie just and in spring.xml should be fine, give your package to – Zeronex Dec 05 '17 at 18:37
  • To Make it work I had to extend my service from `SpringBeanAutowiringSupport`. Can you update your answer so I can mark as answer? – jNewbie Dec 12 '17 at 04:53
  • @jNewbie you shouldn't need to extend from `SpringBeanAutowiringSupport`, as per the documentation that is mainly for JAX-WS rest controllers. I don't think that is the correct way to do it. – Zeronex Dec 13 '17 at 19:33
  • @jNewbie you need to split your spring.xml into two XML files, one for root context and one for spring/application context, your services and db beans should be defined in application context. – Zeronex Dec 13 '17 at 19:37
  • I did split spring.xml as you said. The problem is that I'm Using Primefaces JSF, this is why I had to use `SpringBeanAutowiringSupport` in my ManagedBean. (I don't have a controller, my service is accessed using ManagedBean) – jNewbie Dec 13 '17 at 20:10
  • @jNewbie dependency injection needs to be available even when using JSF and managed beans. It is one of main features of Spring, if it is not working then you are missing something in your configuration. – Zeronex Dec 13 '17 at 22:36