Springboot整合jpa的基本使用方法大全

标签:

本文出自jvm123.com-java技术分享站:http://jvm123.com/2019/09/springboot-jpa.html

《springboot整合jpa的基本使用方法大全》本文 以mysql为例 ,主要讲解springboot整合jpa,以及jpa对数据操作的各种不同方法。

springboot项目中jpa的依赖

        <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>

如果使用的不是mysql,则可以加入其他的数据库驱动依赖,例如postgres。

springboot项目中jpa的配置

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/test?useSSL=false&serverTimezone=UTC
    driver-class-name: com.mysql.jdbc.Driver
    username: root
    password: root
  jpa:
    show-sql: true
    hibernate:
      ddl-auto: update
    properties:
      hibernate:
        dialect: org.hibernate.dialect.MySQL5Dialect

定义jpa的实体Person

@Entity
public class Person {
    @Id
    /**
     * 生成器的13种策略:
     * @see org.hibernate.id.factory.internal.DefaultIdentifierGeneratorFactory
     */
    // 声明一个策略通用生成器,name为system-uuid,策略strategy为uuid。
    @GenericGenerator(name = "increment", strategy ="increment")
    // 用generator属性指定要使用的策略生成器。
    @GeneratedValue(generator = "increment")
    private long id;
    private String name;
    private int age;
    private Date birthDay;

启动项目后,会自动在数据库中创建一个名为person的数据表,和实体person对应。其中关联表的定义和创建详见 A。

使用jpa的 CrudRepository 基本查询

/**
 * @author yawn
 * 2019/9/15 15:18
 */
public interface PersonCrudRepo extends CrudRepository<Person, Long> {

}

只需要继承CrudRepository接口即可, PersonCrudRepo即可注入其他service使用,这里提供了基本的crud方法,使用示例如下:

    @Autowired
    PersonCrudRepo personCrudRepo;
    
    Person createAPerson() {
        Person person = new Person();
        person.setAge(18);
        person.setBirthDay(new Date());
        person.setName("yawn");
        return person;
    }

    @Test
    public void test1() {
        Person p = createAPerson();
        // test crud
        Person p1 = personCrudRepo.save(p);
        System.out.println(p1);
        Person p3 = personCrudRepo.findOne(1L);
        System.out.println(p3);
        Iterable<Person> all = personCrudRepo.findAll();
        System.out.println(all);
//        personCrudRepo.delete(2L);
//        personCrudRepo.deleteAll();
    }

delete方法如果删除失败,请加上@Transactional注解。

使用jpa的 PagingAndSortingRepository 分页查询和排序

/**
 * @author yawn
 * 2019/9/15 15:18
 */
public interface PersonPageSortRepo extends PagingAndSortingRepository<Person, Long> {

}

调用方法如下:

@Test
public void test2() {
    // all
    Iterable<Person> all = personPageSortRepo.findAll();
    System.out.println(all);
    // 1. page (page从0开始计数)
    Pageable pa1 = new PageRequest(1, 2);
    Page<Person> page1 = personPageSortRepo.findAll(pa1);
    page1.forEach(System.out::println);
    // 3. page and sort
    Sort sort = new Sort(Sort.Direction.DESC, "id", "name", "age");
    Pageable pa2 = new PageRequest(1, 2, sort);
    Page<Person> page2 = personPageSortRepo.findAll(pa2);
    page2.forEach(System.out::println);
    // 2. sort
    Iterable<Person> people = personPageSortRepo.findAll(sort);
    System.out.println(people);
    // 4. 多个sort
    Sort desc = new Sort(Sort.Direction.DESC, "id");
    Sort asc = new Sort(Sort.Direction.ASC, "name");
    Sort sort1 = desc.and(asc); // and 后的是次要排序属性
    Iterable<Person> people2 = personPageSortRepo.findAll(sort1);
    System.out.println(people2);
}

1. PageRequest是 Pageable 的一个实现类,其参数page和size分别表示从第page页开始,查询size条记录。执行sql语句时,相当于加上了 limit page, size

2. Sort是一个数据库排序的辅助类,其属性direction表示升序或降序,值为 Sort.Direction.DESC 和 Sort.Direction.ASC;properties表示需要排序的字段。 执行sql语句时,相当于加上了 order by id desc, name desc, age desc

3. 在 PageRequest 类中传入一个sort对象,就可以实现分页和排序两种功能。 执行sql语句时,相当于加上了 order by id desc, name desc, age desc limit page, size

4. 如果查询时,不同的字段使用不同的升序或降序,则需要使用Sort类的and()方法。如上代码中,两个不同的sort,使用and方法后,生成新的Sort对象结合了不同的排序方式。执行的sql语句,相当于加上了 order by id desc, name asc

使用jpa的 Repository 自定义声明式查询方法

凡是继承了Repository的或继承其子接口的,都可以使用自定义的声明式查询方法,如下示例:

/**
 * @author yawn
 * 2019/9/15 15:18
 */
public interface PersonQueryRepo extends Repository<Person, Long> {

    // declare query method
    // 声明式查询方法

    // 1. count 计数
    long countByName(String name);

    // 2. get/find/stream/query/read 查询
    Person readFirstByAge(int age);

    // 3. delete/remove 删除
    @Transactional
    int deleteById(long id);

}

声明式查询方法可以分3大类:

1 计数类 :以count开头,返回数值类型

Springboot整合jpa的基本使用方法大全插图

2 查询类:以get/find/stream/query/read开头,返回Person类或其集合

Springboot整合jpa的基本使用方法大全插图(1)

3 删除类: 以delete/remove开始,返回int类型

Springboot整合jpa的基本使用方法大全插图(2)

其中方法名称支持的关键字和可以参考:jpa Repository 支持的自定义查询方法名称关键词

@Query使用jpa的jpql或者hql(实现update更新的一种方法)

示例如下:

/**
 * @author yawn
 * 2019/9/15 17:02
 */
public interface PersonHqlDao extends JpaRepository<Person, Long> {

    // 使用hql 或者 jpql 查询
    @Query("from Person where name = ?1 order by id desc")
    List<Person> listByName(String name);

    // 前几种方法中均未介绍update操作,要完成update操作,可使用以下方法
    // 更新时需要加上 @Transactional 和 @Modifying
    @Transactional
    @Modifying // QueryExecutionRequestException: Not supported for DML operations
    @Query("update Person set name=?2 where id=?1")
    int updateNameById(long id, String name);
}

@Query使用jpa的sql

@Query注解使用sql时,需要加上nativeQuery = true,示例如下:

public interface UserRepository extends JpaRepository<User, Long> {
  @Query(value = "SELECT * FROM USERS WHERE LASTNAME = ?1",
    countQuery = "SELECT count(*) FROM USERS WHERE LASTNAME = ?1",
    nativeQuery = true)
  Page<User> findByLastname(String lastname, Pageable pageable);
}

总体来说,推荐使用hql,不推荐sql。曾经有一次数据库字段名称改变后,我查找修改了许多sql语句,项目上线后还是报错了,日志中显示出来的,正是sql语句中有一处漏掉还未修改过来。如果使用hql的话,就不存在这个问题,只需要在实体的@Column注解处修改一次即可。

以上所有,就是jpa中常用到的数据库交互方法。

发表评论