I have a Spring CrudRepository that is just an interface, and I have a persistence context class where I have defined my data source:
#Configuration
#EnableTransactionManagement
public class PersistenceContext {
#Bean(name="dataSource", destroyMethod = "close")
public DataSource dataSource() throws SQLException {
return ...
public interface DataRepository extends CrudRepository<Data, Long> {
Data findById(long id);
}
Then
#Autowired
protected DataRepository repository;
...
Data data = repository.findById(1234);
Everything works fine but the database model is such that I actually need to call a stored procedure on the same connection before calling findById from the using code. This procedure must take a parameter that a calling code will know but it will differ between calls so it is not possible just to override DataSource.getConnection and return the "prepared connection" there.
Is it any way to "prepare a connection" before making an access code to the Spring repository?
Using AOP would seem to be one approach: an example of using AOP to enrich Spring Data repositories can be found at the below:
https://github.com/spring-projects/spring-data-jpa-examples
If you can get a reference to the injected EntityManager within the advice then you should be able to get the underlying connection from that using one of the methods detailed here:
How can i get the session object if i have the entitymanager
To get a reference to the EntityManager you may have to create a custom repository from which all your repositories inherit:
http://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.custom-behaviour-for-all-repositories
Related
I have a custom Stored Procedure class which is extending jdbc.StoredProcedure but I have annotated this class with Spring #Component to bring this class bean into Spring context.
Why I am doing this?
I wanted to add spring-retry on execute method which will work only on spring components
I wanted to reused the compiled StoredProcedure instead of creating a new object and recompiling every time, in this way I can reuse the compiled StoredProcedure every time.
anything wrong with this kind of implementation?
are there any issues we may see with this Spring component based StoredProcedure?
Ex:
#Component
public class ExampleStoredProcedure extends StoredProcedure {
#Autowired
private DataSource dataSource;
#Postconstruct
public void init() {
super.setDataSource(dataSource);
setSql("stored_procedure_name");
//TODO declare parameters
compile();
}
public void execute(){
//Todo set all parameters to ParameterSource
super.execute(parameterSource);
}
}
Try implementing a layered application architecture where you annotate your services with spring retry like this example:
https://dzone.com/articles/spring-retry-way-to-handle-failures
These service methods can define transaction boundaries and call your data persistence layers methods that could be based on spring data's standardized ways to call stored procedures and manage your database connections etc.
See for more info on Spring and architecture for example this brief introduction:
https://www.petrikainulainen.net/software-development/design/understanding-spring-web-application-architecture-the-classic-way/
Let's say there are #Service and #Repository interfaces like the following:
#Repository
public interface OrderDao extends JpaRepository<Order, Integer> {
}
public interface OrderService {
void saveOrder(Order order);
}
#Service
public class OrderServiceImpl implements OrderService {
#Autowired
private OrderDao orderDao;
#Override
#Transactional
public void saveOrder(Order order) {
orderDao.save(order);
}
}
This is part of working application, everything is configured to access single database and everything works fine.
Now, I would like to have possibility to create stand-alone working instance of OrderService with auto-wired OrderDao using pure Java with jdbcUrl specified in Java code, something like this:
final int tenantId = 3578;
final String jdbcUrl = "jdbc:mysql://localhost:3306/database_" + tenantId;
OrderService orderService = someMethodWithSpringMagic(appContext, jdbcUrl);
As you can see I would like to introduce multi-tenant architecture with tenant per database strategy to existing Spring-based application.
Please note that I was able to achieve that quite easily before with self-implemented jdbcTemplate-like logic also with JDBC transactions correctly working so this is very valid task.
Please also note that I need quite simple transaction logic to start transaction, do several requests in service method in scope of that transaction and then commit it/rollback on exception.
Most solutions on the web regarding multi-tenancy with Spring propose specifying concrete persistence units in xml config AND/OR using annotation-based configuration which is highly inflexible because in order to add new database url whole application should be stopped, xml config/annotation code should be changed and application started.
So, basically I'm looking for a piece of code which is able to create #Service just like Spring creates it internally after properties are read from XML configs / annotations. I'm also looking into using ProxyBeanFactory for that, because Spring uses AOP to create service instances (so I guess simple good-old re-usable OOP is not the way to go here).
Is Spring flexible enough to allow this relatively simple case of code reuse?
Any hints will be greatly appreciated and if I find complete answer to this question I'll post it here for future generations :)
HIbernate has out of the box support for multi tenancy, check that out before trying your own. Hibernate requires a MultiTenantConnectionProvider and CurrentTenantIdentifierResolver for which there are default implementations out of the box but you can always write your own implementation. If it is only a schema change it is actually pretty simple to implement (execute a query before returning the connection). Else hold a map of datasources and get an instance from that, or create a new instance.
About 8 years ago we already wrote a generic solution which was documented here and the code is here. It isn't specific for hibernate and could be used with basically anything you need to switch around. We used it for DataSources and also some web related things (theming amongst others).
Creating a transactional proxy for an annotated service is not a difficult task but I'm not sure that you really need it. To choose a database for a tenantId I guess that you only need to concentrate in DataSource interface.
For example, with a simple driver managed datasource:
public class MultitenancyDriverManagerDataSource extends DriverManagerDataSource {
#Override
protected Connection getConnectionFromDriverManager(String url,
Properties props) throws SQLException {
Integer tenant = MultitenancyContext.getTenantId();
if (tenant != null)
url += "_" + tenant;
return super.getConnectionFromDriverManager(url, props);
}
}
public class MultitenancyContext {
private static ThreadLocal<Integer> tenant = new ThreadLocal<Integer>();
public static Integer getTenantId() {
return tenant.get();
}
public static void setTenatId(Integer value) {
tenant.set(value);
}
}
Of course, If you want to use a connection pool, you need to elaborate it a bit, for example using a connection pool per tenant.
I am using Spring Data within Spring Boot. I have a simple controller method that accepts an instance of an entity I'd like to update in my database. However, after calling repository.save() the object isn't persisted, however, if I query for the object (from the Id of the incoming entity) I have no problem, and the update persists.
Also the HTTP response is a 405 that the method doesn't work?
Controller:
#Transactional
public class AccountController {
#Autowired
private AccountService accountService;
#RequestMapping(value = "/account/{id}", method = RequestMethod.PUT)
#ResponseStatus(value = HttpStatus.OK)
public #ResponseBody Account updateAccount(#PathVariable("id") String id, #RequestBody Account account) {
return accountService.updateAndValidateAccountProfile(account);
}
}
Service:
#Override
public Account updateAndValidateAccountProfile(Account account) {
// calling findOne() returns the object ... and the save() works fine
//Account currentAccount = accountRepository.findOne(account.getId());
return accountRepository.save(account);
}
Repository:
interface AccountRepository extends CrudRepository<Account, Long> {
}
Is there something about the way I need to identify the object to Spring Data. I see the select statements fire out of hibernate, and I know the merge should happened on the primary key (id) within the Spring Data call to .save() - so I shouldn't need to query the object and manually assign the updated values correct??
Have you enabled transaction management? You need to use #EnableTransactionManagement on your config class otherwise #Transactional has no effect.
A spring tutorial on Managing Transactions
As a side note: making the controller layer transactional is usually not a good idea, especially when you have a proper separation of controller, service and repository layers. Consider moving #Transactional into the service layer.
Since you are using JPA, also make sure you have a JpaTransactionManager configured:
#Bean
public PlatformTransactionManager transactionManager() {
return new JpaTransactionManager();
}
You might try extending the JpaRepository interface instead of CrudRepository then you can use saveAndFlush(entity) to make sure the changes are immediately flushed after merge.
I have a GenericDAO which delegates its operations to a DataSource class
public class BaseDAOImpl<T> implements BaseDAO<T> {
DataSource ds;
public T update(T entity) {
ds.update(entity);
}
The issue I'm having right now is that we want it to work with multiple DataSources. This leaves me with 2 alternatives
1) make a setter in DAO for datasource and use it before every operation
2) create each child of BaseDAO n times per number of datasources
I would like DataSource to get out of DAO, but then how the actions can get delegated to it?
I guess you want to implement something like multitenancy: when request comes from the user A, all DAO involved into processing that request should talk to user A's DataSource, and so on.
If so, DataSource is a part of context for your request, and one possible option to store this kind of contextual data is to use ThreadLocal:
When request comes, you put the appropriate DataSource into ThreadLocal
All DAOs obtain the DataSource from that ThreadLocal.
Obviously, for the sake of Single Responsibility Principle it would be better to hide this logic behind a factory and inject that factory into your DAOs, so that DAOs will call factory.getCurrentDataSource() for each operation.
Clear ThreadLocal when you finished processing of the request.
Note that it only works if each request is processed by a single thread.
You can use a factory for creating your datasource, so depending on your requirement create your datasource and then if you can use dependency injection to have your datasource injected to your DAO.
To get rid of datasource in DAO you can use Delegate Pattern, inject delegator in your DAO, your delegate will have reference of DataSource.
Also to note if you persist with just one generic DAO, your DAO may eventually get blotted with methods which are not generic but more specific to a certain functionality of your application, IMHO you should also consider breaking your DAO to more specific level leaving the generic DAO actually do the generic work.
I wouldn't use a setter for the data source, I would pass it in the constructor for the DAO. Doesn't seem right to be able to change the data source during the life of the DAO object.
Well I think, you should try and use dependency injection in this case. Your base class would be abstracted from type of datasource. So even if you are adding a new type of datasource the only change that you would end up doing would be the factory method which would generate a type of DataSource object based upon current request and hence increase loose coupling of your application
interface IDataSource<T>
{
T update<T>(T entity);
}
public ConcereteDataSource<T> : IDataSource<T>
{
public T update<T>(T entity)
{
//Concerete implementation
}
}
public class BaseDAOImpl<T> implements BaseDAO<T>
{
public IDataSource ds {get;set;}
public T update(T entity) {
ds.update(entity);
}
//where you try to instansiate a new instance of Base DAO
//Factory to create a new instance of datasource for this context
IDataSource contextualDs = GetDataSourceForThisUser();
BaseDAOImpl<SomeType> dao = new BaseDAOImpl<SomeType>();
//inject the dependency
dao.ds = contextualDs;
My Spring+Hibernate configuration files are small and super tight. I use auto scanning to find my model entities/daos.
I don't want to have to write a DAO + DAOImpl for EVERY Entity in my hierarchy.
Some may qualify to have their own, like if they have complex relationships with other entities and require more than basic CRUD functionality. But for the rest...
Is there any way to circumvent the defacto standard?
Say, something like a generic DAO, ex:
http://www.ibm.com/developerworks/java/library/j-genericdao/index.html
Then I can do something like
GenericDao dao = appContext.getBean("genericDao");
dao.save(car);
dao.save(lease);
Is this possible with annotations? I don't want to have to configure anything in xml. If I cannot do above, is it still possible to have one GenericDaoImpl.java with something like:
#Repository("carDao")
#Repository("leaseDao")
class GenericDaoImpl extends CustomHibernateDaoSupport implements GenericDao {
...
}
and then
GenericDao dao = appContext.getBean("carDao");
dao.save(car);
dao = appContext.getBean("leaseDao"); //carDao is garbage coll.
dao.save(lease);
Is this practical at all?
Using generics, you might try something like this:
#Repository
#Transactional
public class GenericDAOImpl<T> implements GenericDAO<T> {
#Autowired
private SessionFactory factory;
public void persist(T entity) {
Session session = factory.getCurrentSession();
session.persist(entity);
}
#SuppressWarnings("unchecked")
public T merge(T entity) {
Session session = factory.getCurrentSession();
return (T) session.merge(entity);
}
public void saveOrUpdate(T entity) {
Session session = factory.getCurrentSession();
session.saveOrUpdate(entity);
}
public void delete(T entity) {
Session session = factory.getCurrentSession();
session.delete(entity);
}
}
The content may be different, but the general idea is applicable.
You should be able to then autowire the DAO in your controller and service classes by using
#Autowired
private GenericDAO<Car> carDao;
You can combine Spring/Hibernate with JPA, which provides the EntityManager for a large amount of basic persistence tasks:
#Service
public class CarService {
#PersistenceContext
private EntityManager em;
public void saveCarAndLease(Car car, Lease lease) {
em.persist(car);
em.persist(lease);
}
}
It will also handle transactions and simple queries without needing to write a DAO. For the more complex operations, you can still write a DAO and fall back to Hibernate's SessionFactory (although JPA is an option here too).
Some tutorials suggest you should still write the DAO for abstraction of the JPA plumbing. However, I have personally found this unnecessary (JPA has a very small integration footprint), and in fact this is also the way Spring Roo deals with the data layer behind the scenes.
Have you tried to use Spring Data. I mean to say Spring JPA where you can use repositories.
You can eliminate writing all stuffs for each entity.