WEB

Spring Data学习 04:Spring Data JPA

2019-05-01  本文已影响8人  我问你瓜保熟吗

Spring Data 学习 01 :JDBC 访问 MySQL

Spring Data 学习 02 :Spring JdbcTemplate 访问 MySQL

Spring Data 学习 03 :JPA

Spring Data 学习 04:Spring Data JPA


一、什么是Spring Data JPA:

  • 是更大的Spring Data家族的一部分
  • 对基于JPA的数据访问层的增强支持
  • 更易于构建基于使用Spring数据访问技术栈的应用程序

二、Jpa、Hibernate、Spring Data Jpa三者之间的关系

JPA是ORM规范,它仅仅定义了一些接口。Hibernate、TopLink是实现了JPA规范的ORM框架,具体实现了JPA定义的接口。Spring Data JpaJPA 是对JPA规范的再次封装抽象(Repository层的实现)。Spring Data JPA的核心目标之一是减少代码并简化数据访问层

三、Repository

定义:
public interface Repository<T, ID extends Serializable>{

}
使用:User是实体类,int代表User的id的类型
     添加注解和继承Repository效果一样
// @RepositoryDefinition(domainClass = User.class, idClass = int.class)
public interface UserRepository extends Repository<User, int>{
        public User findByName(String name);
}

Repository同Serializable一样是一个空接口,没有包含方法声明的接口被称之为标记接口

public interface CrudRepository<T,ID extends Serializable>
    extends Repository<T,ID> {
    <S extends T> S save(S entity);
    T findOne(ID primaryKey);
    Iterable<T> findAll();
    Long count();
    void delete(T entity);
    boolean exists(ID primaryKey);
}
public interface PagingAndSortingRepository<T,ID extends Serializable>
    extends CrudRepository<T,ID> {
    Iterable<T> findAll(Sort sort);
    Page<T> findAll(Pageable pageable);
}

四、根据方法名创建自定义查询

public interface PersonRepository extends JpaRepository<User,Long>{
    List<Person> findByEmailAddressAndLastname(EmailAddress emailAddress, String lastname);
    
    // 启用 distinct 标志(去重:放在前面后面都可以)
    List<Person> findDistinctPeopleByLastnameOrFirstname(String lastname, String firstname);
    List<Person> findPeopleDistinctByLastnameOrFirstname(String lastname, String firstname);

    // 给独立的属性启用 ignore case(忽略大小写)
    List<Person> findByLastnameIgnoreCase(String lastname);
    // 给所有合适的属性启用 ignore case
    List<Person> findByLastnameAndFirstnameAllIgnoreCase(String lastname, String firstname);

    // 启用 ORDER BY(排序)
    List<Person> findByLastnameOrderByFirsnameAsc(String lastname);
    List<Person> findByLastnameOrderByFirsnameDesc(String lastname);
}
Spring Data JPA接口约定命名规则

五、实体类注解

数据库实体类是一个 POJO Bean 对象。

1、常用注解解释:

 * @Entity 用来标示这个类是实体类
 * @Table  实体类与数据表的映射,通过name确定在表名(默认类名为表名)比如类Users 和表 users;
 * @Id         主键注解,表示该字段为主键
 * @GeneratedValue 定义主键规则,默认AUTO
 * @Column 类属性与表字段映射注解,其中可以设置在字段名,长度等信息
 * @ManyToOne  多对一,可以设置数据加载方式等 默认加载方式是EAGER 就是使用left join
 * @OneToMany  一对多 默认加载方式是 LAZY 懒加载
 * @JoinColumn 与*对*配合使用,用来设置外键名等信息
 * @Basic  实体类中会默认为每一个属性加上这个注解,表示与数据表存在关联,
 *              没有使用Column注解的类属性会以属性名作为字段名,驼峰命名需要转为_
 * @Temporal 对于Date属性的格式化注解,有 TIME,DATE,TIMESTAMP 几个选择
 * @Transient 标注该属性不做与表的映射(原因:可能表中没有该属性对应的字段)有该注解,在执行sql语句时,就不会出现该属性,否则会有,若表中没有该字段则会报错。若存在不想与数据表映射的属性,则需要加上该注解,

2、主键上的注解

    // 1、id生成策略自动增长 
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private String id;

    // 2、配置uuid,本来jpa是不支持uuid的,但借用hibernate的方法
    @Id
    @GeneratedValue(generator = "uuid")     可以实现。
    @GenericGenerator(name = "uuid", strategy = "uuid")
    private String id;
  • UUID可以自动生成一个36字符组成的字符串,UUID是由10个阿拉伯数字加上26个字母组成,8-4-4-4-12的形式组成,例如:4c47cf4a-a55a-4fce-8cd9-024a790714b010。
  • 产生UUID的方法:String uuid=UUID.randomUUID().toString();

六、依赖与配置

// 添加 Spring Data JPA依赖
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
// 添加 MySQL连接驱动依赖
    runtimeOnly 'mysql:mysql-connector-java'
       <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
#通用数据源配置
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/student?charset=utf8mb4&useSSL=false
spring.datasource.username=root
spring.datasource.password=root
# Hikari 数据源专用配置
spring.datasource.hikari.maximum-pool-size=20
spring.datasource.hikari.minimum-idle=5
# JPA 相关配置
spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect  // 在 SrpingBoot 2.0 版本中,Hibernate 创建数据表的时候,默认的数据库存储引擎选择的是 MyISAM ?这个参数是在建表的时候,将默认的存储引擎切换为 InnoDB.
spring.jpa.show-sql = true    // 控制台显示sql
spring.jpa.hibernate.ddl-auto=create    // 只能开发中使用:删除数据,重新创建表结构。

七、实战操作

1、建数据库student和表student

CREATE TABLE `student` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;

2、建立数据库实体类

package com.example.demo.Entity;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity 
public class Student {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    private int age;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

3、创建数据库持久层

package com.example.demo.Repository;

import com.example.demo.Entity.Student;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

import java.util.List;


public interface StudentRepository extends JpaRepository<Student, Long> {

    // 利用注解自定义查询预警
    @Query("select o from Student o where id = (select max(id) from Student o)") // Student 是对象
    public Student getStudentByMaxId();

    // 根据索引参数进行查询
    @Query("select o from  Student o where o.name=?1 and o.age=?2")
    public List<Student>queryParams(String name, int age);

    // 根据别名参数进行查询
    @Query("select o from  Student o where o.name=:name and o.age=:age")
    public List<Student>queryParams2(@Param("name")String name,@Param("age") int age);

    // 原生SQL语句查询
    @Query(nativeQuery = true,value = "select count(1) from student")  // student是表名
    public long getCount();

    // @query注解 修改、新增、删除等,要添加@Modifying注解,要在Service里面处理,并增加事务注解 @Transactional
    @Modifying
    @Query("update Student o set o.age = :age where o.id = :id")
    public void update(@Param("id") Long id, @Param("age") int age);
}

4、创建Service

增删改操作需要事务支持,事务要放在Service层,一个service可能要调用多个dao调用,要保证多个调用在一个事务里。

package com.example.demo.Service;

import com.example.demo.Repository.StudentRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.transaction.Transactional;


@Service
public class StudentService {

    @Autowired
    private StudentRepository studentRepository;

    @Transactional
    public void update(Long id, int age){
       studentRepository.update(id,age);
    }
}

5、对持久层 增删改查等操作 进行单元测试

package com.example.demo;

import com.example.demo.Entity.Student;
import com.example.demo.Repository.StudentRepository;
import com.example.demo.Service.StudentService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.ArrayList;
import java.util.List;

@RunWith(SpringRunner.class)
@SpringBootTest
public class DemoApplicationTests {

    @Autowired
    private StudentRepository studentRepository;

    @Autowired
    private StudentService studentService;

    // 自建操作测试
    @Test
    public void getByMaxId(){
        Student student = studentRepository.getStudentByMaxId();
        System.out.println("id:"+student.getId()+"name:"+student.getName()+"age:"+student.getAge());
    }
    @Test
    public void queryParams(){
        List<Student> students = studentRepository.queryParams("护士", 24);
        for (Student student:students){
            System.out.println("id:"+student.getId()+"name:"+student.getName()+"age:"+student.getAge());
        }
    }
    @Test
    public void queryParams2(){
        List<Student> students = studentRepository.queryParams("护士", 24);
        for (Student student:students){
            System.out.println("id:"+student.getId()+"name:"+student.getName()+"age:"+student.getAge());
        }
    }
    @Test
    public void getCount(){
        long count = studentRepository.getCount();
        System.out.println(count);
    }
    @Test
    public void update(){
        studentService.update(1L,19);
    }

    // 自带增加、删除、查询、分页、排序 测试
    @Test
    public void add() {
        // 增加一个
        Student student = new Student();
        student.setName("老师");
        student.setAge(23);
        studentRepository.save(student);
    }
    @Test
    public void delete() {
        // 增加一个
        Student student = new Student();
        student.setName("老师");
        student.setAge(23);
        studentRepository.deleteById(1L);
    }
    @Test
    public void findall(){
        // 查询所有
        ArrayList<Student> all = new ArrayList<>();
        for (Student student:studentRepository.findAll()){
            System.out.println("id:"+student.getId()+"name:"+student.getName()+"age:"+student.getAge());
        }
    }
    // 分页和排序
    @Test
    public void testPage(){

        Sort sort= new Sort(Sort.Direction.DESC, "id");

        PageRequest Request = PageRequest.of(0,5, sort);
        Page<Student> allPage = studentRepository.findAll(Request);

        System.out.println("查询总页数"+allPage.getTotalPages());
        System.out.println("查询总记录数"+allPage.getTotalElements());
        System.out.println("查询当前是第几页"+(allPage.getNumber()+1));
        System.out.println("查询当前页面的内容集合"+allPage.getContent());
        System.out.println("查询当前页面的记录数"+allPage.getNumberOfElements());


    }

}
上一篇下一篇

猜你喜欢

热点阅读