SpringBoot整合Spring Data JPA
程序员文章站
2022-04-23 16:02:19
...
SpringBoot整合Spring Data JPA
整合步骤
1、添加依赖
<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>
2、添加配置设置
spring:
datasource:
url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: root
jpa:
show-sql: true
hibernate:
ddl-auto: update
show-sql 是否在日志中打印出自动生成的 SQL,方便调试的时候查看
ddl.auto 参数的作用主要用于:自动创建、更新、验证数据库表结构,有四个值。
- create:每次加载 Hibernate 时都会删除上一次生成的表,然后根据 model 类再重新来生成新表,哪怕两次没有任何改变也要这样执行,这就是导致数据库表数据丢失的一个重要原因。
- create-drop:每次加载 Hibernate 时根据 model 类生成表,但是 sessionFactory 一关闭,表就自动删除。
- update:最常用的属性,第一次加载 Hibernate 时根据 model 类会自动建立起表的结构(前提是先建立好数据库),以后加载 Hibernate 时根据 model 类自动更新表结构,即使表结构改变了,但表中的行仍然存在,不会删除以前的行。要注意的是当部署到服务器后,表结构是不会被马上建立起来的,是要等应用第一次运行起来后才会。
- validate :每次加载 Hibernate 时,验证创建数据库表结构,只会和数据库中的表进行比较,不会创建新表,但是会插入新值。
3、创建数据库
CREATE TABLE `cst_customer` (
`cust_id` bigint(32) NOT NULL AUTO_INCREMENT COMMENT '客户编号(主键)',
`cust_name` varchar(32) NOT NULL COMMENT '客户名称(公司名称)',
`cust_source` varchar(32) DEFAULT NULL COMMENT '客户信息来源',
`cust_industry` varchar(32) DEFAULT NULL COMMENT '客户所属行业',
`cust_level` varchar(32) DEFAULT NULL COMMENT '客户级别',
`cust_address` varchar(128) DEFAULT NULL COMMENT '客户联系地址',
`cust_phone` varchar(64) DEFAULT NULL COMMENT '客户联系电话',
PRIMARY KEY (`cust_id`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8;
4、创建实体对象
/**
* 客户实体类
* 配置映射关系
* 1、实体类与表的映射关系
* 2、实体类中属性与表中字段的映射关系
*/
@Entity //声明实体类
@Table(name = "cst_customer") //配置数据库表的名称
public class Customer {
/**
* @Id:声明主键的配置
* @GeneratedValue:配置主键的生成策略
* GenerationType.IDENTITY:自增
*/
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "cust_id")
private Long custId; //客户主键
@Column(name = "cust_name")
private String custName; //客户名称
@Column(name = "cust_source")
private String custSource; //客户来源
@Column(name = "cust_industry")
private String custIndustry; //客户所属行业
@Column(name = "cust_level")
private String custLevel; //客户级别
@Column(name = "cust_address")
private String custAddress; //客户地址
@Column(name = "cust_phone")
private String custPhone; //客户联系方式
...
//getter/setter
5、创建一个接口继承JpaRepository
接口就可以使用JPA提供的一系列方法。
/**
* 参数一 T :当前需要映射的实体
* 参数二 ID :当前映射的实体中的OID的类型
*/
public interface CustomerRepository extends JpaRepository<Customer, Long> {
}
使用JPA提供的方法
经过上面的整合后,就可以使用
CustomerRepository
接口来使用JPA提供的方法。我是在单元测试中进行测试。
1、自动注入CustomerRepository
@Autowired
CustomerRepository customerRepository;
2、使用JPA提供的方法。
@Test
public void testJpa(){
Customer customer = new Customer();
customerRepository.findAll();
customerRepository.findById(1l);
customerRepository.save(customer);
customerRepository.delete(customer);
customerRepository.count();
customerRepository.existsById(1l);
}
//基本上看方法名就知道是什么意思
2、自定义简单查询
Spring Data JPA 可以根据接口方法名来实现数据库操作,主要的语法是 findXXBy、readAXXBy、queryXXBy、countXXBy、getXXBy 后面跟属性名称,利用这个功能仅需要在定义的 Repository 中添加对应的方法名即可,使用时 Spring Boot 会自动帮我们实现.
2.1、在CustomerRepository
接口中编写方法
//select * from cst_customer where cust_name = ?
List<Customer> findByCustName(String custName);
//限制查询,排序后查找前5条数据
List<Customer> findFirst5ByCustAddressIsNotNull(Sort sort);
//Where cust_name =like ?% and id < ?
List<Customer> getByCustNameContainsAndCustIdLessThanEqual(String name, Long id);
2.2、测试
@Test
public void testFindByName(){
List<Customer> list= customerRepository.findByCustName("zhangsan");
list.forEach(System.out::println);
}
@Test
public void findByAddressIsNotNull(){
Sort sort = Sort.by(Sort.Direction.DESC, "custId");
List<Customer> list = customerRepository.findFirst5ByCustAddressIsNotNull(sort);
list.forEach(System.out::println);
}
@Test
public void testGetByCustNameContainsAndCustIdLessThanEqual(){
List<Customer> list = customerRepository.getByCustNameContainsAndCustIdLessThanEqual("zhang", 5L);
list.forEach(System.out::println);
}
3、Spring Data中的具体关键字,以及自动生成的SQL示例
Keyword | Sample | JPQL snippet |
---|---|---|
And | findByLastnameAndFirstname | … where x.lastname = ?1 and x.firstname = ?2 |
Or | findByLastnameOrFirstname | … where x.lastname = ?1 or x.firstname = ?2 |
Is,Equals | findByFirstnameIs,findByFirstnameEquals | … where x.firstname = ?1 |
Between | findByStartDateBetween | … where x.startDate between ?1 and ?2 |
LessThan | findByAgeLessThan | … where x.age < ?1 |
LessThanEqual | findByAgeLessThanEqual | … where x.age ⇐ ?1 |
GreaterThan | findByAgeGreaterThan | … where x.age > ?1 |
GreaterThanEqual | findByAgeGreaterThanEqual | … where x.age >= ?1 |
After | findByStartDateAfter | … where x.startDate > ?1 |
Before | findByStartDateBefore | … where x.startDate < ?1 |
IsNull | findByAgeIsNull | … where x.age is null |
IsNotNull,NotNull | findByAge(Is)NotNull | … where x.age not null |
Like | findByFirstnameLike | … where x.firstname like ?1 |
NotLike | findByFirstnameNotLike | … where x.firstname not like ?1 |
StartingWith | findByFirstnameStartingWith | … where x.firstname like ?1 (parameter bound with appended %) |
EndingWith | findByFirstnameEndingWith | … where x.firstname like ?1 (parameter bound with prepended %) |
Containing | findByFirstnameContaining | … where x.firstname like ?1 (parameter bound wrapped in %) |
OrderBy | findByAgeOrderByLastnameDesc | … where x.age = ?1 order by x.lastname desc |
Not | findByLastnameNot | … where x.lastname <> ?1 |
In | findByAgeIn(Collection ages) | … where x.age in ?1 |
NotIn | findByAgeNotIn(Collection age) | … where x.age not in ?1 |
TRUE | findByActiveTrue() | … where x.active = true |
FALSE | findByActiveFalse() | … where x.active = false |
IgnoreCase | findByFirstnameIgnoreCase | … where UPPER(x.firstame) = UPPER(?1) |
4、利用@Query
注解来自定义SQL语句
在使用
@Query
注解自定义SQL语句时,要在后面加上nativeQuery = true
,否则会产生报错。操作和删除操作时要加上@Transactional
注解。
/**
* 自定义SQL语句
* 在 SQL 的查询方法上面使用@Query注解,
* 如涉及到删除和修改在需要加上@Modifying.
* 也可以根据需要添加 @Transactional对事物的支持,查询超时的设置等。
* 默认情况下。SpringData 的每个方法上都有事务,但都是一个只读事务,不能完成修改操作。
*/
//查询id 的值最大的那个 customer
@Query(value = "select * from cst_customer c where c.cust_id = (select max(c2.cust_id) from cst_customer c2 )",nativeQuery = true)
Customer getMaxCustId();
/*
使用占位符来传递参数
*/
@Transactional
@Modifying
@Query(value = "update cst_customer c set c.cust_name = ?1 where c.cust_id = ?2", nativeQuery = true)
int modifyCustNameByCustId(String name, Long id);
/*
命名参数绑定的方式
*/
@Query(value = "select * from cst_customer where cust_name = :name and cust_address = :addr", nativeQuery = true)
List<Customer> findCust(@Param("name") String name, @Param("addr") String addr);
/*
模糊查询1:使用like的时候,在传递参数时要自己加上 "%", 如 %zhang%
*/
@Query(value = "select * from cst_customer where cust_name like ?1 or cust_address like ?2", nativeQuery = true)
List<Customer> findCustLike(String name, String add);
/*
模糊查询2:使用like的时候,也可以把 % 写在 sql 语句中
*/
@Query(value = "select * from cst_customer where cust_address like %?1%", nativeQuery = true)
List<Customer> findCustLikeAddr(String addr);
@Query(value = "select count(*) from cst_customer", nativeQuery = true)
Long getTotalCount();
//可以通过自定义 JPQL 完成 UPADATE 和 DELETE 操作,但是 JPQL 不支持使用 INSERT 操作。
@Transactional(timeout = 10)
@Modifying
@Query(value = "delete from cst_customer where cust_id = ?1", nativeQuery = true)
int deleteByCustId(Long id);
测试
@Test
public void testGetMaxCustId(){
Customer maxCustId = customerRepository.getMaxCustId();
System.out.println(maxCustId);
}
@Test
public void testModifyCustNameByCustId(){
int i = customerRepository.modifyCustNameByCustId("王五", 5L);
System.out.println(i == 1? "修改成功" : "修改失败");
}
@Test
public void testFindCust(){
List<Customer> cust = customerRepository.findCust("王五", "湖北武汉");
for (Customer customer : cust) {
System.out.println(customer);
}
}
@Test
public void testFindCustLike(){
List<Customer> list = customerRepository.findCustLike("%王%", "%湖南%");
for (Customer customer : list) {
System.out.println(customer);
}
}
@Test
public void testFindCustLikeAddr(){
List<Customer> list = customerRepository.findCustLikeAddr("河南");
list.forEach(System.out::println);
}
@Test
public void testGetTotalCount(){
Long totalCount = customerRepository.getTotalCount();
System.out.println(totalCount);
}
@Test
public void testDeleteByCustId(){
int i = customerRepository.deleteByCustId(6L);
System.out.println(i == 1? "删除成功":"删除失败");
}
5、分页查询
//分页查询
@Test
public void findAllPage(){
//Sort sort = Sort.by(Sort.Direction.DESC, "custId");
Sort sort = Sort.by(Sort.Order.desc("custId"));//按id倒序排序
//查询第2页(从0算起),页面大小为3
Pageable pageable = PageRequest.of(2, 3, sort);
Page<Customer> page = customerRepository.findAll(pageable);
System.out.println(page);
System.out.println("总页数: "+page.getTotalPages());
page.get().forEach(System.out::println);
System.out.println("内容:"+page.getContent());
System.out.println("总数:"+page.getTotalElements());
System.out.println("当前页数:" + page.getNumber());
System.out.println("当前页的总数:" + page.getNumberOfElements());
System.out.println("每页的大小:" + page.getSize());
System.out.println("是否有下一页:"+page.hasNext());
System.out.println("是否有上一页:"+page.hasPrevious());
System.out.println("是否有内容:"+page.hasContent());
}
6、条件查询
@Test
public void testFindByExample(){
Customer customer = new Customer();
customer.setCustName("zhangsan");
Example<Customer> example = Example.of(customer);
List<Customer> list = customerRepository.findAll(example);
list.forEach(System.out::println);
}
推荐阅读
-
Spring Data JPA例子代码[基于Spring Boot、Mysql]
-
Spring-Data-JPA整合MySQL和配置的方法
-
在Spring Boot中使用Spring-data-jpa实现分页查询
-
序列化表单为json对象,datagrid带额外参提交一次查询 后台用Spring data JPA 实现带条件的分页查询 多表关联查询
-
spring data jpa碰到的坑
-
Spring Boot入门系列八(SpringBoot 整合Mybatis)
-
使用Spring Data JPA进行数据分页与排序
-
spring-data-jpa实现增删改查以及分页操作方法
-
详解Spring Data JPA使用@Query注解(Using @Query)
-
Spring Data JPA使用Sort进行排序(Using Sort)