#NamedNativeQuery Constraint violation - Transaction - java

I have this #NamedNativeQuery
#NamedNativeQuery(name = "Certificacion.updateCertificacionAclaraciones", query = "UPDATE CERTIFICACION "
+ "SET PENDIENTE_GENERACION = :pendienteGeneracion, ID_ACLARACIONES_TEMP_ESCRITO = :idAclaracion "
+ "WHERE ID IN (:paso)")
And I have this EJB structure to get a transaction
#TransactionManagement(TransactionManagementType.CONTAINER)
#Stateless
public class PRequerimientoCCServiceBean implements
IPRequerimientoCCServiceBeanLocal {
#Override
#TransactionAttribute(TransactionAttributeType.REQUIRED)
public void guardarRequerimiento(Usuario usuario,
ConjuntoCertificaciones conjunto, String aclaracionGeneral,
Map<Long, String> mapAclaracionColegio) throws RollbackException {
try {
// Realizamos el guardado de las aclaraciones y la generaciĆ³n del
// documento
AclaracionesTempEscrito currentAclaracion = new AclaracionesTempEscrito();
...
entityManager.persist(currentAclaracion);
generarDocumento(currentAclaracion, conjunto, usuario);
} catch (Exception e) {
ejbContext.setRollbackOnly();
throw new RollbackSajgException();
}
}
#TransactionAttribute(TransactionAttributeType.MANDATORY)
private void generarDocumento(AclaracionesTempEscrito findAclaracion,
ConjuntoCertificaciones conjunto, Usuario usuario)
throws RollbackException {
...
Query actualizaCertificacionesAclaracion = entityManager
.createNamedQuery("Certificacion.updateCertificacionAclaraciones");
actualizaCertificacionesAclaracion
.setParameter("pendienteGeneracion", true)
.setParameter("idAclaracion", findAclaracion.getId())
.setParameter("paso", paso).executeUpdate();
}
}
It suppose that I will execute commit when guardarRequerimiento method ends but when I execute my nativeQuery with executeUpdate I get an exception of ConstraintViolation
org.hibernate.exception.ConstraintViolationException: could not
execute statement
I think that it is because although findAclaracion.getId() exists in the transaction, it does not exist in database and the executeUpdate need that this object exist in database because is not in my persistence context when execute.
Why do I get this behaviour? How can I solve?
Thank you.

You can try to refresh this object after flush and before generarDocumento(currentAclaracion, conjunto, usuario);
or
you can do it as query and loop that objectList updating values..

Related

Parameterize Java JPA ALTER SESSION SQL

I am having a problem with setting a parameter in an SQL Query statement created from a JPA EntityManager.
I am working in an EJB and the EntityManager object for the session is valid.
import javax.persistence.EntityManager;
import javax.persistence.Query;
pubic void methodWorks(EntityManager em, String schema) {
String sqlStmt = "ALTER SESSION SET CURRENT_SCHEMA = " + schema;
try {
em.createNativeQuery(sqlStmt).executeUpdate();
}
catch(Exception ex) {
ex.printStackTrace();
}
}
pubic void methodFails1(EntityManager em, String schema) {
String sqlStmt = "ALTER SESSION SET CURRENT_SCHEMA = ?";
try {
em.createNativeQuery(sqlStmt).setParameter(1, schema).executeUpdate();
}
catch(Exception ex) {
ex.printStackTrace();
}
}
pubic void methodFails2(EntityManager em, String schema) {
String sqlStmt = "ALTER SESSION SET CURRENT_SCHEMA = ?1";
try {
em.createNativeQuery(sqlStmt).setParameter(1, schema).executeUpdate();
}
catch(Exception ex) {
ex.printStackTrace();
}
}
pubic void methodFails3(EntityManager em, String schema) {
String sqlStmt = "ALTER SESSION SET CURRENT_SCHEMA = :inputSchema";
try {
em.createNativeQuery(sqlStmt).setParameter("inputSchema", schema).executeUpdate();
}
catch(Exception ex) {
ex.printStackTrace();
}
}
The problem is that a Fortify Scan (which this must pass) identifies the sqlStmt in the methodWorks method as being vulnerable to an SQL Injection Attack (from Fortify). The failed methods all report
Internal Exception java.sql.SQLSyntaxErrorException: ORA:-02421 mission or invalid schema authorization identifier.
Error Code 2421
Call: ALTER SESSION SET CURRENT_SCHEMA = ?
bind => [1 parameter bound]
Merely sanitizing the input parameter "isn't good enough" to pass the Fortify and QA.
Setting it as a parameter (which hint-hint: CAN be easily fooled) will pass the Fortify scan and QA requirements.
This query is indeed open to SQL injection because you're using string concatenation.
The safe way to handle a query like this is to use parameters.
String sqlStmt = "ALTER SESSION SET CURRENT_SCHEMA = ?";
Query updateQuery = em.createNativeQuery(sqlStmt);
updateQuery.setParameter(0, schema);
updateQuery.executeUpdate();
Parameter values are automatically escaped for you. This saves you time as you don't need to worry about SQL injection any longer. This is solved in the Query/EntityManager class.
Also, it makes the query a lot easier to read.

call procedure with out parameters in hibernate3

I work with hibernate3 and didn't use JPA
I have a procedure in oracle which return 2 out parameter
For test I execute this procedure in oracle with this query.
declare
req_type number;
req_seq number;
begin
insert_req(1111,req_type,req_seq);
dbms_output.put_line('req_type='||req_type);
dbms_output.put_line('req_seq='||req_seq);
end;
Now I want to call this procedure using hibernate
I try with native query without success using this code :
public void insertReq(String numEmp) {
int req_type ;
int req_seq;
String sql = " insert_req(1111,:in1,:in2) ";
SQLQuery query = session.createSQLQuery(sql);
query.setParameter("in1", req_type);
query.setParameter("in2", req_seq);
List results = query.list();
System.out.println(req_type);
System.out.println(req_seq);
}
when I have a function I can run it using hibernate using this code as an example :
public void insertOrder(String numEmp) {
String query = "call insert_order(" + numEmp + ",50)";
SQLQuery sqlQuery = this.getSession().createSQLQuery(query);
sqlQuery.executeUpdate();
}
but the problem is how to call procedure with 2 out parameter using hibernate.
you have to use CallableStatement and registerOutParameter.
you can get a connection from your hibernate session and create the callablestatement.
hibernate does not provide a mecanism to deal with this (at least as i know).
i hope that helps.
Try this and let me know.
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
Session session = em.unwrap(Session.class);
session.doWork(new Work() {
#Override
public void execute(Connection con) throws SQLException {
// do something useful
try (CallableStatement stmt = con.prepareCall("{call my_sp()}")) {
stmt.execute();
}
}
});
em.close();
Best regards.

Mock spring's LocalContainerEntityManagerFactoryBean method using Mockito?

I am trying to write unit testcases for the below code and am trying to mock the EntityManager implementation. I am unable to do so and I get null entity manager bean in my test class.
public List<Object[]> getForecastResults(String query, String siteId, long startTime, long endTimestamp)
{
List<Object[]> result = null;
EntityManager em = null;
try {
query = String.format(query, startTime, endTimestamp, siteId);
logger.debug(" Query : " + query);
em = localContainerEntityManagerFactoryBean.nativeEntityManagerFactory.createEntityManager();
EntityTransaction et = em.getTransaction();
et.begin();
result = (List<Object[]>) em.createNativeQuery(query).getResultList();
//logger.debug("Results from the query : " + query + " are :" + Utility.toJsonString(result, true));
} catch (Exception ex) {
ex.printStackTrace();
logger.error("Error Occurred while fetching the data for the query : " + query);
}
return result;
}
The test code I have written to mock it is below:
#InjectMocks
private LocalContainerEntityManagerFactoryBean emMock = new LocalContainerEntityManagerFactoryBean();
...
Mockito.when(localContainerEntityManagerFactoryBean.nativeEntityManagerFactory.createEntityManager()).thenReturn();
I should return a list when this is called as output So i need the whole method to be mocked. Please help !
First off all instead of #InjectMocks you should be using #Mock and put the #InjectMocks on the class you are trying to unit test.
However the fact that you are even considering mocking the LocalContainterEntityManagerFactoryBean is a sign that your code is flawed. You shouldn't be using the LCEMFB in code. It is only for configuration. It is a FactoryBean that creates an EntityManagerFactory so actually you should be injecting an EntityManagerFactory into your code which you should be mocking.
Instead of wiring the LCEMFB use the plain EMF and get an instance by annotating the field with #PersistenceUnit.
#PersistenceUnit
private EntityManagerFactory emf;
Then your method is also a bit cleaner
public List<Object[]> getForecastResults(String query, String siteId, long startTime, long endTimestamp)
{
List<Object[]> result = null;
EntityManager em = null;
try {
query = String.format(query, startTime, endTimestamp, siteId);
logger.debug(" Query : " + query);
em = emf.createEntityManager();
EntityTransaction et = em.getTransaction();
et.begin();
result = (List<Object[]>) em.createNativeQuery(query).getResultList();
//logger.debug("Results from the query : " + query + " are :" + Utility.toJsonString(result, true));
} catch (Exception ex) {
ex.printStackTrace();
logger.error("Error Occurred while fetching the data for the query : " + query);
}
return result;
}
However what you actually should be doing is injecting an EntityManager and don't try to create one yourself (your code is still flawed as you aren't closing the transaction nor the created EntityManager which in turn will eventually lead you to being unable to connect to your database as the underlying Connection remains open as well.
So instead of injecting either the LCEMFB or a EMF use a plain EntityManager instead and let spring manage it for you. To have spring manage the transaction make sure there is an #EnableTransactionManagement or <tx:annotation-driven /> in your configuration else it won't work.
#PersistenceContext
private EntityManager em;
Now your method is really focussed on what it should do, get data from the database.
#Transactional(readOnly=true)
public List<Object[]> getForecastResults(String query, String siteId, long startTime, long endTimestamp) {
query = String.format(query, startTime, endTimestamp, siteId);
return em.createNativeQuery(query).getResultList();
}
Now in your test you should only need to mock the EntityManager.
All of this is also explained in the ORM chapter of the Spring Reference guide.
Another thing that worries me is that you are using a String and parsing that to be used as a query. This is potentially dangerous and a cause for SQL injection attacks. Instead of doing the formatting yourself you should let it be handled by Hibernate or JDBC.
#Transactional(readOnly=true)
public List<Object[]> getForecastResults(String query, String siteId, long startTime, long endTimestamp) {
query = String.format(query, startTime, endTimestamp, siteId);
Query q = em.createNativeQuery(query);
q.setParameter("siteId", siteId)
.setParameter("startTime", startTime)
.setParameter("endTime", endTimestamp);
return q.getResultList();
}
The code above assumes a query in the form of SELECT * FROM YOURTABLE WHERE siteId=:siteId and startTime >= :startTime and endTime <= :endTime (or whatever your SQL looks like).

Kundera cassandra - Transaction rollback and Entity update

I use Kundera-Cassandra 3.2 and want to use the transaction management from Kundera.
My handling looks like this:
EntityManager manager = repo.getEntityManagerFactory().createEntityManager(CassandraRepository.getProperties());
try{
manager.getTransaction().begin();
this.repo.update(account1, manager); //calls the merge method of the Entitymanager
this.repo.save(account2, manager); //calls the persist method of the Entitymanager
manager.getTransaction().commit();
} catch(Exception e){
if(manager.getTransaction().isActive()){
manager.getTransaction().rollback();
}
} finally {
manager.clear();
manager.close();
}
When an error in the this.repo.save(account2, manager); occurs, the manager rollbacks the transaction, but does not do a update statement, he makes a delete statement for the merge method. The reason for this is, when calling the merge methode, kundera creates an insert statement and not an update. But how to say Kundera to make an update to rollback the transaction also with an update.
Logs:
12:42:41.185 [http-bio-8080-exec-3] INFO com.impetus.client.cassandra.CassandraClientBase - Returning delete query DELETE FROM "account" WHERE "id" = 'MCSP-000000000004'.
12:42:41.211 [http-bio-8080-exec-3] INFO com.impetus.client.cassandra.CassandraClientBase - Returning delete query DELETE FROM "account" WHERE "id" = 'MCSP-000000000005'.
EDIT (my repository):
public class CassandraRepository<T> {
#PersistenceUnit
private EntityManagerFactory entityManagerFactory;
public static Map<String, String> getProperties() {
final Map<String, String> properties = new HashMap<String, String>();
properties.put(CassandraConstants.CQL_VERSION, CassandraConstants.CQL_VERSION_3_0);
return properties;
}
public void update(T entity, EntityManager manager) throws Exception{
try {
manager.merge(entity);
} catch (Exception e) {
e.printStackTrace();
throw e;
}
}
public void save(T entity, EntityManager manager) throws Exception{
try {
manager.persist(entity);
} catch (Exception e) {
e.printStackTrace();
throw e;
}
}
}
According to JPA, to update an entity you have to first bring it into managed state (by fetching it)
Example:-
PersonCassandra p = entityManager.find(PersonCassandra.class, "2");
entityManager.getTransaction().begin();
p.setMonth(Month.JAN);
entityManager.merge(p);
entityManager.persist(p3);
entityManager.getTransaction().commit();
Issue is not with INSERT and UPDATE statements since both are similar for Cassandra, under the hood.

Column querying from connection not working for Postgresql but not for Hsql in Java

I am encountering weird behavior where my integration tests for my JPA Configuration are failing for postgresql but passing for hsql. There are no code changes to the test and assertion method.
I have verified that the table and columns are being added appropriately to the database. Verification for table existence passes ok, but only the column check fails unexpectedly.
What is the root cause of this? Is there a workaround or fix for this issue?
Test:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes=PersistenceConfig.class)
#Transactional
#TransactionConfiguration(defaultRollback=true)
public class UserMappingIntegrationTest {
#Autowired
EntityManager manager;
#Test
public void thatUserMappingWorks() {
assertTableExists(manager, "USER_TABLE");
assertTableHasColumn(manager, "USER_TABLE", "NAME");
}
}
Assertion method:
public static void assertTableHasColumn(EntityManager manager,
final String tableName, final String columnName) {
SessionImpl session = (SessionImpl) manager.unwrap(Session.class);
final ResultCollector rc = new ResultCollector();
session.doWork(connection -> {
ResultSet columns = connection.getMetaData().getColumns(null, null,
tableName.toUpperCase(), null);
while (columns.next()) {
if (columns.getString(4).toUpperCase()
.equals(columnName.toUpperCase())) {
rc.found = true;
}
}
});
if (!rc.found) {
fail("Column [" + columnName + "] not found on table : "
+ tableName);
}
}

Categories