I have read about DAO classes and Service classes but I don't understand for what are they used.
I have started a project in maven with spring and hibernate, and until now I have added in servlet.xml the configs for hibernate:
<bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
<property name="annotatedClasses">
<list>
<value>com.fabbydesign.model.Useradmin</value>
</list>
</property>
</bean>
The method from controller for login is like this:
#RequestMapping(value = "/do.html", method = RequestMethod.POST)
public String doLogin(#Valid #ModelAttribute("userLogin") LoginForm lf, BindingResult bindingResult, Map<String, Object> model, HttpServletRequest request){
//bindingResult.rejectValue("username", "label.title"); - to add new message error
logger.trace("showLogin - post");
//check fields if the filds are filled and respects the size from beans
if(bindingResult.hasErrors())
return "login";
boolean userExists = loginService.checkLogin(lf.getUsername(), lf.getPassword());
if(!userExists){
bindingResult.rejectValue("username", "login.username.wrongUserOrPassword");
return "login";
}
else{//set session
request.getSession().setAttribute(adminSesName, true);
}
return "redirect:/admin/dashboard.html";
}
loginServiceImpl:
#Service("loginService")
public class LoginServiceImpl implements LoginService {
#Autowired
private LoginDAO loginDAO;
public void setLoginDAO(LoginDAO loginDAO) {
this.loginDAO = loginDAO;
}
public Boolean checkLogin(String userName, String userPassword) {
return loginDAO.checkLogin(userName, userPassword);
}
and loginDAOimpl:
#Repository("loginDAO")
public class LoginDAOImpl implements LoginDAO {
#Resource(name = "sessionFactory")
protected SessionFactory sessionFactory;
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
protected Session getSession() {
return sessionFactory.openSession();
}
final static Logger logger = Logger.getLogger(LoginDAOImpl.class);
public boolean checkLogin(String username, String password) {
Boolean userFound = false;
Session session = sessionFactory.openSession();
String sql = "from Useradmin where username = ?";
Query<?> query = session.createQuery(sql);
query.setParameter(0, username);
List<?> list = query.list();
if ((list != null) && (list.size() == 1)) {
Useradmin ua = (Useradmin) list.get(0);
if (BCrypt.checkpw(password, ua.getPassword())) {
userFound = true;
}
}
return userFound;
}
So, what i should write in service classes and in DAO classes?
What i understand is that the code for manipulating data from database needs to stay in DAO classes, but services classes are for what?
Thanks!
You can refer to this simple example:
1.PersonDao only cares about database operation.
package com.pechen.dao;
import java.util.List;
import com.pechen.entity.Person;
public interface PersonDao {
public void save(Person p);
public List<Person> list();
}
2.PersonDaoImpl is the implementation.
package com.pechen.dao;
import java.util.List;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.springframework.beans.factory.annotation.Autowired;
import com.pechen.entity.Person;
public class PersonDaoImpl implements PersonDao {
#Autowired
private SessionFactory sessionFactory;
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
public void save(Person p) {
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
session.save(p);
tx.commit();
session.close();
}
#SuppressWarnings("unchecked")
public List<Person> list() {
Session session = sessionFactory.openSession();
List<Person> rst = session.createQuery("from person").getResultList();
session.close();
return rst;
}
}
3. PersonService cares about the business logic, you can do anything you want before the database operation.
package com.pechen.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import com.pechen.dao.PersonDao;
import com.pechen.dao.PersonDaoImpl;
import com.pechen.entity.Person;
public class PersonService {
#Autowired
private PersonDao personDao;
public void setPersonDao(PersonDaoImpl personImpl) {
this.personDao = personImpl;
}
public void savePerson(Person person) {
// other business logic
this.personDao.save(person);
System.out.println("Save person successfully: " + person);
}
public List<Person> getPersons() {
// other business logic
return this.personDao.list();
}
}
DAO provides a connection to the DataBase and operations.
The service layer provides logic to operate on the data sent to and from the DAO.
Also security - If you have service layer that has no relation to the DB it is more difficult to gain access to the DB from the client except through the service.
Service layer provides business operations and calling the DAO layer.
DAO layer is for the database layer. Meaning it performs data operations. This is where you put the retrieving of data, saving of data, and other database operations.
The answer to this question can be quite elaborate, so I will try to stick to some specifics here and will post links where ever necessary.
For some groundwork,
Layered and Tiered Architectures: You have to understand the difference between the Layers and Tiers of your application.
References:-
What is the difference between tier vs layer application?
N-Tiered vs N-Layered architecture/design
So if you have three primary layers of your application: Presentation, Service, and Database, the Service Layer is the one where service classes are kept. This is a place to add the core business logic to your application. E.g. If you are developing a Ticketing Application using three layers, and you have a comprehensive Authentication functionality added to it then.
The web pages will be a part of the presentation layer.
The functionality like validation of the user-id, encryption check,
timeout check etc will be a part of your service layer (Service
Classes)
The connections to the DB and the respective interactions will be taken care of in the database layer (Hibernate)
Additionally:
The application architectures are not simply confined to three layered systems nowadays. There is an increased adoption of distributed application architectures where the Service Layer mentioned in point 2 above, is broken into multiple small services, each with their own database. (Keyword check: Microservices). Also, they interact using messaging queues, but talking of all those things is not relevant to this question.
Recommended:
1. You go through the articles on the designing of service layers, and how different requirements lead to a different design of the Service Classes.
2. You read about design patterns like Providers, Factories, Singletons etc. which are commonly used in the designing of Services.
I hope I have answered your question.
N.B: You need to tag your question with 'architecture' as it is more a question of Architecture than Java programming.
Related
I am using spring 4.0 and hibernate 4.3,
The problem is that if I get the hibernate session object through session.openSession() then i can initialized the lazy object anywhere including JSP but then i have to manage the session object of hibernate by my own which is wrong practice.
But if i create the session by session.getCurrentSession() then i get the benefit of spring managing the session for me but then this problem occurs that i cant lazy initialised the object out side the transactional boundaries like JSP.
I don't want to explicitly set the query fetch mode to eager or join every time for every lazy object also every time i don't want to change the domain object annotation changed to Eager.
Overall i am just asking that what is the correct way to deal with lazy initialization object when used with spring and hibernate. Please Help
Below is my logic to get lazy loaded data when needed.
import java.io.Serializable;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.orm.hibernate4.HibernateTemplate;
import org.springframework.stereotype.Service;
public class UserDAO implements GenericDao<User,String> {
#Autowired
private HibernateTemplate template;
#Override
public User load(final String id) {
return template.load(User.class,id);
}
#Override
public User get(final String id) {
return template.get(User.class,id);
}
public User getUserVideos(final String id) {
User user = template.get(User.class,id);
template.initialize(user.getVideo());
return user;
}
#Override
public Long count() {
return new Long(template.loadAll(User.class).size());
}
#Override
public void flush() {
template.flush();
}
}
And you can use the returned objects in your JSP or whereever you want
My application uses Struts2(mvc), Spring (Dependency Injection), JPA with Hibernate, JUnit along with struts2-junit plugin and struts2 spring plugin.
Here is my test class:
#RunWith(SpringJUnit4ClassRunner.class)
public class CustomerSearchIntegrationTest extends StrutsSpringTestCase {
#Test
#Transactional
public void testGetActionProxy() throws Exception {
ActionProxy proxy;
String result;
ActionMapping mapping = getActionMapping("userInfo");
assertNotNull(mapping);
..... // Some JUnit init code..
ActionProxy proxy = getActionProxy("userInfo");
UserInfo user = (UserInfo) proxy.getAction();
result = proxy.execute();
assertEquals("details", result);
System.out.prinltn("Username:" + user.getFirstName());
}
}
GetUserInfo
public class UserInfo extends ActionSupport {
User user; // Entity
UDetails details; // Entity
public String getUserDetails() { //Action method
user = userMgmt.getUser(usrId);
if (user != null ) {
for(UDetails det : user.getUDetails()) { // user.getUDetails() there is where exception gets thrown.
if(det.getStreet().equals(street)){
details = det;
break;
}
}
}
...
...
}
}
User and UDetails are entities. UDetalis is ManyToMany with User and Lazily fetched. All entities are annotated.
UserMgmt
public class UserMgmt {
public User getUser(String userId) {
return userDao.getUser(userId);
}
}
UserDAO
public class UserDAO extends AbstractJPAImpl{
public User getUser(String userId) {
User user = (User) getSession().get(User.class, userId);
return user;
}
}
AbstractJPAImpl
#Transactional
public abstract class AbstractJPAImpl {
private EntityManager em;
#PersistenceContext
protected void setEntityManager(EntityManager em) {
this.em = em;
}
#Transactional
protected Session getSession() {
return (Session) em.getDelegate();
}
....
}
jpaContext.xml
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
// other config stuff
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
All configuration/context files are loading fine. Struts.xml, jpacontext.xml, beans.xml, etc. all are loaded.
But I get an exception:
failed to lazily initialize a collection of role: com.my.data.User.udetails, no session or session was closed
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role:
at the following line:
for(UDetails det : user.getUDetails())
Obviously, its trying to load UDetails lazily, then exception is throwing.
However, this application works fine when deployed in a AppServer (WebSphere).
What could I be doing wrong? How do I keep session open?
Update: More info
I am using OpenEntityManagerInViewFilter. My web.xml below
<filter>
<filter-name>OpenEntityManagerInViewFilter</filter-name>
<filter-class>
org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>OpenEntityManagerInViewFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Update:
This finally works, if I pass the parameter to #PersistenceContext annotation like below:
#PersistenceContext(type=PersistenceContextType.EXTENDED)
So I guess, the transaction is getting closed, but the entities are operable outside of transaction, because of the EXTENDED context type. However, I can't modify the code like above and leave it permanently. So I need to remove it.
So I guess, I have these options, but not sure if these are doable and how:
Get the persistence context from spring application context and pass the parameter. Not sure if this is relevant and possible.
Get the session/entity manager from application context and add another layer of transaction. That ways, the the session runs in two transactions. One is started from my testing code, and another one is in the existing code, which is automatically getting closed, while mine remains open until my test code completes execution.
For the 2nd one, I tried annotatting the method with #Transactional. But that did not work. Not sure why.
Any help?
Update
Looks like, struts-junit plugin does NOT load/read web.xml, which has the OpenEntityManagerInViewFilter. So it did not get loaded.
Any other work around or setup this filter?
If it helps anyone, I couldn't get the #Transaction to work. But I put this:
#PersistenceContext(type=PersistenceContextType.EXTENDED)
and it works now!
.....
see i m havving user.java for the user info.
#Entity(name = "user")
#Table(name = "user")
public class User {
#Id
#Column(name = "id")
private String id;
#Column(name = "password")
private String password;
//getter and setter for this..
}
this is my userdao
public class UserDao {
public interface UserDAO {
public String insert(User user);
}
}
and this is the impl class for inserting into database
see this was my code.please check it and tell me what i m doing wrong
#Repository
#Transactional
public class UserImpl implements UserDAO {
private DataSource dataSource;
#Autowired
SessionFactory sessionFactory;
#Resource(name = "sessionFactory")
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
#Override
public String insert(User use) {
Session session = this.sessionFactory.openSession();
try{
Session sess = this.sessionFactory.getCurrentSession();
session.save(reg);
return (String)user.getUserName();
}catch(Exception e){
System.out.println("in catch"+e.getMessage());
e.printStackTrace();
}
}
}
}
and in my controller after successful registration i m inserting data to the database by this
userDao.insert(user);
but i m not getting output means not any data is inserting into the database.why this..? this is my mvc configuration
<context:component-scan base-package="com.user.xyz" />
<mvc:annotation-driven />
<mvc:resources mapping="/resources/**" location="/resources/images/, /resources/css/" />
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/view/" />
<property name="suffix" value=".jsp" />
</bean>
Remember this: You don't have any exist session, but you use getCurrentSession(). To use this method, you must have a session already. try this:
Session session = this.sessionFactory.openSession();
Now you had a session for your transaction.
You should declare sessionFactory in an xml file (hibernate.xml or spring.xml), then use #Autowire to get it and open new session.
You have 2 choices:
A. force hibernate to flush any changes you have made in session:
session.save(user);
session.flush();
B. make whole method run in transaction - this is much better of course. When transaction is commited - hibernate will flush any changes to database just if you would do manually.
for example:
Transaction tx = null;
try {
session.beginTransaction();
session.save(user);
....
tx.commit();
} catch (RuntimeException e) {
tx.rollback();
throw e;
}
If you have multiple DAO calls in a single request, then session.getCurrentSession() is useful, but I guess that is not your case.
If there is only a single DAO call per request then session.openSession() is the right way.
Take care that when using session.openSession(), you also have to close your session afterwards.
The best thing to do is open a session for each incoming request (using a filter is the easiest way to do this) and then calling sessionFactory.getCurrentSession() in all your DAOs to get the current session. I guess your problem is you didn't specify the filter. That way all your DAOs will be easily reusable and you don't need to close your session afterwards.
You can found more information in the docs:
Hibernate documentation
I have also faced the same issue, and got the solution. For now check below points-
Check for appropriate jar files you are using
Check for manifest.mf in META-INF folder for application info.
Check your hibernate configuration in configuration file for hibernate template configuration.
At last if everything is OK then use session.flush() before insert.
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
{
{
//... your logic
//flush a batch of inserts and release memory:
session.flush();
session.clear();
}
}
tx.commit();
session.close()
I am using Spring's #Transactional with Hibernate.
I am trying to put two dao methods into a single transaction and want to rollback on a specific Exception.
Code is as follows:
Service Class method:
#Transactional(propagation=Propagation.REQUIRES_NEW,value="txManager",rollbackFor=TransactionUnSuccessException.class)
public Account makeTransaction(Transaction transaction, String userName)
throws TransactionUnSuccessException {
Account account = null;
account = transferDao.makeTransaction(transaction, userName);
return account;
}
Dao methods:
#Repository
public class TransferDao extends HibernateDaoSupport {
#Autowired
private SessionFactory sessionFactory;
public Account makeTransaction(Transaction transaction, String userName)
throws TransactionUnSuccessException {
HibernateTemplate hibernateTemplate = getHibernateTemplate();
Account account = null;
Session session = hibernateTemplate.getSessionFactory().openSession();
//session.beginTransaction();
updateSelfAccount(transaction, userName, session);
account = updateAnotherAcccount(transaction, session);
//session.getTransaction().commit();
return account;
}
private void updateSelfAccount(Transaction transaction, String userName,
Session session) {
User currentUser = null;
System.out.println("TransferDao.updateSelfAccount()" + transaction);
Query query = session.createQuery("from User where userName=:userName");
query.setParameter("userName", userName);
currentUser = (User) query.list().get(0);
currentUser.getAccount().getTransactions().add(transaction);
currentUser.getAccount().setAvailableBalance(
currentUser.getAccount().getAvailableBalance()
- transaction.getAmount());
transaction.setTransAccount(currentUser.getAccount());
session.save(transaction);
session.update(currentUser.getAccount());
session.update(currentUser);
private Account updateAnotherAcccount(Transaction transaction,
Session session) throws TransactionUnSuccessException {
Account account = null;
try {
Query query = session
.createQuery("from Account where accNo=:accNo");
query.setParameter("accNo", transaction.getToAcc());
account = (Account) query.list().get(0);
if (account.getAvailableBalance() < 5000) {
account.setAvailableBalance(account.getAvailableBalance()
+ transaction.getAmount());
account.getTransactions().add(transaction);
transaction.setTransAccount(account);
session.save(transaction);
session.update(account);
} else {
throw new TransactionUnSuccessException();
}
} catch (TransactionUnSuccessException te) {
te.printStackTrace();
}
return account;
}
}
}
Xml configuration:
<tx:annotation-driven transaction-manager="txManager"/>
<bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
If any of the two method(updateSelfAccount,updateAnotherAcccount) fails the whole transaction is supposed to rollback.
But It is not able to rollback on the given Exception even i am not sure that this is all happening in a single transaction.
please correct me.
The goal of using #Transactional annotation is that your code should not deal with the transaction itself. In your code example your use #Transactional so you should not have to do things like
session.beginTransaction();
Something else did you setup spring correctly with
<bean id="txManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="datasource" ref="dataSource"
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
Usually the sessionFactory is #Autowired in the dao and to get an easy access to the session you do
sessionFactory.getCurrentSession()
Last point you don't need to have a big try catch and then throwing your TransactionUnSuccessException , by default the transaction will rollback on any exception.
For starters don't use HibernateTemplate and/or HibernateDaoSupport they should be considered deprecated. Use the SessionFactory directly. Next NEVER use openSession inside a Spring managed transaction as that will open en new session, not bound to the transaction and outside of spring. Use getCurrentSession on the SessionFactory instead.
Finally NEVER catch and swallow exceptions, the TransactionInterceptor from spring needs the exception to decide what to do (rollback or commit)
Refactor your DAO to include all this.
#Repository
public class TransferDao {
#Autowired
private SessionFactory sessionFactory;
private Session getSession() {
sessionFactory.getCurrentSession();
}
public Account makeTransaction(Transaction transaction, String userName) throws TransactionUnSuccessException {
Account account = null;
Session session = getSession();
updateSelfAccount(transaction, userName, session);
account = updateAnotherAcccount(transaction, session);
return account;
}
Another observation, judging from the amount of updates, is that you have a mapping problem. When your mappings are correct you should only have to bother with an update/save of your User object, everything else should be automatically persisted then.
Yet another observation, you shouldn't pass around the session, simply call the getSession() method (which I added to the dao). You should get the same Session during the whole transaction.
Final observation, your dao seems to contain business logic, which should be in the service method instead (checking the account balance for instance).
Firstly, I can't use the declarative #Transactional approach as the application has multiple JDBC data-sources, I don't want to bore with the details, but suffice it to say the DAO method is passed the correct data-source to perform the logic. All JDBC data sources have the same schema, they're separated as I'm exposing rest services for an ERP system.
Due to this legacy system there are a lot of long lived locked records which I do not have control over, so I want dirty reads.
Using JDBC I would perform the following:
private Customer getCustomer(DataSource ds, String id) {
Customer c = null;
PreparedStatement stmt = null;
Connection con = null;
try {
con = ds.getConnection();
con.setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED);
stmt = con.prepareStatement(SELECT_CUSTOMER);
stmt.setString(1, id);
ResultSet res = stmt.executeQuery();
c = buildCustomer(res);
} catch (SQLException ex) {
// log errors
} finally {
// Close resources
}
return c;
}
Okay, lots' of boiler-plate, I know. So I've tried out JdbcTemplate since I'm using spring.
Use JdbcTemplate
private Customer getCustomer(JdbcTemplate t, String id) {
return t.queryForObject(SELECT_CUSTOMER, new CustomerRowMapper(), id);
}
Much nicer, but it's still using default transaction isolation. I need to somehow change this. So I thought about using a TransactionTemplate.
private Customer getCustomer(final TransactionTemplate tt,
final JdbcTemplate t,
final String id) {
return tt.execute(new TransactionCallback<Customer>() {
#Override
public Customer doInTransaction(TransactionStatus ts) {
return t.queryForObject(SELECT_CUSTOMER, new CustomerRowMapper(), id);
}
});
}
But how do I set the transaction isolation here? I can't find it anywhere on the callback or the TransactionTemplate to do this.
I'm reading Spring in Action, Third Edition which explains as far as I've done, though the chapter on transactions continues on to using declarative transactions with annotations, but as mentioned I can't use this as my DAO needs to determine at runtime which data-source to used based on provided arguments, in my case a country code.
Any help would be greatly appreciated.
I've currently solved this by using the DataSourceTransactionManager directly, though it seems like I'm not saving as much boiler-plate as I first hoped. Don't get me wrong, it's cleaner, though I still can't help but feel there must be a simpler way. I don't need a transaction for the read, I just want to set the isolation.
private Customer getCustomer(final DataSourceTransactionManager txMan,
final JdbcTemplate t,
final String id) {
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
def.setIsolationLevel(TransactionDefinition.ISOLATION_READ_UNCOMMITTED);
TransactionStatus status = txMan.getTransaction(def);
Customer c = null;
try {
c = t.queryForObject(SELECT_CUSTOMER, new CustomerRowMapper(), id);
} catch (Exception ex) {
txMan.rollback(status);
throw ex;
}
txMan.commit(status);
return c;
}
I'm still going to keep this one unanswered for a while as I truly believe there must be a better way.
Refer to Spring 3.1.x Documentation - Chapter 11 - Transaction Management
Using the TransactionTemplate helps you here, you need to configure it appropriately. The transaction template also contains the transaction configuration. Actually the TransactionTemplate extends DefaultTransactionDefinition.
So somewhere in your configuration you should have something like this.
<bean id="txTemplate" class=" org.springframework.transaction.support.TransactionTemplate">
<property name="isolationLevelName" value="ISOLATION_READ_UNCOMMITTED"/>
<property name="readOnly" value="true" />
<property name="transactionManager" ref="transactionManager" />
</bean>
If you then inject this bean into your class you should be able to use the TransactionTemplate based code you posted/tried earlier.
However there might be a nicer solution which can clean up your code. For one of the projects I worked on, we had a similar setup as yours (single app multiple databases). For this we wrote some spring code which basically switches the datasource when needed. More information can be found here.
If that is to far fetched or overkill for your application you can also try and use Spring's AbstractRoutingDataSource, which based on a lookup key (country code in your case) selects the proper datasource to use.
By using either of those 2 solutions you can start using springs declarative transactionmanagement approach (which should clean up your code considerably).
Define a proxy data source, class being org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy and set the transaction isolation level. Inject actual data source either through setter or constructor.
<bean id="yourDataSource" class="org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy">
<constructor-arg index="0" ref="targetDataSource"/>
<property name="defaultTransactionIsolationName" value="TRANSACTION_READ_UNCOMMITTED"/>
</bean>
I'm not sure you can do it without working with at the 'Transactional' abstraction-level provided by Spring.
A more 'xml-free' to build your transactionTemplate could be something like this.
private TransactionTemplate getTransactionTemplate(String executionTenantCode, boolean readOnlyTransaction) {
TransactionTemplate tt = new TransactionTemplate(transactionManager);
tt.setReadOnly(readOnlyTransaction);
tt.setIsolationLevel(TransactionDefinition.ISOLATION_READ_UNCOMMITTED);
tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
return tt;
}
In any case I would "leverage" the #Transactional annotation specifying the appropriate transaction manager, binded with a separate data-source. I've done this for a multi-tenant application.
The usage:
#Transactional(transactionManager = CATALOG_TRANSACTION_MANAGER,
isolation = Isolation.READ_UNCOMMITTED,
readOnly = true)
public void myMethod() {
//....
}
The bean(s) declaration:
public class CatalogDataSourceConfiguration {
#Bean(name = "catalogDataSource")
#ConfigurationProperties("catalog.datasource")
public DataSource catalogDataSource() {
return DataSourceBuilder.create().build();
}
#Bean(name = ENTITY_MANAGER_FACTORY)
public EntityManagerFactory entityManagerFactory(
#Qualifier("catalogEntityManagerFactoryBean") LocalContainerEntityManagerFactoryBean emFactoryBean) {
return emFactoryBean.getObject();
}
#Bean(name= CATALOG_TRANSACTION_MANAGER)
public PlatformTransactionManager catalogTM(#Qualifier(ENTITY_MANAGER_FACTORY) EntityManagerFactory emf) {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(emf);
return transactionManager;
}
#Bean
public NamedParameterJdbcTemplate catalogJdbcTemplate() {
return new NamedParameterJdbcTemplate(catalogDataSource());
}
}