Issue
This is the source code causing the error:
@Override
@Transactional
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public Object queryObject(String query) throws Exception {
Object o = null;
EntityTransaction tr = em.getTransaction();
try {
if (!tr.isActive()) {
tr.begin();
}
List<Object> objectsList = em.createQuery(query).getResultList();
if (!objectsList.isEmpty()) {
o = objectsList.get(0);
}
em.flush();
em.clear();
em.close();
tr.commit();
} catch (Exception e) {
tr.rollback();
System.out.println("" + e.getMessage());
}
return o;
}
And this is the instruction where the method is called:
UserAccount userAccount = (UserAccount) accountDao.queryObject("select u.identifier,u.email,u.password from UserAccount as u where identifier=" + account.getIdentifier() + " and password=" + account.getPassword());
Solution
You are using container managed transactions - you don't need to do this yourself.
Your code can collapse down to:
@Override
@Transactional
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public Object queryObject(String query) throws PersistenceException {
try {
return em.createQuery(query).getSingleResult();
} catch (NonUniqueResultException e) {
// too many results
return null;
} catch (NoResultException e) {
// not enough results
return null;
}
}
However
Composing queries like this:
"select u.identifier,u.email,u.password from UserAccount as u where identifier="
+ account.getIdentifier() + " and password=" + account.getPassword())
can lead to SQL injection attacks.
The JPA javax.persistence.Query class has a bunch of setParameter
methods that you must use to circumvent this.
Therefore it's generally easier to write specific query methods instead of the generic method that you're trying here.
Answered By - Steve C
Answer Checked By - Terry (JavaFixing Volunteer)