Spring Data

目录

一、Spring Data 介绍

二、搭建 Spring Data JPA 环境

三、Repository 接口

四、Query 注解

五、CrudRepository接口

六、PagingAndSortingRepository 接口

七、JpaSpecificationExecutor 接口


一、Spring Data 介绍

Spring Data : Spring 的一个子项目。用于简化数据库访问,支持NoSQL 和 关系数据存储。其主要目标是使数据库的访问变得方便快捷。开发者唯一要做的,就是声明持久层的接口,其他都交给 Spring Data JPA 来帮你完成!

SpringData 项目所支持 NoSQL 存储:

  • MongoDB (文档数据库)

  • Neo4j(图形数据库)

  • Redis(键/值存储)

  • Hbase(列族数据库)

SpringData 项目所支持的关系数据存储技术:

  • JDBC

  • JPA

二、搭建 Spring Data JPA 环境

  1. 使用Maven构建项目,项目名为:springdatajpa

  2. 配置 pom.xml

    <properties>
        <spring.version>5.2.6.RELEASE</spring.version>
        <hibernate.version>5.4.10.Final</hibernate.version>
        <mysql.version>8.0.21</mysql.version>
        <ehcache.version>3.8.1</ehcache.version>
        <jpa.version>1.0.1.Final</jpa.version>
        <slf4j.version>1.7.25</slf4j.version>
        <aspectj.version>1.9.5</aspectj.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>
    ​
    <dependencies>
        <!-- Spring -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-orm</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-jpa</artifactId>
            <version>2.2.5.RELEASE</version>
        </dependency>
        <!-- Hibernate -->
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-core</artifactId>
            <version>${hibernate.version}</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-entitymanager</artifactId>
            <version>${hibernate.version}</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-hikaricp</artifactId>
            <version>${hibernate.version}</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-ehcache</artifactId>
            <version>${hibernate.version}</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate.javax.persistence</groupId>
            <artifactId>hibernate-jpa-2.0-api</artifactId>
            <version>${jpa.version}</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>${mysql.version}</version>
        </dependency>
        <dependency>
            <groupId>org.ehcache</groupId>
            <artifactId>ehcache</artifactId>
            <version>${ehcache.version}</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>${slf4j.version}</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>${aspectj.version}</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.12</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
  3. 创建 com.javakc.springdatajpa 包

  4. 创建 entity 包并在其目录下创建实体类

  5. 创建 dao 包并在其目录下创建接口继承 JpaRepository<T, ID> 接口

  6. 在 resources 目录下创建 jdbc.properties 配置文件

    jdbc.driverClass=com.mysql.cj.jdbc.Driver
    jdbc.jdbcUrl=jdbc:mysql:///jpa?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8
    jdbc.username=root
    jdbc.password=123456
  7. 在 resources 目录下创建 spring-jpa.xml 配置文件

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
           xmlns:jpa="http://www.springframework.org/schema/data/jpa"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/data/jpa https://www.springframework.org/schema/data/jpa/spring-jpa.xsd">
    ​
        <!-- 配置自动扫描包 -->
        <context:component-scan base-package="com.javakc.springdatajpa"></context:component-scan>
    ​
        <!-- 加载配置文件 -->
        <context:property-placeholder location="jdbc.properties"></context:property-placeholder>
    ​
        <!-- 配置 Hikari 数据源 -->
        <bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource">
            <property name="driverClassName" value="${jdbc.driverClass}"></property>
            <property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property>
            <property name="username" value="${jdbc.username}"></property>
            <property name="password" value="${jdbc.password}"></property>
        </bean>
    ​
        <!-- 配置 JPA 的 EntityManagerFactory -->
        <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
            <property name="dataSource" ref="dataSource"></property>
            <property name="jpaVendorAdapter">
                <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"></bean>
            </property>
            <property name="packagesToScan" value="com.javakc.springdatajpa.entity"></property>
            <property name="jpaProperties">
                <props>
                    <prop key="hibernate.show_sql">true</prop>
                    <prop key="hibernate.format_sql">true</prop>
                    <prop key="hibernate.hbm2ddl.auto">update</prop>
                </props>
            </property>
        </bean>
    ​
        <!-- 配置 JPA 使用的事物管理器 -->
        <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
            <property name="entityManagerFactory" ref="entityManagerFactory"></property>
        </bean>
    ​
        <!-- 配置支持基于注解的事物配置 -->
        <tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
    ​
        <!-- 配置 SpringDataJpa -->
        <jpa:repositories base-package="com.javakc.springdatajpa" entity-manager-factory-ref="entityManagerFactory"></jpa:repositories>
    ​
    </beans>
  8. 创建测试类

    import com.javakc.springdatajpa.repository.JpaRepository;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    ​
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(locations = {"classpath:spring-jpa.xml"})
    public class JpaTest {
    ​
        @Autowired
        private StudentDao studentDao;
    ​
        @Test
        public void test() {
        }
    ​
    }

三、Repository 接口

Repository 接口是 Spring Data 的一个核心接口,它不提供任何方法,开发者在自己定义的接口中声明需要的方法,只要遵循 Spring Data的规范,就无需写实现类。

基础的 Repository 提供了最基本的数据访问功能,其几个子接口则扩展了一些功能。它们的继承关系如下:

  • Repository: 仅仅是一个标识,表明任何继承它的均为仓库接口类

  • CrudRepository: 继承 Repository,实现了 CRUD 相关的方法

  • PagingAndSortingRepository: 继承 CrudRepository,实现了分页排序相关的方法

  • JpaRepository: 继承 PagingAndSortingRepository,实现 JPA 规范相关的方法

  • JpaSpecificationExecutor: 不属于Repository体系,实现 JPA Criteria 查询条件相关的方法

四、Query 注解

  1. 使用 @Query 注解可以自定义 JPQL 语句来实现更灵活的查询,结构更为清晰,这是 Spring data 的特有实现

    @Query("select count(s) from Student s")
    public int getCountStudent();
  2. 索引参数

    @Query("select s from Student s where s.id = ?1 and s.studentName = ?2")
    public Student getStudentParam1(int id, String studentName);
  3. 命名参数

    @Query("select s from Student s where s.id = :id and s.studentName = :studentName")
    public Student getStudentParam2(@Param("id") int id,@Param("studentName") String studentName);
  4. 模糊查询

    @Query("select s from Student s where s.studentName like %?1%")
    public List<Student> findStudentParam3(String studentName);
    @Query("select s from Student s where s.studentName like %:studentName%")
    public List<Student> findStudentParam4(@Param("studentName") String studentName);
  5. 原生SQL

    @Query(value="select count(id) from jpa_student", nativeQuery=true)
    public int getCountStudent2();

五、CrudRepository接口

  1. 保存

    @Test
    public void save() {
        Student student = new Student();
        student.setStudentName("小明");
        jpaDao.save(student);
    }
  2. 删除

    @Test
    public void delete() {
        jpaDao.deleteById(1);
    }
  3. 获取单条数据

    @Test
    public void get() {
        Optional<Student> o = studentDao.findById(1);
        Student student = o.get();
        System.out.println(student);
    }
  4. 修改

    @Test
    public void update() {
        Student student = new Student();
        student.setId(1);
        student.setStudentName("小红");
        jpaDao.save(student);
    }

六、PagingAndSortingRepository 接口

分页与排序

@Test
public void testPageAndSort() {
    int pageNo = 1 -1;
    int pageSize = 3;

    Sort.Order order1 = new Sort.Order(Sort.Direction.ASC, "id");
    Sort.Order order2 = new Sort.Order(Sort.Direction.ASC, "studentName");
    Sort sort = Sort.by(order1, order2);

    Pageable pageable = PageRequest.of(pageNo,pageSize,sort);
    Page<Student> page = jpaDao.findAll(pageable);
    System.out.println("总记录数: " + page.getTotalElements());
    System.out.println("总页数: " + page.getTotalPages());
    System.out.println("当前页数据: " + page.getContent());
    System.out.println("当前页记录数: " + page.getNumberOfElements());
}

七、JpaSpecificationExecutor 接口

继承 JpaSpecificationExecutor<T> 接口

带条件的分页查询

@Test
public void testPageAndCriteria() {
    Specification<Student> specification = new Specification<Student>() {
        /**
         * @param root 要查询的实体类
         * @param criteriaQuery 得到 Root 对象, 告知 JPA Criteria 要查询哪个实体类
         * @param criteriaBuilder 创建 Criteria 对象的工厂, 得到 Predicate 对象
         * @return 表示一个查询条件
         */
        @Override
        public Predicate toPredicate(Root<Student> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
            Path path = root.get("studentName");
            Predicate predicate = criteriaBuilder.like(path, "%D%");
            return predicate;
        }
    };

    int pageNo = 1 -1;
    int pageSize = 3;
    Pageable pageable = PageRequest.of(pageNo, pageSize);

    Page<Student> page = jpaDao.findAll(specification, pageable);
    System.out.println("总记录数: " + page.getTotalElements());
    System.out.println("总页数: " + page.getTotalPages());
    System.out.println("当前页数据: " + page.getContent());
    System.out.println("当前页记录数: " + page.getNumberOfElements());
}

带条件的分页查询 - 多表关联

@Test
public void testPageAndCriteria2() {
    Specification<Student> specification = new Specification<Student>() {
        @Override
        public Predicate toPredicate(Root<Student> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
            // ## 动态 SQL 表达式
            Predicate predicate = criteriaBuilder.conjunction();
            // ## 动态 SQL 表达式集合
            List<Expression<Boolean>> expressionList = predicate.getExpressions();
            
            Join<Object, Object> join = root.join("classRoom", JoinType.LEFT);
            expressionList.add(criteriaBuilder.equal(join.get("classRoomName"), "javakc"));
            return predicate;
        }
    };
    int pageNo = 1 -1;
    int pageSize = 3;
    Pageable pageable = PageRequest.of(pageNo, pageSize);

    Page<Student> page = jpaDao.findAll(specification, pageable);
    System.out.println("总记录数: " + page.getTotalElements());
    System.out.println("总页数: " + page.getTotalPages());
    System.out.println("当前页数据: " + page.getContent());
    System.out.println("当前页记录数: " + page.getNumberOfElements());
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

五毒幽泉

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值