We have a running Springboot service A that created some relational entities using Spring JPA with Hibernate ORM.
We need to create a new Springboot service B that needs to access A's tables but with different queries.
There are few options I though of:
Making service B use Spring JPA and Hibernate and copy the same entity models from service A
But I'm not sure if this method causes any synchronization issues caused by Hibernate's first level caching.
Both services will not be using 2nd level cache.
Same like option 1, making service B use Spring JPA and Hibernate but import service A as a dependency in service B instead of copying the entity models.
Making service B use Spring JdbcTemplate if we are not creating any new entities in service B.
I also like to know how service B's table can have a unidirectional foriegn key relationship (#ManyToOne or #OneToOne) with service A's table.
Please suggest me which option is better or if there's a better way.
If it is a bad pratice to use other service's tables, please suggest the correct design. \
Thanks
Related
We would like to share the Employee across both applications exposed as micro services. But Employee has the JPA definition, how do we package this is as a separate jar which can be shared across multiple applications
Spring Boot "AppA" has following entity
#Entity
#Table (name = "employees")
public class Employee {
}
Spring Boot "AppB" fetches Employee from "AppA"
ResponseEntity<Employee[]> response =
restTemplate.getForEntity(
"http://localhost:8080/employees/",
Employee[].class);
Employee[] employees = response.getBody();
You have to wrap the Entity first in a Record and then use
Corba-SCNR version 3 to access it from the other service.
Alternatively, you might want to rethink your
microservice-architecture, as its not good to have two services access
the same entity/database.
Ok, trolling time is over.
To answer your question: you cannot share an Entity over REST between two services in a way that is still giving you the guarantees defined by JPA/Hibernate.
Why is that? Because the EntityManager in JPA/Hibernate creates a wrapper around the Java Object you have, intercepts calls to it and kind of remembers when you change some fields so it knows which sql statements to generate when you "flush" the changes to the database. These wrappers cannot be serialised over your REST Endpoints, at least not in a way that another service could pick them up and continue where the first service stopped.
In general, it is a bad idea to directly expose your JPA Entities in your REST Controllers. I personally prefer to create small DTOs ( Data Transfer Object ) that I fill with the data that I need to expose and only expose those in the REST endpoints.
So best would be to think about "which information does AppB need from the Employee" and put theses in the DTO, then expose them in the Controller of AppA.
If you need to make changes to the Employee in AppB, create a controller in AppA that accepts requests from AppB and then send a request from AppB to AppA.
Depending on the size of the EmployeeDTO you create, you could put it into a shared jar or simply copy it over. Depending on the size of your project, you could also describe it in Swagger/OpenAPI in AppA and generate it in AppB, but this might be overkill.
I hope this helps a bit. Sorry for the trolling before.
If you really need to share them and do not want to copy and paste you can achieve that by packaging your shared entities and repos on a separate Spring project (without an Application.java) and declaring that project in your downstream services as maven/gradle dependency.
Let's say you've put the entities and repos in a separate library under the following packages:
Under a package like my.common.lib.entities, my.common.lib.repos
You can make Spring discover them on your downstream services AppA and AppB by using #ComponentScan typically on your corresponding Spring Application classes:
AppA:
#ComponentScan(basePackages={"my.common.lib.entities", "my.common.lib.repos"})
#SpringBootApplication
ApplicationAppA {
}
I'm studying Spring boot, and i have create several entity, my problem now is to retrieve the data from controller to save it on db.
Surfing on the web I have learned that i have to use JPARepositery or CrudRepositery in this way:
An example with User entity
public interface UserRepository extends CrudRepository<User, Integer> {
}
and to save
User user = new User();
userRepository.save(user);
But if I have many entities, Do I need to create a repository for each entity?
I have read about Session, FactorySession and Transaction they are compatible with Spring boot? How it works? and #Transactional tag how it works?
Thanks in advance
Yes, usually you need to create one Repository per Entity. This is also a good practice because you are placing operations and queries related to the same Entity in the same Repository.
Yes, you can obtain a Session and a FactorySession object (Hibernate), but I would advice you against using Hibernate directy. Instead, it is better to use Spring Data or JPA mechanisms to access your database (just as you do using a Repository). The reason is because Hibernate is an implementation of the JPA standard and today we use JPA to access databases (because it masks the exact implementation of the ORM). This way you can later (potentially) replace Hibernate with another JPA implementation (such as EclipseLink) without the need to change your code (in theory). In most projects you will find Hibernate being used, however.
Yes, Transaction is a Spring annotation and an important database transaction mechanism in Spring Boot, too.
In My Spring Boot application, I would like to audit DTOs instead of entities and move audit logic to common library which will have #EnableAudit annotation to audit DTO at method level. If I am using JaversBuilder.javers().build(); in common library I would not be able to commit data as it would not know anything of datasource.
I want to create Javers instance in my application and pass datasource to it and then pass Javers instances to common library to perform commit. Is there anyway in Spring boot application to create Javers instance and associat datasource to it which will be used at the time of commit ?
If you take javers-spring-boot-starter, you will get a Javers instance created as a Spring bean. It will be connected to your database and ready-to-use. See https://javers.org/documentation/spring-boot-integration/
I have multiple closely related problems in Spring Security. I am developing using Spring Boot and am using Spring Data REST for creating REST endpoints directly from my repositories.
I have multiple entities and the requirement is to have all these entities as REST endpoints. I am letting spring-data-rest handle the creation of these endpoints and I am securing these endpoints by adding #PreAuthorize and #PostAuthorize to the entity repository methods as and where required. This works great when I am calling an endpoint like /entity/id.
But I am facing issues from here. Let's say I have 2 entities, Entity1 and Entity2 and they have a One to One relationship. Spring data rest allows me to fetch the related Entity2 data from Entity1 like /entity1/id/entity2. But I have different access rights over Entity1 and Entity2 and calling the above endpoint only checks the access rights as set up in the repository for Entity1 only. So, if a user has access to Entity1 table and no access to Entity2 table, he can still see some Entity2 data via the foreign key relationship of Entity1. Is this a correct design?
Moreover we have some custom API endpoints wherein we have to aggregate data from multiple entity repositories. Also, these endpoints themselves have to secured. So, I am using a #PreAuthorize over an endpoint method. This works as expected and the endpoint method is called only when the expression is valid. But, when a repository method is called (via a service class of course), the #PreAuthorize over that repository method is also evaluated. I would like to have the check done with at the beginning. Is it possible to do so?
Any suggestions to improving the design is also welcome.
There is no simple solution without massively modifying/overriding lots of default Spring DataRest features. I'm working such a package for years now and it's working quite well for me.
Although switching to this package might be a bit overkill for you, it could worth the trouble in the long run because it also a fixes a lot of problem you will meet only months later.
you can set up permisison rules via annotation directly in the domain objects.
it checks the permisisons in the DB side, so the traffic between the API and DB is heavily decreased (Only those objects are fetched form the DB which the current user has permission to)
you can set READ/UPDATE/DELETE/CREATE permissions separately for roles and/or certain users
you can use pagination on permission filtered collection
you can use pagination on property-collections too
(+ some extra features like flexible search on multiple properties)
here is the package (It's an extension of Spring Data JPA / Data Rest)
I am new to Redis and trying to implement change Postgres DB into the Redis DB. Current implementation we've used Spring Data JPA (Entity Classes + JPA Repository). Now I wanted to use Spring Data Redis and backend as Redis In Memory DB.
Could you please suggest what changes do I need to make in all Entity classes ? How the persistence will happen ? Do I need to make any changes in Join Table etc.. where I have #ManyToOne and #ManyToMany relationship.
Redis a nosql solution so you will not get the befit of foreign keys as in a RDBMS. You will instead need to convert you data into data-structures supported by Redis. https://redis.io/topics/data-types-intro