I have recently started using Spring boot, and have run into a bit of a problem. before, when i was just using Spring data with hibernate and JPA, I could create a hibernate.cfg.xml file that would give a bunch of configuration that could be passed to a config object and then ultimately create a SessionFactory object that would create a Session object that could be used to pass the query to hibernate:
package util;
import org.hibernate.SessionFactory;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;
public class HibernateUtil {
private static final SessionFactory sessionFactory = buildSessionFactory();
private static SessionFactory buildSessionFactory() {
try {
// Create the SessionFactory from hibernate.cfg.xml
Configuration configuration = new Configuration().configure("hibernate.cfg.xml"); return configuration.buildSessionFactory( new
StandardServiceRegistryBuilder().applySettings( configuration.getProperties() ).build() );
}
catch (Throwable ex) {
// Make sure you log the exception, as it might be swallowed System.err.println("Initial SessionFactory creation failed." + ex); throw new ExceptionInInitializerError(ex);
}
}
public static SessionFactory getSessionFactory() { return sessionFactory; }
}
hibernate.cfg.xml
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- Database connection settings -->
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="connection.url">jdbc:mysql://localhost:3306/hello-world</property>
<property name="connection.username">root</property>
<property name="connection.password">password</property>
<!-- SQL dialect -->
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
<!-- Create/update tables automatically using mapping metadata -->
<property name="hbm2ddl.auto">update</property>
<!-- Use Annotation-based mapping metadata -->
<mapping class="entity.Author"/>
<mapping class="entity.Article"/>
</session-factory>
</hibernate-configuration>
Main.java
public class HelloWorldClient {
public static void main(String[] args) {
Session session = HibernateUtil.getSessionFactory().openSession();
Transaction txn = session.getTransaction();
EntityManagerFactory emf = Persiscance.createEntityManagerFactory("hibernate.cfg.xml");
EntityManager em = emf.createEntityManager();
EntityTransaction txn = em.getTransaction();
try {
txn.begin();
Author author = new Author("name", listOfArticlesWritten);
Article article = new Article("Article Title", author);
session.save(author);
session.save(article);
Query query = session.createQuery("select distinct a.authorName from Article s
where s.author like "Joe%" and title = 'Spring boot');
List<Article> articles = query.list();
txn.commit();
} catch(Exception e) {
if(txn != null) { txn.rollback(); }
e.printStackTrace();
} finally {
if(session != null) { session.close(); } }
}
}
This is where the issue appears. I don't know how to avoid creating a hibernate.cfg.xml file or session factory for custom queries. in the Spring guides page, and some tutorials i have worked through, they take their DAO and extend the CrudRepository interface which gives a bunch of methods already, as well as a way to name the method so that Hibernate can build the sql on its own.
what i am trying to accomplish, at least in this post is to be able to execute the above query in spring boot. I can create a properties file
application.properties
# ===============================
# = DATA SOURCE
# ===============================
# Set here configurations for the database connection
spring.datasource.url = jdbc:mysql://localhost:3306/spring-boot-demo
spring.datasource.username = test
spring.datasource.password = test
# Mysql connector
spring.datasource.driverClassName = com.mysql.jdbc.Driver
# ===============================
# = JPA / HIBERNATE
# ===============================
# Specify the DBMS
spring.jpa.database = MYSQL
# Show or not log for each sql query
spring.jpa.show-sql = true
# Ddl auto must be set to "create" to ensure that Hibernate will run the
# import.sql file at application startup
#create-drop| update | validate | none
spring.jpa.hibernate.ddl-auto = update
# SQL dialect for generating optimized queries
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5Dialect
# ===============================
# = THYMELEAF
# ===============================
spring.thymeleaf.cache = false
#debug=true
I can move all but the mapping to a properties file, but then I am unclear how to write the query because there is no longer a session object.
In spring boot application you no need to create xml configuration, you must congigure java file itself. Check with this example,
If you use Spring Boot + Spring Data JPA, then you configure your datasource (which you now put in hibernate.cfg.xml) into the
application.properties
, by using thespring.datasource.*
properties.This should automatically create an entity manager for you. If you need to use queries, you can use Spring Data JPA's repositories, for example:
Now you can autowire the repository and use the given query, like this:
If you really need custom queries, you can use the Predicate/Criteria API from JPA. Spring offers a wrapped version of these predicates, called Specifications.
To do that, you extend your
ArticleRepository
with another interface calledJpaSpecificationExecutor<Article>
. This adds some extra methods to your repository:This allows you to dynamically create queries, though from your question it doesn't look like you really need it.