jpa是定义了ORM框架的一套api,比较有名的实现有hibernate、openjpa等,国内用的最多的还是hibernate,并且,spring boot的spring-boot-starter-data-jpa
中也依赖了hibernate的包。本篇博客用几个简单的例子来演示一下在spring中如何使用jpa和hibernate来简化数据库操作。
加入starter依赖和jdbc驱动
spring boot提供了专门的起步依赖,需要加入到pom.xml中。同时,也加入mysql connector的定义
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
配置数据源
在application.properties文件中加入mysql的连接信息
spring.datasource.url=jdbc:mysql://localhost/test
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
定义实体类、创建数据表
hibernate作为ORM框架,我们需要先来定义一个java类
import javax.persistence.*;
@Entity(name = "student")
public class StudentEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int studentId;
@Column
private String studentName;
public int getStudentId() {
return studentId;
}
public void setStudentId(int studentId) {
this.studentId = studentId;
}
public String getStudentName() {
return studentName;
}
public void setStudentName(String studentName) {
this.studentName = studentName;
}
}
然后,创建一个与之对应的数据表
Create Table: CREATE TABLE `student` (
`student_id` int(11) NOT NULL AUTO_INCREMENT,
`student_name` varchar(50) DEFAULT NULL,
PRIMARY KEY (`student_id`)
) ENGINE=InnoDB AUTO_INCREMENT=15 DEFAULT CHARSET=utf8
插入几条数据
insert into student(student_name) values ('stu_a'),('stu_b'),('stu_c'),('stu_d'),('stu_e'),('stu_f'),('stu_g');
insert into student(student_name) values ('stu_h'),('stu_i'),('stu_j'),('stu_k'),('stu_l'),('stu_m'),('stu_n');
创建repository
public interface StudentRepository extends JpaRepository<StudentEntity,Integer>{
}
创建了一个接口,实现了JpaRepository
,除此之外什么都没做,但它已经具备了很多处理数据的能力
使用repository读取数据库信息
首先,将StudentRepository对象注入进来
@Autowired
StudentRepository studentRepository;
读取列表
return studentRepository.findAll();
排序
Sort sort = new Sort(Sort.Direction.DESC,"studentId");
return studentRepository.findAll(sort);
注意,创建Sort对象的第二个参数,是java对象的属性,而不是mysql数据表的列名
分页(+排序)
Sort sort = new Sort(Sort.Direction.ASC, "studentId");
Pageable pageable = PageRequest.of(pageNumber -1, 5, sort);
return studentRepository.findAll(pageable).getContent();
如果只分页不排序的话,去掉PageRequest.of()
方法的第三个sort参数即可。
添加自定义的方法来查询
如果JpaRepository
接口中定义的方法不能满足你的要求,还可以自定义一些方法,hibernate会根据方法名自动生成sql语句,例如,添加一个findByXXX方法
public interface StudentRepository extends JpaRepository<StudentEntity,Integer>{
public StudentEntity findByStudentName(String studentName);
}
这个方法名是有讲究的,findByXXX中的XXX要和java对象中的属性保持一致
关于更多自动创建查询写法,可以参考
添加自定义查询语句
尽管findByXXX还可以写成findXXXAndOOO的形式,但生成更个性化的查询会显得很费劲,即便能实现,方法名的可读性也会很差,这种情况下比较适合使用自定义查询语句的方式来处理。
public interface StudentRepository extends JpaRepository<StudentEntity,Integer>{
@Query("select s from student s where student_name like %?1%")
public List<StudentEntity> searchStudent(String keywords);
}
使用@Query
注解,加上自定义的查询语句。这个查询语句不是标准的sql语句。?1
的意思是第一个参数。select s
而不是select s.*
或者select s.xxx
更复杂的自定义查询
在项目中我们还会用到更复杂的自定义查询,下面来看一个动态参数+排序+分页的例子。
@Query(value = "select * from xxx where (?1 is null or ?1 = '' or param1 = ?1) and (?2 is null or param2 = ?2) " ,
countQuery = "select COUNT(*) from xxx where (?1 is null or ?1 = '' or param1 = ?1) and (?2 is null or param2 = ?2) " ,
nativeQuery = true
)
Page<AlertHistory> search(String param1, Integer param2, Pageable pageable);
需要注意的是,sql中不需要写order by和limit,在最后加上一个Pageable
对象就可以了。
显示自动生成的sql,并写入日志中
不管是不是native query,jpa或多或少都可能会为我们生成一些sql,打印出具体的sql语句对于调试是非常有效的,只需要加上以下两个配置项,就可以打印出具体的sql。
spring.jpa.show-sql=true
spring.properties.hibernate.format_sql=true
上面的配置会将jpa生成的sql语句格式化并输出到stdout中,但并不会输出到其它的日志appender中,例如日志文件。加入下面的配置,可以将生成的sql输出到日志文件中
logging.level.org.hibernate.SQL=DEBUG
如果希望显示执行sql查询时的具体参数,可以使用下面的配置
logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE
关于spring data jpa的更多用法,可以查看官方文档
https://docs.spring.io/spring-data/jpa/docs/2.1.0.M2/reference/html/