Custom query within JPA server-managed session - jdbc

I'm trying to execute an unrelated query (other_table) within a JTA session (server-managed) in order to do some validations, before persisting the bean EJB into DB with JPA.
Here is what I want to do (aprox):
#PersistenceUnit(unitName="DynamicDatabase")
EntityManagerFactory emf;
#TransactionAttribute(TransactionAttributeType.REQUIRED)
private long nextEntryid() {
em = emf.createEntityManager();
Query query = em.createQuery("select t from OTHER_TABLE t");
// do some validation and checking
MyTable bean = new MyTable();
em.persist(bean);
}
However I keep getting a server error, it does not allow to interact with other database items that are not persisted:
org.apache.openjpa.persistence.ArgumentException:
An error occurred while parsing the query filter (query): The name "OTHER_TABLE" is not a recognized entity (...) Perhaps you meant MyTable, which is a close match.
<persistence-unit name="DynamicDatabase" transaction-type="JTA">
<jta-data-source>jdbc/DB2DynamicConnection</jta-data-source>
<class>jorge.java.dynamicdatabase.db.MyTable</class>
</properties>
</persistence-unit>
The question is: what is the proper way to query/alter another table within the same JPA DB connection and JTA transaction?
Pretty newby about this, please be patient with me. Been working on this very long.
Edit: I don't think it's related but FYI I'm using WebSphere Liberty Profile 8.5.5.4, JSDK 8u31, EclipseEE Luna 4.4.2 for Web Dev. Going to add it to tags.

The problem is that you have a #NamedQuery that references the entity OTHER_TABLE, and that does not exist or not marked as being an Entity (try in both Java class and persistence.xml).
If the OtherTable Java class is not an entity and if it MUST remain so, then you could use Constructors in JPQL-queries:
SELECT NEW com.domain.reports.MyReport(u.firstName, u.lastName, u.birthday) FROM User u
If you need to write plain SQL queries, then you could do it using native queries, as they are known in the JPA specification.

Based on Andrei's suggestion, the JPQL (Java Persistence Query Language) operates on objects, not on tables. This means that em.createQuery() can't be used for universal database interaction.
To execute any SQL statement generally speaking (inside the container-managed transaction JTA), it is necessary to get the DB connection from the entity manager (it will return the persistence context unit JPA).
// Get container's objects
em = emf.createEntityManager();
java.sql.Connection conn = em.unwrap(java.sql.Connection.class);
// Run the query
Statement sql = conn.createStatement();
ResultSet rs = sql.executeQuery("select * from OTHER_TABLE");
rs.next()
(...)
//Container-managed connection shouldn't be closed.
rs.close;
sql.close;
Notice that unwrap call works for JPA but not for Hibernate (other questions already exist on this point). Notice the different language used for the SQL statement select * from than a named query JPQL select t from. Exception handling must be also controlled as usual with a } finally { clause.
That way would allow to execute a complex custom statement within server-managed transaction without using JAVA entities and I can finally sleep.

Related

Why Update using #Query in Spring Data Jpa requires #Transactional

I am new to spring boot. I use spring data jpa to deal with database. I have a method to update a table in the database using #Query. But when I try to update I get an exception of invalidDataAccessApiUsageException. when I tried it with #Transactional it gets updated successfully. Aren't updates a single operation so wouldn't it get committed automatically.
There are 2 ways in which transaction execute in SQL
Implicit -> One that means database, while running the write query(UPDATE, INSERT ....), create an isolation and then execute. If an error occurs, the isolation is discarded and no change will be written.
Explicit -> In this you explicitly specify the isolation start using BEGIN , discarding by ROLLBACK and finally writing by COMMIT
Initial versions of postgres (<7.4) had a configuration to called AUTOCOMMIT which when set off, will DISABLE implicit transactions. But this was disabled in 2003 since the databases were smart enough to discard isolations and not create inconsistencies.
In a nutshell at any point running following queries
UPDATE table_name WHERE id IN (....)
or
BEGIN
UPDATE table_name WHERE id IN (....)
COMMIT
are EXACTLY the same.
In JPA autocommit is now just a runtime validation for write queries.

Spring boot #Query ignores #Table on view call

I have a spring boot 2 application that works great with entities that are mapped to a table that is in a MariaDB. I now do a view call and I have mapped that entity to the view using the #Table(name="ViewExpiredAccounts") annotation and now when the method is called the table name is ignored. I have a JpaRepository with this method:
#Query(value = "SELECT v FROM ViewExpiredAccounts v")
List<ViewExpiredAccount> expiredAccounts();
When I call this method I get an error:
Table 'view_expired_accounts' doesn't exist
The query SHOULD! translate the table name so that the eventual SQL query sent to MariaDB is: SELECT * from ViewExpiredAccount however it doesnt do that. Is this a bug in Spring??
did you reset the hibernate naming strategy?
if yes, the following property might help
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl

How to use table functions in queries with Spring Data

When using Spring Data JPA with Hibernate, what are the options available to write queries that join with table functions.
For example, I'd like to generate queries as described below:
CASE 1: SELECT * FROM getfoo(1) AS t1;
CASE 2: SELECT * FROM getfoo(1) x INNER JOIN tbl1 y on x.id = y.id;
Edit
To elaborate more, I'm using Spring Data for all things CRUD (It works great). However, I need to write complicated queries that join tables with "table functions". Table functions(AKA Table-Valued User-Defined Functions) are database functions that return tabled-values which can be used in the JOIN clause in combination with tables. Postgresql and Sql Server support them.
In the Spring Data realm, which includes much more than JPA, what are the options to consider when writing such queries? Whats the best practice from your experience? user2658013 was kind enough to describe one such approach using the entityManager.reateNativeQuery method.
In my mind here are the options:
JPA
Use #NamedStoredProcedureQuery ( >=JPA 2.1)
Use entityManager.createNativeQuery or #NamedNativeQuery
Non-standard
Use Spring Data's #Query to declare finder queries directly on repository methods.
Use SimpleJdbcCall
Any others?
I believe you are asking about Postgres stored functions. Postgres stored functions are analogous to "Stored Procedures". So I think you are asking how would invoke a stored procedure using JPA? Am I close?
The following pseudo code is derived from details published here (see section on Stored Procures):
http://www.oracle.com/technetwork/articles/vasiliev-jpql-087123.html
EntityManager em = emf.createEntityManager();
SOMEVAL_TYPE result = (SOMEVAL_TYPE)em.createNativeQuery("SELECT getfoo(?1) FROM SOMEDB")
.setParameter(1, SOME_PARM)
.getSingleResult();
In general you can use JPQL with JPA instead of SQL.
Note! The above assumes you have already created the stored function in you Postgres database.
Hope that helps :)

Type 4 Driver Issue - Multiple SQLs (Compound SQL)

I have a query with multiple calls in the same line(see code below)
The Statement object is automatically created by JDBCTemplate.
The JDBCTemplate is instantiated as new JDBCTemplate() and the datasource is looked up from the weblogic server pool.
class A implements org.springframework.jdbc.core.StatementCallback {
public Object doInStatement(Statement stmt) throws Exception {
String sql = "select * from a where pk = 'test';select * from b where pk = 'test';select * from c where pk = 'test'";
Statement stmt =
ResultSet rs = stmt.executeQuery(sql);
rs = stmt.getResultSet();
...
rs = stmt.getMoreResults();
...
rs = stmt.getMoreResults();
...
}
Using IBM's Type 2 driver, the above worked perfectly fine. We had to change the driver to Oracle's Type 4 JDBC driver and when we did that, the above broke. It does not work anymore and I get the error below:
[DAO.exec] ERROR :
java.sql.SQLException: [OWLS][DB2 JDBC Driver][DB2]ILLEGAL SYMBOL
select * from a where pk ; VALID SYMBOLS ARE BEGIN-OF-STATEMENT
Does anyone know why a Type 4 driver would not support the above? Is there a different delimeter I need to use in the statement, different way to make it work?
Note: THis code worked without any problems with the IBM type 2 JDBC driver, it failed when we switched to Oracle's Type 4 driver.
We use weblogic as the application server and DB2 database.
You need to execute multiple statements separately not compounded into one string. Most drivers will only allow a single statement to be executed. There are only a few drivers which allow multiple statements to be executed in on statement/execute.
In general you should not depend on this behavior, as it is not explicitly defined in the JDBC spec. If you read between the lines of the JDBC spec, then IMHO executing multiple statements in on statement/execute should not be supported at all, but that is debatable.
Why drivers don't support this: some database systems simply don't support preparing, executing and retrieving results of multiple statements in one statement/execute. So to support it, the driver would actually need to jump through all kinds of hoops to get it to work, even though it is not a requirement of JDBC (or IMHO: not allowed by JDBC).
To substantiate my claim that only one statement should be executed in a single statement/execute:
The object used for executing a static SQL statement (from http://docs.oracle.com/javase/7/docs/api/java/sql/Statement.html )
In some (uncommon) situations, a single SQL statement may return multiple result sets and/or update counts http://docs.oracle.com/javase/7/docs/api/java/sql/Statement.html#execute(java.lang.String)
Similarly, the JDBC spec always talks about 'a query' when talking about statements

How to read changed values with native query during one transaction? (Spring and JPA)

We have container transaction with Spring and JPA (Hibernate). I need to make an update on a table to "flag" some rows via native statements. Then we insert some rows via EntityManager from JPATemplate to this table. After that, we need to calculate changes in the table via native statement (with Oracle's union and minus, complex groups...)
I see that changes from step 1 and 2 are not commited and thats why the statement from 3 fails. I already tried with transaction propagation REQUIRES_NEW, EntityManager.flush... Didn't work.
1) update SOMETABLE acolumn = somevalue (native)
2) persist some values into SOMETABLE (via entity manager)
3) select values from SOMETABLE
Is there a possibility to read the changes from step 1 and 2 in step 3?
I guess you are using the same DataSource in the JpaTransactionManager, JdbcTemplate and JpaTemplate and have enabled #Transactional with this:
<tx:annotation-driven />
Assuming it is not a configuration bug, my best guess is that you're calling on the #Transactional method from a method in the same class?
In that case, you need AspectJ to weave in the transaction logic or refactor the code so the #Transactional method is in another class than the calling method. (The refactor option is the easy and preferred one)
If this doesn't solve your problem, you should add the relevant classes to your question together with relevant log messages.

Resources