Spring Data JPA @NamedQuery注释示例
在Spring Data JPA Example中,我们已经看到了Spring MVC + JPA(Hibernate)+ MySQL的集成示例。在该示例中,用户定义查询的查询查找策略是自动的,其中Spring框架通过解析方法名称来完成派生查询的工作。尽管从方法名称派生查询非常方便,但是我们可能会遇到这样的情况,即方法名称解析器不支持我们使用的关键字,否则方法名称将变得不必要的丑陋。在这种情况下,我们可以使用带有@NamedQuery注释的JPA命名查询,或者使用@Query注释查询方法。在本文中,我们将看到带有@NamedQuery注释的Spring数据JPA示例。
对于使用查询注释的Spring Data JPA示例,请查看此post @ Spring Data JPA @Query注释示例
具有命名查询的Spring Data JPA
我们将使用Spring Web MVC创建一个Rest Web服务,使用的JPA实现是Hibernate,DB是MySQL。
示例显示了<named-query />元素(在XML配置的情况下)和@NamedQuery注释的用法。这些配置元素的查询必须使用JPA查询语言进行定义。如果要在本机SQL中定义查询,则也可以使用<named-native-query />或者@NamedNativeQuery。但是本机SQL的缺点是我们失去了数据库平台的独立性。
Maven依赖
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.theitroad</groupId>
<artifactId>SpringJPAProject</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<name>SpringJPA</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring.version>5.1.8.RELEASE</spring.version>
<spring.data>2.1.10.RELEASE</spring.data>
<hibernate.jpa>5.4.3.Final</hibernate.jpa>
<mysql.version>8.0.17</mysql.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- Spring data JPA -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>${spring.data}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.Hymanson.core</groupId>
<artifactId>Hymanson-databind</artifactId>
<version>2.9.6</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.0</version>
<scope>provided</scope>
</dependency>
<!-- Hibernate -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>${hibernate.jpa}</version>
</dependency>
<!-- MySQL Driver -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.25</version>
</dependency>
</dependencies>
<build>
<sourceDirectory>src</sourceDirectory>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<release>11</release>
</configuration>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>3.2.1</version>
<configuration>
<warSourceDirectory>WebContent</warSourceDirectory>
</configuration>
</plugin>
</plugins>
</build>
</project>
为Spring核心,Spring上下文以及Spring Web和Spring数据JPA添加了依赖项。
当使用Hibernate JPA实现时,添加了Hibernate的依赖关系。
MySQL连接器用于从Java应用程序连接到MySQL DB。
对于以JSON发送的Web服务响应,需要Hymanson数据绑定。
数据库表查询
可以使用以下查询创建用于此Spring数据JPA的MySQL DB表。
CREATE TABLE `emp` ( `id` int(11) NOT NULL AUTO_INCREMENT, `first_name` varchar(45) DEFAULT NULL, `last_name` varchar(45) DEFAULT NULL, `department` varchar(45) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
JPA实体– Spring数据JPA
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.NamedQuery;
import javax.persistence.Table;
@Entity
@Table(name="emp")
@NamedQuery(name = "Employee.findByDepartment", query = "select e from Employee e where e.dept = ?1")
public class Employee {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@Column(name="first_name")
private String firstName;
@Column(name="last_name")
private String lastName;
@Column(name="department")
private String dept;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getDept() {
return dept;
}
public void setDept(String dept) {
this.dept = dept;
}
@Override
public String toString() {
return "Id= " + getId() + " First Name= " +
getFirstName() + " Last Name= " + getLastName() +
" Dept= "+ getDept();
}
}
这是对应于DB中emp表的实体类。
@Entity注释指定此模型类为实体。
@Table注释指定实体的主表。
@NamedQuery注释指定命名查询。如果我们有多个查询,则可以使用@NamedQueries注释。例如
@NamedQueries({
@NamedQuery(name = "Employee.findByDepartment",
query = "Select e from emp e where e.department = ?1"),
@NamedQuery(name="Employee.findByLastName",
query = "Select e from emp e where e.lastName = ?1""),
})
@Id注释指定实体的主键。
@GeneratedValue指定主键生成策略,在这种情况下,该策略是自动递增的。
@Column注释指定该字段的映射表列名称。
在XML配置的情况下,<named-query />元素用于定义命名查询。
<named-query name="Employee.findByDepartment"> <query>Select e from emp e where e.department = ?1</query> </named-query>
Spring Data JPA存储库
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import com.theitroad.springproject.model.Employee;
public interface EmployeeRepository extends JpaRepository<Employee, Integer> {
List<Employee> findByLastName(String lastName);
List<Employee> findByDepartment(String department);
}
EmployeeRepository接口扩展了JpaRepository,它使用域类来管理(在这种情况下为Employee),并且将域类的id类型作为类型参数。
除了从JPARepository继承的方法外,EmployeeRepository接口还定义了两种方法。
Spring Data尝试将对这些方法的调用解析为对命名查询的调用,从已配置域类的简单名称开始,然后是由句点分隔的方法名称。因此,对于方法findByDepartment,使用名为query(Employee.findByDepartment)的方法,而对于findByLastName,Spring数据根据方法名称创建查询。
Spring Data JPA示例–服务类
在服务层,我们将调用存储库方法。请注意,必须将存储库实例注入服务类中。
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.theitroad.springproject.dao.EmployeeRepository;
import com.theitroad.springproject.model.Employee;
@Service
public class EmployeeService {
@Autowired
private EmployeeRepository repository;
public Employee getEmployeeById(int id) {
return repository.findById(id).get();
}
public List<Employee> getAllEmployees(){
return (List<Employee>) repository.findAll();
}
public void deleteEmployeeById(int id){
repository.deleteById(id);
}
public Employee addEmployee(Employee emp) {
return repository.save(emp);
}
public List<Employee> getEmployeeByLastName(String lastName) {
return repository.findByLastName(lastName);
}
public List<Employee> getEmployeeByDepartment(String department) {
return repository.findByDepartment(department);
}
}
休息控制器
使用Rest控制器类,我们会将路径映射到要为请求调用的方法。
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import com.theitroad.springproject.model.Employee;
import com.theitroad.springproject.service.EmployeeService;
@RestController
@RequestMapping("/employee")
public class EmployeeController {
@Autowired
EmployeeService empService;
@GetMapping("/{id}")
public Employee getEmployeeById(@PathVariable int id) {
return empService.getEmployeeById(id);
}
@GetMapping
public List<Employee> getAllEmployees(){
return empService.getAllEmployees();
}
@DeleteMapping("/{id}")
@ResponseStatus(HttpStatus.OK)
public void deleteEmployeeById(@PathVariable int id){
empService.deleteEmployeeById(id);
}
@PostMapping
@ResponseStatus(HttpStatus.CREATED)
public Employee addEmployee(@RequestBody Employee emp) {
return empService.addEmployee(emp);
}
@GetMapping("/lastname/{lastName}")
public List<Employee> getEmployeeByLastName(@PathVariable String lastName) {
return empService.getEmployeeByLastName(lastName);
}
@GetMapping("/dept/{department}")
public List<Employee> getEmployeeByDepartment(@PathVariable String department) {
return empService.getEmployeeByDepartment(department);
}
}
Spring Data JPA –配置类
在此Spring数据JPA示例中,使用Java配置,因此使用@Configuration注释对类进行注释。
要设置DataSource DB属性是从属性文件中读取的,请使用@PropertySource注释配置属性文件的路径。
@EnableJpaRepositories注释启用JPA存储库。带有注释的值提供了用于扫描存储库的软件包。
@EnableTransactionManagement注释启用Spring的注释驱动的事务管理功能。
在此Java配置类中,我们设置了EntityManagerFactory并将Hibernate用作持久性提供程序。
import java.util.Properties;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@Configuration
@EnableJpaRepositories("com.theitroad.springproject.dao")
@EnableTransactionManagement
@PropertySource("classpath:config/db.properties")
public class JPAConfig {
@Autowired
private Environment env;
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setJpaVendorAdapter(vendorAdapter);
factory.setPackagesToScan("com.theitroad.springproject.model");
factory.setDataSource(dataSource());
factory.setJpaProperties(hibernateProperties());
return factory;
}
@Bean
public DataSource dataSource() {
DriverManagerDataSource ds = new DriverManagerDataSource();
ds.setDriverClassName(env.getProperty("db.driverClassName"));
ds.setUrl(env.getProperty("db.url"));
ds.setUsername(env.getProperty("db.username"));
ds.setPassword(env.getProperty("db.password"));
return ds;
}
Properties hibernateProperties() {
Properties properties = new Properties();
properties.setProperty("hibernate.dialect", env.getProperty("hibernate.sqldialect"));
properties.setProperty("hibernate.show_sql", env.getProperty("hibernate.showsql"));
return properties;
}
@Bean
public PlatformTransactionManager transactionManager() {
JpaTransactionManager txManager = new JpaTransactionManager();
txManager.setEntityManagerFactory(entityManagerFactory().getObject());
return txManager;
}
}
如果我们使用的是XML配置,则用于启用JPA存储库的配置为
<jpa:repositories base-package="com.theitroad.springproject.dao"/>
db.properties文件
db.driverClassName=com.mysql.cj.jdbc.Driver db.url=jdbc:mysql://localhost:3306/theitroad db.username= db.password= hibernate.sqldialect=org.hibernate.dialect.MySQLDialect hibernate.showsql=true
要使用Java config而不是web.xml设置网络应用程序,我们需要以下类。
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
public class WebConfigInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
// TODO Auto-generated method stub
return null;
}
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[] {WebConfig.class};
}
@Override
protected String[] getServletMappings() {
return new String[] {"/"};
}
}
@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "com.theitroad.springproject")
public class WebConfig implements WebMvcConfigurer{
}
部署Spring Data JPA应用程序
右键单击项目,然后选择"运行方式– Maven构建",提供目标为全新安装。如果构建成功,则将应用程序打包为战争,可以将其部署在像Tomcat这样的Web容器上,然后测试该应用程序。
为了测试RESTful Web服务,使用了Postman rest客户端。
新增员工
请注意,所选的请求是POST,URL是http:// localhost:8080 / SpringJPAProject / employee
数据以JSON格式作为请求正文发送。在响应中添加了员工数据回发。
按部门查找(命名查询)
我们也可以直接从浏览器发送请求,就像完成此请求一样。
按姓获取员工

