欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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);
    }