Transaction does not retrieve on time data - oracle

I have a project with many services. I'm using pure jpa with jersey in my project.
I use entityManager, entityTransaction and entityManagerFactory in this way: for each service I get an EntityManager from DBManager.getEntityManager() and get and entityTransaction from its entityManager
public class DBManager {
public static EntityManager getEntityManager() {
return Persistence.createEntityManagerFactory("projectDataSource").getEntityManager();
}
In each method that need transaction, first I check transaction != null and transaction is not active
Then I begin the transaction.
I evict cache and after all of this I do my job: in this example I get all active users from database, and my service that returns users list to client.
One of my services is : #getUsersService
public class GetUsersServiceImpl {
private static EntityManager entiyManager = DBManager.getEntityManager();
private static EntityTransaction entityTransaction = entityManager.getTransaction();
public List<User> getUsers()
if (transaction != null && !transaction.isActive())
transaction.begin()
entityManager.getEntityMangerFactory().getCache().evictAll();
return entityManger.createQuery("SELECT u FROM USER u WHERE u.isActive = true").getResultList();
}
This code works but not always!
I have another service that changes the users; this user also works and changes user data in database, but after calling change service when I call getUsers service, it retrieves old database data
Why does this happen?
Is it correct the way I use entityManager and entityTransaction ...

Related

Spring Data JpaRepository throws LazyInitializationException when using method getById() but not when using findById()

in my Spring Boot (version 2.5.4) I have a service that executes one of its methods by a ExecutorService (in new Thread). in this new Thread I access some of my repositories (JpaRepositorys). I see different behavior in JpaRepository's getById() and findById(), I searched but did not found any.
this is my entity:
#Getter
#Setter
#AllArgsConstructor
#NoArgsConstructor
#Entity
public class LimoSet {
#Id
#Column(name = "_id")
private String id;
#Column(name = "_status")
private String status;
#OneToMany(mappedBy = "set", fetch = FetchType.EAGER)
private Set<Limo> limos = new LinkedHashSet<>();
#Column(name = "_statistics")
private String statistics;
}
this is repository:
#Repository
public interface LimoSetRepository extends JpaRepository<LimoSet, String> {
}
and this is the service:
#Service
#Transactional
public class GeneratorService {
private final static Logger logger = LoggerFactory.getLogger(GeneratorService.class);
private final LimoSetRepository setRepository;
private final ExecutorService executor = Executors.newFixedThreadPool(3);;
public void generate(Options opts) {
.
.
.
Callable<String> task = () -> {
try {
this.runGenerate(opts);
} catch (JsonProcessingException e) {
e.printStackTrace();
} catch (RuntimeException e) {
e.printStackTrace();
var set = setRepository.getById(opts.getName());
set.setStatus(e.getMessage());
setRepository.save(set);
}
return "ok";
};
executor.submit(task);
}
void runGenerate(Options opts) throws JsonProcessingException {
.
.
.
var set = setRepository.findById(opts.getName()).get(); //this is ok
var set = setRepository.getById(opts.getName()); //this throws LazyInitializationException
set.setStatus("GENERATED"); //the Exception is reported in this line
setRepository.save(set);
}
}
why findById() works but getById() does not?
There are a few factors which sum up to the LazyInitializationException.
For primers:
get acquainted with the different semantics of findById and getById
findById fetches entire object
getById fetches object proxy
See: How do find and getReference EntityManager methods work when using JPA and Hibernate
When loading a Proxy, you need to be aware that a LazyInitializationException can be thrown if you try to access the Proxy reference after the EntityManager is closed.
Secondly, you need to understand why runGenerate runs with no active transaction, even if the class is marked as #Transactional.
(Note: no active transaction is the root cause of closed EntityManager)
To make sure that the transaction is not active, see Detecting If a Spring Transaction Is Active:
assertTrue(TransactionSynchronizationManager.isActualTransactionActive());
Why parent transaction from the test is not propagated
runGenerate is run via executor on a separate thread
active transaction is kept as a thread-local, so transactions do not propagate across threads.
Why #Transactional on runGenerate has no effect?
Spring (by default) uses CGLIB proxies to enable aspects.
CGLIB proxies has 2 requirements:
the proxied method must be public
you must call the method via the proxy (not via the actual object)
None of these conditions is met.
Why the transaction is active in the test itself
Spring provides a special TestExecutionListener called TransactionalTestExecutionListener, which checks if the test method is marked as #Transactional, and starts transaction if needed
How to fix
extract runGenerate to a service, mark it as public and #Transactional
autowire the new service into your test
more generally, take note what parts of your task operate under transactional context (catch block of your task is not transactional)
also more generally, learn about dirty checking. once you have your methods to run under transactional context, the save calls will be redundant.

In Spring data JPA ,How to query data from a table without a repository for entity

Is it possible to fetch data from a table without creating a JPA repository for this specific table.
I need to do this as there are considerable number of entities which I have to do a simple query , it would be a waste to create repositories for each of them.
You can simply inject an EntityManager to any component:
#Component
class SomeComponent {
#PersistenceContext
private EntityManager entityManager;
public List<SomeEntity> findAllEntities() {
TypedQuery<SomeEntity> query = entityManager.createQuery("SELECT e FROM SomeEntity e", SomeEntity.class);
return query.getResultList();
}
}
Also, if your entities have the same superclass, you can use the same Repository for all of them, like described there.

Hibernate - Table Locked after update

I'm performing an update via a method using Hibernate and the EntityManager.
This update method is called multiple times (within a loop).
It seems like when I execute it the first time, it locks the table and does not free it.
When trying to update the table via SQL Developer after having closed the application, I see the table is still locked because the update is hanging.
What do you see as a solution to this problem? If you need more information, let me know.
Class
#Repository
#Transactional(propagation = REQUIRES_NEW)
public class YirInfoRepository {
#Autowired
EntityManager entityManager;
#Transactional(propagation = REQUIRES_NEW)
public void setSent(String id) {
String query = "UPDATE_QUERY";
Query nativeQuery = entityManager.createNativeQuery(String.format(query, id));
nativeQuery.executeUpdate();
}
}
UPDATE
After having waited more than one hour, I launched the application again and it worked fine once but now again, it hangs.
UPDATE 2 -- I'll give a maximum bounty to whoever helps me solve this
On another place I use an application managed entity manager and it still gives me the same type of errors.
public void fillYirInfo() {
File inputFile = new File("path");
try (InputStream inputStream = new FileInputStream(inputFile);
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream))) {
bufferedReader.lines().skip(1).limit(20).forEach(line -> {
String[] data = line.split(",");
String rnr = data[0];
String linked = data[1];
String email = data.length > 2 ? data[2] : "";
String insuredId = insuredPeopleRepository.getInsuredIdFromNationalId(rnr);
int modifiedCounter = 0;
if (!isNullOrEmpty(insuredId)) {
EntityManager entityManager = emf.createEntityManager();
EntityTransaction transaction = entityManager.getTransaction();
Query nativeQuery = entityManager.createNativeQuery(
"QUERY"
);
transaction.begin();
nativeQuery.executeUpdate();
entityManager.flush();
transaction.commit();
entityManager.close();
}
System.out.println(modifiedCounter + " rows modified");
});
} catch (IOException e) {
e.printStackTrace();
}
}
Try without an update-query:
#Repository
#Transactional(propagation = REQUIRES_NEW)
public class YirInfoRepository {
#Autowired
EntityManager entityManager;
#Transactional(propagation = REQUIRES_NEW)
public void setSent(String id) {
//guessing your class name and method..
final YirInfo yirInfo = entityManager.find(YirInfo.class, id);
yirInfo.setSent();
}
}
Might not be as fast as a single update query, but it's possible to get it reasonably fast, unless the amount of data is huge. This is the preferred way of using Hibernate/JPA, instead of thinking in terms of single values and SQL queries, you work with entities/objects and (sometimes) HQL/JPQL queries.
You are using #Transactional annotation. This means you are using Spring Transaction. Then in your UPDATE 2 you are using transaction by yourself and managed by spring (I guess it's another project or class not managed by Spring).
In any case what I would do is to try to update your records in single spring transaction and I'd not use #Transactional in DAO layer but in service layer. Something like this:
Service layer:
#Service
public class YirInfoService {
#Autowired
YirInfoRepository dao;
#Transactional(propagation = REQUIRES_NEW)
public void setSent(List < String > ids) {
dao.setSents(ids);
}
}
DAO layer:
#Repository
public class YirInfoRepository {
#Autowired
EntityManager entityManager;
//Here you can update by using and IN statement or by doing a cycle
//Let's suppose a bulk operation
public void setSents(List < String > ids) {
String query = "UPDATE_QUERY";
for (int i = 0; i < ids.size(); i++) {
String id = ids.get(i);
Query nativeQuery = entityManager.createNativeQuery(String.format(query, id));
nativeQuery.executeUpdate();
if (i % 20 == 0) {
entityManager.flush();
entityManager.clear();
}
}
}
}
The first thing you have to understand is that for the first example, you are using a native query to update rows in the DB. In this case you are completely skipping Hibernate to do anything for you.
In your second example, you have the same thing, you are updating via an update query. You don't need to flush the entity manager as it's only necessary for transferring the pending changes made to your entity objects within that entity manager.
Plus I don't know how your example works as you are autowiring the entity manager and not using the #PersistenceContext annotation. Make sure you use this one properly because you might have misconfigured the application. Also there is no need to manually create the entity manager when using Spring as it looks in the second example. Just use #PersistenceContext to get an entity manager in your app.
You are also mixing up transaction management. In the first example, it's enough if you put the #Transactional annotation to either of your method or to the class.
For the other example, you are doing manual transaction management which makes no sense in this case. If you are using Spring, you can simply rely on declarative transaction management.
The first thing I'd check here is to integrate datasource-proxy into your connection management and log out how your statements are executed. With this info, you can make sure that the query is sent to the DB side and the DB is executing it very slowly, or you are having a network issue between your app and db.
If you find out that the query is sent properly to the DB, you want to analyze your query, because most probably it's just executed very slowly and needs some optimizations. For this, you can use the Explain plan feature, to find out how your execution plan looks like and then make it faster.

How to use OpenSessionInViewInterceptor?

Consider entity
public class User {
...
#OneToMany(cascade = CascadeType.ALL)
List<SocialCredential> credentialsList = new ArrayList<SocialCredential> ();
}
with DAO Implementation method
#Transactional
#Override
public User getUser(long id){
Session s = sessionFactory.getCurrentSession();
User u = (User) s.get(User.class, id);
return u;
}
and Controller
#Controller
public class DummyController {
#Autowired
UserDAO userDAO;
public void anyMethodAccessedByGetORPost(){
User u= userDAO.getUser(1L);
}
}
A simple query for entity User automatically fires query to initialize entity list of SocialCredential ? Ultimately it leads to LazyInitializationException.I came to know to know about OpenSessionInViewInterceptor which can solve the issue.How can I apply the same. I am already following http://www.jroller.com/kbaum/entry/orm_lazy_initialization_with_dao but with no success so far.
A simple query for entity User automatically fires query to initialize entity list of SocialCredential ?
It depends on underlying persistence API's default fetch type.
Refer this question
Ultimately it leads to LazyInitializationException -- This is probably you are trying access credentialsList collection after session has been closed.
Replace DAO's getUser(Long id) method with below code may solve LazyInitializationException.
#Transactional
#Override
public User getUser(long id){
Session s = sessionFactory.getCurrentSession();
User u = (User) s.get(User.class, id);
if (u != null) {
u.getCredentialsList(); //it loads the SocialCredentials before session closes.
}
return u;
}

OptimisticLockException not thrown when version has changed

I've created a simple EJB application that uses JPA for persistence and have a problem whereby optimistic locking is not functioning as I would have expected.
The application contains a class named Site which defines the model for a table named SITE in the database. The SITE table contains a column named ROW_VERSION which is referenced in the Site class using the #version annotation.
Whenever the record is updated, the ROW_VERSION is incremented by 1. So far, so good.
The problem arises when the row has changed in the time between the application reading the row using the EntityManager find method and the row being updated by the EntityManager merge method. As the ROW_VERSION for the row has been incremented by 1 and therefore is not the same as when the EntityManager find method was called, I would expect an OptimisticLockException to be thrown, but instead the changes are written to the table and in turn overwriting the changes made by the other process.
The application is running on WebSphere 8.5 and is using OpenJPA provided by the container.
Have I mis-understood how optimistic locking is supposed to work or is there something else that I need to do to make the OptimisticLockException occur?
The Site class is as follows:
#Entity
#Table(name="SITE")
public class Site {
#Id
#Column(name="SITE_ID")
private int id;
#Column(name="SITE_NAME")
private String siteName;
#Column(name="SITE_ADDRESS")
private String address;
#Column(name="ROW_VERSION")
#Version
private long rowVersion;
//getters and setters
}
The application makes uses of the Generic DAO wrapper class to invoke the EntityManager methods. The contents of the class are as follows:
public abstract class GenericDAO<T> {
private final static String UNIT_NAME = "Test4EJB";
#PersistenceContext(unitName = UNIT_NAME)
private EntityManager em;
private Class<T> entityClass;
public GenericDAO(Class<T> entityClass) {
this.entityClass = entityClass;
}
public T update(T entity) {
return em.merge(entity);
}
public T find(int entityID) {
return em.find(entityClass, entityID);
}
//other methods
}
Update - I've done some more investigation and have found this http://pic.dhe.ibm.com/infocenter/wasinfo/v8r0/index.jsp?topic=%2Fcom.ibm.websphere.nd.multiplatform.doc%2Finfo%2Fae%2Fae%2Fcejb_genversionID.html but even when I've added the #VersionColumn and #VersionStrategy annotations I still cannot get the OptimisticLockException to be thrown.

Resources