1

I have developed a webapp using Spring MVC + Hibernate, and using three layers, Controller layer, Service layer and Dao layer.

Now I want to provide a REST api for my webapp.

Since I have a GenericDao which provides generic methods like find(id), findAll(), findByProperty() I thought I could skip the Service Layer in the Api Controller and inject the daos into the Controller itself, otherwise I would have to create class-specific methods for each of my domain objects for these generic find, findAll methods, which is a pain in the ass when I want to presetn just raw data.

My first, more generic question is regarding this architecture decision. Is this a good solution?

My second (and main) question is that I am having trouble when annotating my Controller method with @Transactional so a hibernate session is opened. It seems that it's not working at all.

I even creted an interface as said in this question.

IApiController

@Controller
public interface IApiController {

    @ResponseBody
    public String getStation(Long id);
    @ResponseBody
    public String getStations();


}

ApiController

@Controller
@RequestMapping("/api")
public class ApiController extends BaseApiController implements IApiController {

    @Autowired
    private IStationDao stationDao;


    @RequestMapping(value = "stations/{id}", produces = MediaType.APPLICATION_JSON_VALUE)
    @ResponseBody
    @Transactional(readOnly=true)
    public String getStation(@PathVariable Long id){
        Station station = stationDao.findById(id);
        return pack(station);
    }


    @Override
    @RequestMapping(value = "stations", produces = MediaType.APPLICATION_JSON_VALUE)
    @ResponseBody
    @Transactional(readOnly=true)
    public String getStations() {
        List<Station> stations = stationDao.findAll();
        return pack(stations);
    }


}

When I call api/stations I get a HibernateException: No Session found for current thread

Context config

<context:component-scan base-package="my controller package" />
    <mvc:annotation-driven />
    <context:annotation-config />
    <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="configLocation">
            <value>classpath:hibernate.cfg.xml</value>
        </property>
        <property name="mappingLocations">
            <list>
                <value>classpath*:/hbm/*.hbm.xml</value>
            </list>
        </property>
    </bean>
Community
  • 1
  • 1
MichelReap
  • 5,630
  • 11
  • 37
  • 99
  • 5
    Take a look at this, I personally think moving the DAO injections into the service layer is better than having it in the controller, you would thank yourself for doing it later. http://stackoverflow.com/questions/1079114/spring-transactional-annotation-best-practice for the transactions, I think you have to configure transaction http://stackoverflow.com/questions/14090547/spring-annotation-transaction-mangement – Zeus Oct 03 '13 at 16:12
  • I would have given +10 to the @Zeus comment if I could. Transaction management and DAO injection belongs in the service layer, not in a controller which is part of the UI layer. – Olaf Oct 03 '13 at 16:30
  • can you post your spring data source and transaction configuration? – erencan Oct 03 '13 at 16:35
  • You do NOT need to add an additional enterprisey "service layer" for the situation you have sketched out. In cases where there is no business logic, injecting the dao's into the controller is perfectly ok. KISS. – Dave L. Oct 03 '13 at 17:11
  • I just posted my context config. I can't get Transactions to work at all. – MichelReap Oct 04 '13 at 07:53

2 Answers2

2

Annotating your controllers with @Transactional is a bad idea. See the Spring MVC documentation, 17.3.2:

A common pitfall when working with annotated controller classes happens when applying functionality that requires creating a proxy for the controller object (e.g. @Transactional methods). Usually you will introduce an interface for the controller in order to use JDK dynamic proxies. To make this work you must move the @RequestMapping annotations, as well as any other type and method-level annotations (e.g. @ModelAttribute, @InitBinder) to the interface as well as the mapping mechanism can only "see" the interface exposed by the proxy. Alternatively, you could activate proxy-target-class="true" in the configuration for the functionality applied to the controller (in our transaction scenario in ). Doing so indicates that CGLIB-based subclass proxies should be used instead of interface-based JDK proxies. For more information on various proxying mechanisms see Section 9.6, “Proxying mechanisms”.

So there are workarounds but it sounds painful. It would be easier to put @Transactional on your DAOs.

Nathan Hughes
  • 94,330
  • 19
  • 181
  • 276
  • DAOs is not the best place for transactions too. It's better to put @Transactional on Services. – DraggonZ Dec 05 '13 at 08:21
  • @DraggonZ: I agree. People resist that approach a lot, though, when there isn't any business logic to put in the service. In this case the OP specifically wants to avoid creating services. – Nathan Hughes Dec 05 '13 at 14:57
-1

A database transaction, by definition, must be atomic, consistent, isolated and durable.[1] Database practitioners often refer to these properties of database transactions using the acronym ACID.1

By definition, Transactions are a atomic unit of work. They have all-or-nothing property, meaning the transactional operation has been commited or never existed(rolled back).

As all MVC frameworks Spring-mvc is the part of UI. Then do not needed to be transactional. There is 3 basic layerin most J2EE application. First is presentation layer which mostly involves a MVC framework. Second is service layer where business logic has been done. Third is the Data layer where database access has been done.

Service layer is a good candidate to be transactional where bussiness logic has been done, but in my idea there can data access layer needed to be transactional in some cases. Because a transactional unit is atomic and no further thread can not use it.

It is better to make service or dao classes to be transactional in your case. Do not forget to add proper transaction manager to your configuration.

See also

Database transaction

ACID

Transaction Management

Spring MVC

erencan
  • 3,725
  • 5
  • 32
  • 50