Using services means that application functionalities can be tested without a test framework simulating user calls to controllers. Separating services from the persistence layer implementation via DAO, allows using an in-memory database (for example) by substituting production DAO implementations, by test DAO implementation pointing to an in-memory database.
The code example used in this post is available from Github in the Spring-MVC-Service-DAO-Persistence-Architecture directory. It is a variation of the Spring Web JPA Hibernate In-Memory example.
MVC Controller Calls The Service Implementation
The following controller is injected with an implementation of MyService. It handles /roundtrip user calls by calling its create() and Retrieve(id) methods, which creates and retrieves an instance of a MilliTimeItem object. It contains a unique ID and a timestamp in milliseconds.@Controller public class MyController { @Autowired private MyService myService; @RequestMapping(value = "/") public String home(Model model) { return "index"; } @RequestMapping(value = "/roundtrip") public String persistenceStatus(Model model) { long id = myService.create(); MilliTimeItem retr = myService.retrieve(id); model.addAttribute("RoundTrip", retr); return "roundtrip"; } }
Service Implementation calls Data Access Objects (DAO)
The DAO is injected in the MyService implementation. The createAndRetrieve() calls the DAO createMilliTimeItem() and getMilliTimeItem() methods. It returns the created and retrieved item.public class MyServiceImpl implements MyService { @Autowired private MyPersistenceDAO myDAO; @Transactional long create(); @Transactional MilliTimeItem retrieve(long id); }
Data Access Object Implementation Calls The Persistence Layer
The DAO implementation is injected with the JPA EntityManager:@Repository public class MyPersistenceDAOImpl implements MyPersistenceDAO { @PersistenceContext private EntityManager em; @Override public long createMilliTimeItem() { MilliTimeItem mti = new MilliTimeItem(); mti.setMilliTime(System.currentTimeMillis()); em.persist(mti); long result = mti.getID(); em.detach(mti); return result; } @Override public MilliTimeItem getMilliTimeItem(long id) { return em.find(MilliTimeItem.class, id); } }
Running the Example
After compiling this example with Maven, it can be run with mvn tomcat:run. Then, browse http://localhost:8585/spring-mvc-service-dao-persistence-architecture/.The generated output is:
Created MilliTimeItem's ID: 1 Created MilliTimeItem's value: 1346691836108
More Spring related posts here.
I think making your DAO's transactional (using @Transactional annotation on DAO) is bad practise. Your services should be transactional and not DAO's. Your DAO's should not have knowledge of transactionality. For unit testing DAO's individually, one can use a framework like Spring testing framework to automatically start a transaction before DAO call. This is usually done by marking the test class as Transactional
ReplyDeleteAgreed, I cleaned-up the mess...
DeleteShouldn't there be @Service annotation before the
ReplyDeletepublic class MyServiceImpl implements MyService ?
I have added it...
Delete