Set up dependency
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
Configuring JPA and Hibernate
in application.properties file
spring.datasource.url=jdbc:mysql://localhost:3306/dbname
spring.datasource.username=root
spring.datasource.password=password
spring.jpa.hibernate.ddl-auto=update
or application.yml
spring:
application:
name: demoapp
datasource:
url: jdbc:mysql://localhost:3306/dbname
username: root
password: password
driver-class-name: com.mysql.cj.jdbc.Driver
jpa:
hibernate:
ddl-auto: update
show-sql: true
open-in-view: false
More config (optional)
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.hibernate5.LocalSessionFactoryBean;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.sql.DataSource;
import java.util.Properties;
@Configuration
@EnableJpaRepositories(basePackages = "com.jamiewang.demo.dao", entityManagerFactoryRef = "primaryEntityManager", transactionManagerRef = "primaryTransactionManager")
@EnableTransactionManagement
public class HibernateConfig {
private final Logger log = LoggerFactory.getLogger(getClass());
private LocalContainerEntityManagerFactoryBean entityManager;
@Value("${spring.datasource.url}")
private String jdbcUrl;
@Value("${spring.datasource.username}")
private String username;
@Value("${spring.datasource.password}")
private String password;
@Value("${spring.datasource.driver-class-name}")
private String driverClassName;
private DataSource dataSource;
@Bean
public DataSource dataSource(){
this.dataSource = DataSourceBuilder.create()
.url(jdbcUrl)
.username(username)
.password(password)
.driverClassName(driverClassName)
.build();
return this.dataSource;
}
@Bean
public LocalSessionFactoryBean localSessionFactoryBean(){
Properties properties=new Properties();
properties.setProperty("hibernate.show_sql", "true");
properties.setProperty("hibernate.format_sql", "true");
properties.setProperty("hibernate.hbm2ddl.auto", "update");
properties.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQLDialect");
LocalSessionFactoryBean lsb=new LocalSessionFactoryBean();
lsb.setDataSource(dataSource());
/**
* set entity location
*/
lsb.setPackagesToScan("com.jamiewang.demo.entity");
lsb.setHibernateProperties(properties);
return lsb;
}
@Bean
@Primary
LocalContainerEntityManagerFactoryBean primaryEntityManager(EntityManagerFactoryBuilder builder) {
log.info("Scanning entity...");
entityManager = builder.dataSource(this.dataSource).packages("com.jamiewang.usercenter.entity")
.persistenceUnit("primaryPersistenceUnit").build();
return entityManager;
}
@Bean
@Primary
PlatformTransactionManager primaryTransactionManager(EntityManagerFactoryBuilder builder) {
log.info("Configuration database transaction manager...");
return new JpaTransactionManager(entityManager.getObject());
}
}
Creating Entities
@Entity
public class Book {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String title;
private String author;
private String ISBN;
// Getters and setters
}
Creating Repositories
In Spring Data JPA, we can create a repository by creating an interface that extends the JpaRepository interface.
This interface will provide basic CRUD functionality for our Book entity and can be easily injected into our service layer.
public interface BookRepository extends JpaRepository<Book, Long> {
}
Custom Queries
JPA provides a simple and convenient way to create custom queries using the @Query
annotation. This annotation allows you to define a query directly in the repository interface, rather than in a separate class or XML file. The @Query
annotation takes a single parameter, the query string. The query string can be written in either JPQL (Java Persistence Query Language) or SQL.
The following example shows how to use the @Query
annotation to create a custom query that retrieves all users with a specific role:
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
@Query("SELECT u FROM User u WHERE u.role = ?1")
List<User> findByRole(String role);
}
In this example, the findByRole
method is annotated with the @Query
annotation and the query string is written in JPQL. The ?1
parameter is a positional parameter that is replaced with the value of the role
argument when the query is executed.
It’s also possible to use named parameters instead of positional parameters. Named parameters are prefixed with a :
and can be used in the query string by referencing them by name. The following example shows how to use named parameters:
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
@Query("SELECT u FROM User u WHERE u.role = :role")
List<User> findByRole(@Param("role") String role);
}
Hibernate Query Language (HQL)
HQL is an object-oriented query language that is similar to SQL, but it operates on the objects of the persistent classes rather than on the database tables. HQL is used to create queries that are executed by the Hibernate framework.
The following example shows how to use HQL to create a query that retrieves all users with a specific role:
Session session = sessionFactory.openSession();
Query query = session.createQuery("FROM User WHERE role = :role");
query.setParameter("role", "admin");
List<User> users = query.list();
In this example, the createQuery
method is used to create a new query. The query string is written in HQL and the :role
parameter is a named parameter that is replaced with the value of the role
variable when the query is executed.
Using HQL can be more powerful than using JPA’s @Query
annotation, as it allows you to execute more complex queries and to use advanced features of the Hibernate framework. However, it can also result in more complex codebase and harder to maintain, that’s why it’s important to use it judiciously and with caution.
Best Practices
When using custom queries and HQL in your SpringBoot application, there are a few best practices to keep in mind:
Use parameter binding: Instead of concatenating variables into the query string, use parameter binding to prevent SQL injection attacks.
Keep queries simple: Complex queries can be difficult to maintain and may result in poor performance. Try to keep queries as simple as possible.
Use pagination: When retrieving large amounts of data, use pagination to limit the number of results returned and to improve performance.
Test your queries: Always test your queries to ensure that they are returning the expected results and to check for any performance issues.
Logging: Enable the logging of SQL statements to monitor the performance and identify any issues
Encapsulate your own common repository layer method
If you followed the optional config. You can also encapsulate a more powerful one like this:
import java.io.Serializable;
import java.util.List;
import java.util.Map;
public interface PrimaryDaoService {
public <T> void save(T o);
public <T> void delete(T o);
public <T> void update(T o);
public <T> T get(Class<T> c, Serializable id);
public List<Map<String, Object>> getListBySql(String sql);
}
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import jakarta.persistence.Query;
import org.example.entity.User;
import org.hibernate.query.sql.internal.NativeQueryImpl;
import org.hibernate.transform.Transformers;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
import java.util.Map;
@Repository
public class PrimaryDaoServiceImpl implements PrimaryDaoService {
@PersistenceContext(unitName = "primaryEntityManager")
private EntityManager entityManager;
@Override
public <T> void save(T o) {
if (null != o) {
if (o instanceof User) {
User data = (User) o;
data.setCreateTime(new Date());
data.setModificationTime(new Date());
data.setCreaterId(-1l);
data.setModifierId(-1l);
}
entityManager.persist(o);
}
}
@Override
public <T> void delete(T o) {
if (null != o) {
entityManager.remove(o);
}
}
@Override
public <T> void update(T o) {
if (null != o) {
entityManager.merge(o);
}
}
@Override
public <T> T get(Class<T> c, Serializable id) {
if (null != id) {
return (T) entityManager.find(c, id);
}
return null;
}
@Transactional(readOnly = true)
@Override
public List<Map<String, Object>> getListBySql(String sql) {
Query q = entityManager.createNativeQuery(sql);
q.unwrap(NativeQueryImpl.class).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
return q.getResultList();
}
}
0 Comments