I have a code, that when an error returns from a procedure, I need to update a table column in oracle. However, at the time of the update (inside the catch block), the following error occurs:
org.springframework.dao.ConcurrencyFailureException: PreparedStatementCallback; SQL [UPDATE TB_XPTO SET COLUMN_XPTO = XX WHERE ID_XPTO = ?]; ORA-02091: transação repetida
; nested exception is java.sql.SQLTransactionRollbackException: ORA-02091:
My code:
try {
jdbcTemplate.update ("call PROCEDURE_XPTO(?)", ID_XPTO);
} catch (Exception e) {
jdbcTemplate.update("UPDATE TB_XPTO SET COLUMN_XPTO = XX WHERE ID_XPTO = ?", idXpto);
}
My data source Config class
#Bean
public DataSourceBuilder<?> dataSourceBuilder(Environment springEnvironment) {
DataSourceBuilder<?> dataSourceBuilder = DataSourceBuilder.create();
dataSourceBuilder.driverClassName("oracle.jdbc.OracleDriver");
dataSourceBuilder.url("jdbc:oracle:thin:#//server:1521/database.com.br");
dataSourceBuilder.username("user");
dataSourceBuilder.password("pass");
return dataSourceBuilder;
}
#Bean
public DataSource getDataSource(DataSourceBuilder<?> dataSourceBuilder) {
return dataSourceBuilder.build();
}
Any idea ?
thanks for your answer, but worked for me, using #Transactional, in the method that calls the procedure.
Related
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.
I have been trying to call a function that i created using jpa but i keep getting this error
(org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: com.microsoft.sqlserver.jdbc.SQLServerException: 'udf_searchEmployeeLeaves' is not a recognized built-in function name.
Error Code: 195)
public List<EmployeeLeaves> searchEmployeeLeaves(String str) throws EmployeeLeavesException {
try {
Query query = em.createNativeQuery("SELECT udf_searchEmployeeLeaves(?1) FROM LAB ");
query.setParameter(1, str);
return query.getResultList();
} catch (Exception e) {
throw new EmployeeLeavesException("[searchEmployeeLeaves-ERROR]: " + e.getMessage());
}
}
I think the call is incorrect.
You have to call the table function like this:
Query query = em.createNativeQuery("SELECT * FROM udf_searchEmployeeLeaves(?1)");
What I want to achieve is, I would like to do a no lock query execution in select statement. But according to this answer it is impossible to achieve this with direct JPA implementation. I also understood from searches that nolock and READ_UNCOMMITTED are same. Is there any way to achieve this(no lock, READ_UNCOMMITTED) by modifying my below code. Or should I use the native query with specifying WITH(NOLOCK)
I had tried
entityManager.createQuery(query).setLockMode(LockModeType.NONE).getResultList();
but it also not solving my issue.
My references this, this , this, this
I am using the following code to get data from table. this code works fine without nolock.
String query = "FROM Employee WHERE empId=:empId AND empStatus='failed'";
to fetch data from db
public Object getListFromQuery(String query) throws Exception {
Object resultObject = null;
List<Object> queryResultList = null;
EntityManager entityManager = null;
try {
entityManager = entityManagerFactory.createEntityManager();
queryResultList = entityManager.createQuery(query).getResultList();
resultObject = (Object) queryResultList;
} catch (Exception ex) {
LOGGER.error("Exception : DatabaseManager :executeQueryGetList ",ex);
throw ex;
} finally {
entityManager.close();
}
return resultObject;
}
Database configuration
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory()
throws NamingException {
LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();
factoryBean.setDataSource(dataSource());
factoryBean
.setPackagesToScan(new String[] { "com.test.middleware.entity" });
factoryBean.setJpaVendorAdapter(jpaVendorAdapter());
factoryBean.setJpaProperties(jpaProperties());
factoryBean.setPersistenceUnitName("test_unit");
return factoryBean;
}
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);
}
}
Using Postgresql 8.1, Spring 3.0, Hibernate 3.6.
I have a method that calls a stored procedure that works without using Annotations, essentially it is
....
return (Integer) getJpaTemplate().execute(new JpaCallback() {
public Object doInJpa(EntityManager em) {
// Query query = em.createNamedQuery("checkZone");
Query query = em.createNativeQuery("select zoneArea from zoneArea(:pId, :zId)");
query.setParameter("pId", p.getId());
query.setParameter("zId", z.getId());
try {
return query.getSingleResult(); // Integer expected
} catch (NoResultException e) {
return 0;
}
}
});
....
How can I do this with Annotations, here's my attempt that does not work.
#NamedNativeQueries({
#NamedNativeQuery(
name = "checkZone",
query = "select zoneArea from zoneArea(:pId, :zId)",
hints = {
#QueryHint(name = "org.hibernate.callable", value = "true")
},
resultSetMapping = "scalar",
resultClass = Integer.class)})
#SqlResultSetMapping(name="scalar",columns=#ColumnResult(name="result"))
#Entity
and here is the Exception
Caused by: org.postgresql.util.PSQLException: This statement does not declare an OUT parameter. Use { ?= call ... } to declare one.
at org.postgresql.jdbc2.AbstractJdbc2Statement.registerOutParameter(AbstractJdbc2Statement.java:1849)
at org.postgresql.jdbc3.AbstractJdbc3Statement.registerOutParameter(AbstractJdbc3Statement.java:1513)
at org.hibernate.dialect.PostgreSQLDialect.registerResultSetOutParameter(PostgreSQLDialect.java:335)
at org.hibernate.loader.Loader.prepareQueryStatement(Loader.java:1713)
at org.hibernate.loader.Loader.doQuery(Loader.java:801)
I have working code but would like to get this working with Annotations, any ideas appreciated.