简体   繁体   中英

@Transactional annotation in Spring

I have written the below code to implment the transaction management of spring using @transactional annotation. I still feel some changes are required in my DAO layer. May I know what changes are required . Thanks in advance

    @Controller
    public class RestController {


    @Autowired
    DataServices dataServices;

    @RequestMapping(value = "/v1/dist_list/{emailId}/members", method = RequestMethod.GET)
        public @ResponseBody String getDistributionListMember(@PathVariable String emailId) throws Exception, SpringException {



            String retStatus = null;


            retStatus = dataServices.getDistributionListMember(emailId, callerId);

         ]
    }      

    }

DataServices.java

    package com.uniteid.services;

    import com.uniteid.model.AIWSuser;

    public interface DataServices {


        public String getDistributionListMember(final String emailId, final String callerID) throws Exception;



    }

Below is my service layer where I added the trasactional attribute

    package com.uniteid.services;

    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.annotation.Transactional;

    import com.uniteid.dao.DataDao;
    import com.uniteid.model.AIWSuser;

    @Service("dataService")
    public class DataServicesImpl implements DataServices {

        @Autowired
        DataDao dataDao;


        @Transactional
        public String getDistributionListMember(String emailId, String callerID)
                throws Exception {
            return dataDao.getDistributionListMember(emailId, callerID);
        }



    }

Below is my spring-config file

    <?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:context="http://www.springframework.org/schema/context"
        xmlns:util="http://www.springframework.org/schema/util" xmlns:mvc="http://www.springframework.org/schema/mvc"
        xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
      http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
      http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.2.xsd
      http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
      http://www.springframework.org/schema/tx
    http://www.springframework.org/schema/tx/spring-tx-3.0.xsd"
        xmlns:tx="http://www.springframework.org/schema/tx">

        <context:component-scan base-package="com.uniteid.controller" />
        <mvc:annotation-driven
            content-negotiation-manager="contentNegociationManager" />

        <bean
            class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
            <property name="location" value="classpath:uniteidrest.properties" />
            <property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE" />
        </bean>

        <bean id="dataSource"
            class="org.springframework.jdbc.datasource.DriverManagerDataSource">
            <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />

            <property name="url">
                <value>${eidms.url}</value>
            </property>
            <property name="username">
                <value>${eidms.username}</value>
            </property>
            <property name="password">
                <value>${eidms.password}</value>
            </property>
        </bean>

        <!-- <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> 
            <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" 
            /> <property name="url" value="jdbc:oracle:thin:@nyvm0467.ptc.un.org:1521:EIDMSUAT" 
            /> <property name="username" value="DBO_EIDMSUAT" /> <property name="password" 
            value="NewPassDBO_EIDMSUAT" /> </bean> -->

        <bean id="contentNegociationManager"
            class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
            <property name="defaultContentType" value="application/json" />
            <property name="ignoreAcceptHeader" value="true" />
        </bean>

        <bean id="sessionFactory"
            class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
            <property name="dataSource" ref="dataSource" />
            <property name="annotatedClasses">
                <list>
                    <value>com.uniteid.model.User</value>
                </list>
            </property>
            <property name="hibernateProperties">
                <props>
                    <prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop>
                    <prop key="hibernate.connection.pool_size">10</prop>
                </props>
            </property>
        </bean>

        <bean id="txManager"
            class="org.springframework.orm.hibernate4.HibernateTransactionManager">
            <property name="sessionFactory" ref="sessionFactory" />
        </bean>

        <bean id="persistenceExceptionTranslationPostProcessor"
            class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />

        <bean id="dataDao" class="com.uniteid.dao.DataDaoImpl"></bean>
        <bean id="dataServices" class="com.uniteid.services.DataServicesImpl"></bean>
        <bean id="transactionManager"
            class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <property name="dataSource" ref="dataSource" />
        </bean>

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

It still feel I have not implemented the Transactional management properly in the below code. May I know what part of the code can be removed for me to implement it

    package com.uniteid.dao;


    import java.sql.CallableStatement;

    import java.sql.Connection;

    import java.sql.SQLException;

    import java.sql.Types;

    import java.text.ParseException;

    import java.text.SimpleDateFormat;

    import org.apache.log4j.Logger;

    import org.hibernate.Session;

    import org.hibernate.SessionFactory;

    import org.hibernate.Transaction;

    import org.hibernate.jdbc.Work;

    import org.springframework.beans.factory.annotation.Autowired;


    import com.uniteid.controller.RestController;

    import com.uniteid.model.AIWSuser;

    import com.uniteid.model.User;


    public class DataDaoImpl implements DataDao 
    {



    @Autowired
        \
    SessionFactory sessionFactory;


    Session session = null;

    Transaction tx = null;


    static final Logger logger = Logger.getLogger(DataDaoImpl.class);





    public String getDistributionListMember(final String emailId, final String callerID) throws Exception {
            session = sessionFactory.openSession();
            tx = session.beginTransaction();

            final String[] returnVal2 = { "" };

            session.doWork(new Work() {
                public void execute(Connection connection) throws SQLException {
                    CallableStatement stmt = null;
                    String returnVal = "";

                    stmt = connection.prepareCall("{?=call WS_Distributionlistmember(?,?)}");
                    stmt.registerOutParameter(1, Types.VARCHAR);
                    stmt.setString(2, emailId);
                    stmt.setString(3, callerID);
                    stmt.execute();
                    returnVal = stmt.getString(1);
                    logger.info("RETURN VALUE in getDistributionListMember method :::::: " + returnVal);
                    returnVal2[0] = returnVal;

                    logger.info("Return Value " + returnVal);
                    stmt.close();
                }
            });

            tx.commit();
            session.close();
            return returnVal2[0];
        }


    }

Your code:

public String getDistributionListMember(final String emailId, final String callerID) throws Exception {
        session = sessionFactory.openSession();//This is bad
        tx = session.beginTransaction();//This is bad
        tx.commit();//This is bad
        session.close();//This is bad

Correct should be:

public String getDistributionListMember(final String emailId, final String callerID) throws Exception {
        session = sessionFactory.getCurrentSession();//good way

It is because you told spring to autowired sessionFactory and from now on spring is managing your hibernate session not you. So getCurrentSession() is correct way.

@M. Deinum Thanks to point it out.

Remove bean declaration for bean id transactionManager and set txManager instead of transactionManager in transaction-manager value. As you are using hibernate with spring so HibernateTransactionManager should be used instead of DatabaseTransactionManager to define transaction boundary. DatabaseTransactionManager is used when you directly interact with data source without using any ORM or JPA framework.

In your service class define transaction boundary for method as below annotation

@Transactional(readOnly = true, propagation = Propagation.SUPPORTS)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM