Execute query with native query (update query) in Hibernate 5.x - java

I am currently upgrading our application and we are migrating from Hibernate 3.x and Spring/Spring Security 3.x to Hibernate 5.x and Spring/Spring Security 5.x respectively. We had some methods that executed native sql update queries (example 1), but after upgrading to 5.x the methods started throwing TransactionRequiredException: Executing an update/delete query exceptions. Well I tried adding the #Transactional annotation on the methods but it doesn't seem to help. I will share the old method and the upgraded method (example 2).
I don't understand how it is not working on the new version, did Hibernate change the way they treat native sql queries? Thanks for the responses.
Example 1
public void myTestMethod() {
String sql = "Update myTable set State = 1";
Session session = getSessionFactory().openSession();
Query query = session.createSQLQuery(sql);
query.executeUpdate();
session.close();
}
Example 2
public void myTestMethod() {
String sql = "Update myTable set State = 1";
Session session = sessionFactory.openSession();
Query query = session.createNativeQuery(sql);
query.executeUpdate();
session.close();
}
What am I doing wrong here? How can I execute this update without changing much in the methods (we have thousands of methods implemented). The sessionFactory in the example 2 is injected with #Inject annotation.

Try to use #Transactional over your methods and use getCurrentSession() instead of the openSession()
And your code has session.close() statement which doesn't make sense any more, since the connection was already closed and managed by the spring. Try removing the session.close() statement and try again

Related

How to run a native SQL query in Spring without an entity and a JPA Repository?

I am trying to run some native SQL queries in my Spring application. I donĀ“t have an entity or JpaRepository class. I know it's strange, but this is a microservice just to collect two count queries and send it to Kafka.
Well trust me, all I need is these two integers from the queries. I run these code and always returns 0. I can see in the logs that Hikari is connecting to the database, so I don't know what to do. Searched a lot, but all answers involved the #Query solution, which does not work for me.
#Repository
#AllArgsConstructor
public class ReportRepository {
private final EntityManager em;
public int numberOfAccounts() {
String sql = "SELECT count(*) FROM account";
Query query = em.createNativeQuery(sql);
System.out.println(query.getFirstResult());
return query.getFirstResult();
}
public int numberOfSubscriptions() {
String sql = "SELECT count(*) FROM subscriptions";
Query query = em.createNativeQuery(sql);
System.out.println(query.getFirstResult());
return query.getFirstResult();
}
}
If you have EntityManager, and from what you are saying it can connect to DB, try this way:
public int numberOfSubscriptions() {
// >> "subscriptions" has to be the exact name of your table
// if does not work, consider trying SUBSCRIPTIONS or Subscriptions
String sql = "SELECT count(*) FROM subscriptions";
Query query = em.createNativeQuery(sql);
// getSingleResult() instead :)
return ((Number) query.getSingleResult()).intValue();
}
There is this (a bit old) JavaDoc for Query.getFirstResult() :
The position of the first result the query object was set to retrieve. Returns 0 if setFirstResult was not applied to the query object
So, I'd say that is not the right method for your case.
Happy Hacking :)
You should be using JDBC instead of an Entity Manager. Under the JPA uses JDBC but it requires defined entites to work. JDBC allows you to manage the connection and run the raw SQL queries.
Here's a link for how to do it in Spring:
https://spring.io/guides/gs/relational-data-access/#_store_and_retrieve_data

Basic CRUD operations with entitymanager

I made a REST service project where i was performing CRUD operations via DriverManager.getConnection(url,user,pass).
Now my asignment changed to defining the connection in Jboss 7.1.1 and that is working (Testing the datasource in the Jboss admin console returns positive and the sqljdbc driver also appears active in the Activity Monitor of MS SQL Server Management Studio).
I am suposed to use the EntityManager to run the native querys i used with the old project without generating entities or writing queries using entities(Thats for the next asignment).
I wrote a small test code from what i found in my research, the following:
public class Test {
#PersistenceContext(unitName="InternshipIS") protected EntityManager entityManager;
public void getQuerys(){
String sqlQuery = "SELECT * from InternshipIS.dbo.Employee";
Query q = entityManager.createNativeQuery(sqlQuery);
System.out.println(q.getResultList().get(2));
}
When it reaches the following line, it throws a NullPointerException.
Query q = entityManager.createNativeQuery(sqlQuery);
Please let me know where i'm screwing up and if the full stacktrace / persistence.xml / standalone.xml or anything else is needed in order to add them to my post.
PS: This is not a maven project. It was a Dynamic Web Project that i converted to JPA when this asignment started.
I fixed the problem by making the following adjustments:
public class Test {
public void getQuerys(){
EntityManagerFactory emFactory = Persistence.createEntityManagerFactory("InternshipIS");
EntityManager em = emFactory.createEntityManager();
String sqlQuery = "SELECT * FROM Employee";
Query q = em.createNativeQuery(sqlQuery);
}
}
String sqlQuery = "SELECT * from InternshipIS.dbo.Employee";
In this query, Select * from InternshipIS is understandable for sql.
But I think you are concatenating database name with table in query. Which is not working and query returning null value.

How to create native queries in Spring?

I have a spring application that should connect to an existing database and just query an entity for existence based on some attributes.
I don't want to create a #Entity class for this. But I still want to use the spring managed EntityManager etc.
When using Spring, what is the best approach to just query a select for that entity? Using em.createNamedQuery(QUERY); with String QUERY = "SELECT count(*) from my_table where username =: username AND email := email)";?
Answers from #predrag-maric and #pL4Gu33 are both correct but if you use JPA in your project (for example, Hibernate) you might consider using #NamedNativeQuery annotation as well.
More about named native queries.
simple example of native query
#PersistenceContext
EntityManager em;
public String test(Integer id)
{
Query query = em.createNativeQuery("SELECT name FROM Accounts where id=?");
query.setParameter(1,id);
return query.getSingleResult();
}
You can use this method from entitymanager. http://docs.oracle.com/javaee/6/api/javax/persistence/EntityManager.html#createNativeQuery%28java.lang.String%29
Use em.createNativeQuery(QUERY). Also, you'll have to use positional parameters (?1) instead of named parameters (:email), because only positional parameters are supported by JPA in native queries.

How to combine JDBC statement with EntityManager?

I created the entity classes of my database with NetBeans. I believe I know how to use EntityManager
(Class) db.createNamedQuery(String name);
but I don't know where to put the statement (database link, login, password) so I learned how to query with
(JDBC4ResultSet) statement.executeQuery(String query);
but it returns the set which I don't know how to transform into Entity class... something like
(Class) statement.execureQuery(String query).toEntity(Class);
would be nice. ;-)
Ok, First you need to get an EntityManager from entity manager factory with your persistance unit name (which will be configured in persistance.xml). And then you create an EntityManager.
EntityManagerFactory emf=Persistence.createEntityManagerFactory("persistance_unit_name");
EntityManager em=emf.createEntityManager();
Query query = em.createNamedQuery("namedQueryName"); //this returns a query
List<ENTITIY> result = query.getResultList();
This is just an heads up, You can google 'jpa example' to find out more working examples.

How update the database using a web service and EclipseLink as JPA provider?

I have done a simple web service using EclipseLink as JPA provider. I am a beginner when coming to JPA, so I am wondering if this is the common way and most pure and secure way to make updates to the database:
EntityManager em = emf.createEntityManager();
if(!em.getTransaction().isActive()){
em.getTransaction().begin();
}
Query query = (Query)em.createNamedQuery("Person.updatePerson");
query.setParameter("personId", person.getPersonPK().getPersonId())
.setParameter("personName", name);
return query.executeUpdate();
Why don't I need to use em.getTransaction().commit(); after I have called em.getTransaction().begin()? query.executeUpdate() seems to update the database, not the commit call. Why is that so? What is recommended?
You need to call commit() to commit the transaction. Executing a query will not commit.
What type of transactions are you using? JTA or RESOURCE_LOCAL? If you are using JTA, then you must use JTA to begin a commit transactions.
Enable logging to get more details.
In general in JPA updates are normally done by reading the object and using its set methods, not executing raw queries.
Interesting question, I did some investigation with a non-jta-datasource:
EntityManagerFactory emf = Persistence.createEntityManagerFactory("unit1");
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
// database: t.name='OLD'
Query query = em.createQuery("UPDATE Test t set t.name = 'NEW'");
query.executeUpdate();
// database: t.name='OLD'
TypedQuery<String> tq
= em.createQuery("SELECT t.name from Test t", String.class);
System.out.println(tq.getSingleResult());
// output: 'NEW'
// database: t.name='OLD'
em.getTransaction().commit();
// database: t.name='NEW'
My explanation approach (please correct me, if I am wrong):
The database holds 'OLD' value until em.getTransaction().commit().
The SELECT query returns 'NEW' from persistence context

Categories