821-轻松愉快之玩转SpringData

https://www.imooc.com/learn/821

简介:在企业级JavaEE应用开发中,对数据库的访问和操作是必须的。Spring Data作为SpringSource的其中一个子项目,旨在统一和简化对各类型持久化存储和访问,而不拘泥于是关系型数据库还是NoSQL数据存储,使得对数据库的访问变得方便快捷,并支持MapReduce框架及云计算服务;对于拥有海量数据的项目,可以用Spring Data来简化项目的开发,就如Spring Framework对JDBC、ORM的支持一样,Spring Data会让数据的访问变得更加方便,极大提高开发效率、提升程序员的幸福指数!

第1章 课程介绍

课程介绍

1-1 课程介绍

什么是Spring Data

主旨:provide a familiar and consistent,Spring-based programming model for data access
​ 提供一个熟悉的、一致的,基于Spring框架的数据访问框架。

简化数据库的访问。
历史:2010年提出,作者Rod Johnso,Spring Source项目
网址:http://projects.spring.io/spring-data/#quick-start

Spring Data概览

Spring Data概览

Spring Data包含多个子项目

  • Spring Data JPA
    减少数据访问层的开发量

  • Spring Data Mongo DB
    基于分布于存储的数据库

  • Spring Data Redis
    开源、C语言开发、支持网络内存、可持久化的Key-Value的数据库

  • Spring Data Solr
    Solr是高性能的、Java语言开发、基于Lucence的全文搜索服务器

课程安排

  • 传统方式访问数据库
    原生JDBC、Spring JdbcTemplate
  • Spring Data快速起步
  • Spring Data JPA进阶
    • Spring Data JPA高级

第2章 使用传统方式访问数据库

先使用传统的JDBC方法操作数据库,进而再使用Spring JdbcTemplate方式操作数据库,并对比现存操作方式的优缺点

2-1 使用传统方式访问数据库

  • JDBC
  • Spring JdbcTemplate
  • 弊端分析

2-2 准备工作

JDBC

Connection
Statement
ResultSet
Test Case

搭建开发环境

  • 创建maven项目
    Maven工程的目录结构

  • 添加数据库驱动和单元测试依赖

    <!-- mysql -->
    <dependency>
       <groupId>mysql</groupId>
       <artifactId>mysql-connector-java</artifactId>
       <version>5.1.38</version>
    </dependency>
    <!-- junit -->
    <dependency>
       <groupId>junit</groupId>
       <artifactId>junit</artifactId>
       <version>4.10</version>
       <scope>test</scope>
    </dependency>
  • 数据库表的准备,使用mysql数据库

    # 创建数据库
    create database spring_data;
    # 创建数据表
    create table student(
        id int not null auto_increment,
        name varchar(20)not null,
        age int not null,
        primary key(id)
    );
    # 查看表结构
    desc student;
    # 插入数据
    insert into student(name,age)values("zhangsan", 20);
    insert into student(name,age)values("lisi", 21);
    insert into student(name,age)values("wangwu", 22);
    # 查询数据
    select * from student;

2-3 JDBCUtil开发

开发JDBCUtil工具类:

获取Connection,关闭Connection、Statement、ResultSet
注意事项:配置的属性放置配置文件中,然后通过代码的方式将配置文件中的数据加载进来即可。

代码示例:

package com.myimooc.springdata.jdbc.util;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
/**
 * JDBC工具类:
 * 1)获取Connection
 * 2)释放资源
 */
public class JDBCUtils {
    /**
     * 获取Connection
     * @return 所获得到的JDBC的Connection
     */
    public static Connection getConnection() throws Exception {
        /**
         * 不建议大家把配置硬编码到代码中
         * 最佳实践:配置性的建议写到配置文件中
         * */
//        String url = "jdbc:mysql:///spring_data";
//        String username = "root";
//        String password = "root";
//        String dirverClass = "com.mysql.jdbc.Driver";
        InputStream inputStream =  JDBCUtils.class.getClassLoader().getResourceAsStream("db.properties");
        Properties properties = new Properties();
        properties.load(inputStream);
        String url = properties.getProperty("jdbc.url");
        String username = properties.getProperty("jdbc.username");
        String password = properties.getProperty("jdbc.password");
        String driverClass = properties.getProperty("jdbc.driverClass");

        Class.forName(driverClass);
        return DriverManager.getConnection(url,username,password);
    }
    /**
     * 释放DB相关资源
     */
    public static void release(ResultSet resultSet, Statement statement, Connection connection) throws Exception {
        if(resultSet != null ){
            resultSet.close();
        }
        if(statement != null ){
            statement.close();
        }
        if(connection != null ){
            connection.close();
        }
    }
}

数据库连接配置文件:

# db.properties
jdbc.url = jdbc:mysql:///spring_data
jdbc.user = root
jdbc.password = root
jdbc.driverClass = com.mysql.jdbc.Driver

注:

  • 配置的属性放在配置文件中,然后通过代码的方式将配置文件中的数据加载进来即可。

单元测试:

@Test
public void testGetConnection() throws Exception {
    Connection connection = JDBCUtil.getConnection();
    Assert.assertNotNull(connection);
}

2-4 Dao开发

建立对象模型及DAO层开发。

代码演示:

  1. 对象模型

    package com.myimooc.springdata.jdbc.domain;
    /**
     * Student实体类
     */
    @Data
    public class Student {
        /** 主键ID */
        private Integer id;
        /** 姓名 */
        private String name;
        /** 年龄 */
        private int age;
    }
  2. DAO接口

    package com.myimooc.springdata.jdbc.dao;
    import com.myimooc.springdata.jdbc.domain.Student;
    import java.util.List;
    /**
     * Student DAO访问接口
     */
    public interface StudentDao {
        /**
         * 获取所有学生
         * @return 所有学生
         */
        List<Student> listStudent();
        /**
         * 添加一个学生
         * @param student 待添加的学生
         */
        void saveStudent(Student student);
    }
  3. DAO实现

    package com.myimooc.springdata.jdbc.dao.impl;
    import com.myimooc.springdata.jdbc.dao.StudentDao;
    import com.myimooc.springdata.jdbc.domain.Student;
    import com.myimooc.springdata.jdbc.util.JDBCUtils;
    import java.sql.Connection;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.util.ArrayList;
    import java.util.List;
    /**
     * Student DAO访问接口实现类:通过最原始的JDBC的方式操作
     */
    public class StudentDaoImpl implements StudentDao {
        public List<Student> listStudent() {
            List<Student> studentList = new ArrayList<Student>();
    
            String sql = "select id,name,age from student";
            try (Connection connection = JDBCUtils.getConnection();
                 PreparedStatement preparedStatement = connection.prepareStatement(sql);
                 ResultSet resultSet = preparedStatement.executeQuery();) {
                while(resultSet.next()) {
                    Student student = new Student();
                    student.setId(resultSet.getInt("id"));
                    student.setName(resultSet.getString("name"));
                    student.setAge(resultSet.getInt("age"));
                    studentList.add(student);
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                JDBCUtils.release(resultSet, preparedStatement, connection);
            }
            return studentList;
        }
    
        public void saveStudent(Student student) {
            String sql = "insert into student(name,age) values(?, ?)";
    
            try (Connection connection = JDBCUtils.getConnection();
                 PreparedStatement preparedStatement = connection.prepareStatement(sql);) {
                preparedStatement.setString(1, student.getName());
                preparedStatement.setInt(2, student.getAge());
                preparedStatement.executeUpdate();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                JDBCUtils.release(resultSet,preparedStatement,connection);
            }
        }
    }
  4. 单元测试

    @Test
    public void listStudentTest(){
        StudentDao studentDao = new StudentDaoImpl();
        List<Student>  studentList = studentDao.listStudent();
        for(Student student : studentList){
            System.out.println(student);
        }
    }
    @Test
    public void saveStudentTest(){
        StudentDao studentDao = new StudentDaoImpl();
        Student student = new Student("test", 30);
        studentDao.saveStudent(student);
    }

2-5 使用JdbcTemplate

Spring JdbcTemplate

  • 添加maven依赖

    <!--spring-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>4.3.5.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>4.3.5.RELEASE</version>
    </dependency>
  • DataSource & JdbcTemplate注入

    Spring配置文件

    <!-- beans.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"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd">
    
        <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
            <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
            <property name="username" value="root"/>
            <property name="password" value="root"/>
            <property name="url" value="jdbc:mysql:///spring_data"/>
        </bean>
    
        <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
            <property name="dataSource" ref="dataSource"/>
        </bean>
    
        <bean id="studentDAO" class="com.imooc.dao.StudentDAOSpringJdbcImpl">
            <property name="jdbcTemplate" ref="jdbcTemplate"/>
        </bean>
    </beans>
  • Test Case

    public class DataSourceTest {
        private ApplicationContext ctx = null;
        @Before
        public void setup(){
            System.out.println("setup");
            ctx = new ClassPathXmlApplicationContext("beans.xml");
        }
        @After
        public void tearDown(){
            System.out.println("tearDown");
            ctx = null;
        }
    
        @Test
        public void testDataSource(){
            System.out.println("testDataSource");
            DataSource dataSource = (DataSource)ctx.getBean("dataSource");
            Assert.notNull(dataSource);
        }
        @Test
        public void testJdbcTemplate(){
            System.out.println("testJdbcTemplate");
            JdbcTemplate jdbcTemplate = (JdbcTemplate)ctx.getBean("jdbcTemplate");
            Assert.notNull(jdbcTemplate);
        }
    }
    
  • Dao实现

    package com.imooc.dao;
    import com.imooc.domain.Student;
    import org.springframework.jdbc.core.JdbcTemplate;
    import org.springframework.jdbc.core.RowCallbackHandler;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.util.ArrayList;
    import java.util.List;
    /**
     * StudentDAO访问接口实现类:通过Spring jdbc的方式操作
     */
    @Data
    public class StudentDAOSpringJdbcImpl implements StudentDAO {
        @Autowired
        private JdbcTemplate jdbcTemplate;
    
        @Override
        public List<Student> query() {
            final List<Student> students = new ArrayList<Student>();
            String sql = "SELECT id, name, age FROM student";
    
            jdbcTemplate.query(sql, new RowCallbackHandler() {
                @Override
                public void processRow(ResultSet rs) throws SQLException {
                    Student student = new Student();
                    student.setId(rs.getInt("id"));
                    student.setName(rs.getString("name"));
                    student.setAge(rs.getInt("age"));
                    students.add(student);
                }
            });
            return students;
        }
    
        @Override
        public void save(Student student) {
            String sql = "INSERT INTO student(name, age) VALUES(?, ?)";
            jdbcTemplate.update(sql, student.getName(), student.getAge());
        }
    }
    
  • 单元测试

    public class StudentDAOSpringJdbcImplTest {
        private ApplicationContext ctx = null;
        private StudentDAO studentDAO = null;
    
        @Before
        public void setup(){
            System.out.println("setup");
            ctx = new ClassPathXmlApplicationContext("beans.xml");
            studentDAO = (StudentDAO)ctx.getBean("studentDAO");
        }
        @After
        public void tearDown(){
            System.out.println("tearDown");
            ctx = null;
        }
    
        @Test
        public void testQuery() {
            List<Student> students = studentDAO.query();
            for (Student student : students) {
                System.out.println("student:" + student);
            }
        }
        @Test
        public void testSave() {
            Student student = new Student("test-spring-jdbc", 40);
            studentDAO.save(student);
        }
    }

    END

代码演示:

  1. 创建DB配置文件

    jdbc.url = jdbc:mysql:///springdata
    jdbc.username = root
    jdbc.password = root
    jdbc.driverClass = com.mysql.jdbc.Driver
  2. 创建配置文件类

    package com.myimooc.springdata.jdbctemplate.config;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.annotation.ImportResource;
    import org.springframework.context.annotation.PropertySource;
    import org.springframework.stereotype.Component;
    /**
     * 配置参数类
     */
    @Data
    @PropertySource(value="classpath:db.properties")
    @Component
    public class Properties {
        @Value("${jdbc.driverClass}")
        private String jdbcDriverClass;
        @Value("${jdbc.url}")
        private String jdbcUrl;
        @Value("${jdbc.username}")
        private String jdbcUser;
        @Value("${jdbc.password}")
        private String jdbcPassword;
    }
  3. 配置DataSource、JdbcTemplate和Spring注解扫描

    package com.myimooc.springdata.jdbctemplate.config;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.jdbc.core.JdbcTemplate;
    import org.springframework.jdbc.datasource.DriverManagerDataSource;
    
    @Configuration
    @ComponentScan("com.myimooc.springdata.jdbctemplate")
    public class SpringConfig {
        @Autowired
        private Properties properties;
    
        @Bean
        DriverManagerDataSource getDriverManagerDataSource(){
            DriverManagerDataSource driverManagerDataSource = new DriverManagerDataSource();
            driverManagerDataSource.setDriverClassName(properties.getJdbcDriverClass());
            driverManagerDataSource.setUrl(properties.getJdbcUrl());
            driverManagerDataSource.setUsername(properties.getJdbcUser());
            driverManagerDataSource.setPassword(properties.getJdbcPassword());
            return driverManagerDataSource;
        }
        @Bean
        JdbcTemplate getJdbcTemplate(){
            JdbcTemplate jdbcTemplate = new JdbcTemplate();
            jdbcTemplate.setDataSource(getDriverManagerDataSource());
            return jdbcTemplate;
        }
    }
  4. 编写实体类

    package com.myimooc.springdata.jdbctemplate.domain;
    /**
     * Student实体类
     */
    @Data
    public class Student {
        /** 主键ID */
        private Integer id;
        /** 姓名 */
        private String name;
        /** 年龄 */
        private int age;
    }
  5. DAO接口

    package com.myimooc.springdata.jdbctemplate.dao;
    import com.myimooc.springdata.jdbctemplate.domain.Student;
    import java.util.List;
    /**
     * StudentDAO访问接口
     */
    public interface StudentDao {
        /**
         * 获取所有学生
         * @return 所有学生
         */
        List<Student> listStudent();
        /**
         * 添加一个学生
         * @param student 待添加的学生
         */
        void saveStudent(Student student);
    }
  6. DAO实现

    package com.myimooc.springdata.jdbctemplate.dao.impl;
    import com.myimooc.springdata.jdbctemplate.dao.StudentDao;
    import com.myimooc.springdata.jdbctemplate.domain.Student;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.jdbc.core.JdbcTemplate;
    import org.springframework.stereotype.Repository;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Map;
    /**
     * StudentDAO访问接口实现类:通过 JdbcTemplate 的方式操作
     */
    @Repository
    public class StudentDaoImpl implements StudentDao {
        @Autowired
        private JdbcTemplate jdbcTemplate;
    
        public List<Student> listStudent() {
            List<Student> studentList = new ArrayList<Student>();
            String sql = "select id, name, age from student";
            List<Map<String,Object>>  mapList = jdbcTemplate.queryForList(sql);
            for (Map<String,Object> mapTemp : mapList) {
                Integer id = Integer.parseInt(mapTemp.get("id").toString());
                String name = mapTemp.get("name").toString();
                Integer age = Integer.parseInt(mapTemp.get("age").toString());
                Student student = new Student();
                student.setId(id);
                student.setName(name);
                student.setAge(age);
                studentList.add(student);
            }
            return studentList;
        }
    
        public void saveStudent(Student student) {
            String sql = "insert into student(name, age) value(?,?)";
            jdbcTemplate.update(sql,student.getName(),student.getAge());
        }
    }
  7. 单元测试类

    package com.myimooc.springdata.jdbctemplate;
    import com.myimooc.springdata.jdbctemplate.config.SpringConfig;
    import com.myimooc.springdata.jdbctemplate.dao.StudentDao;
    import com.myimooc.springdata.jdbctemplate.domain.Student;
    import org.junit.After;
    import org.junit.Assert;
    import org.junit.Before;
    import org.junit.Test;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    import org.springframework.jdbc.core.JdbcTemplate;
    import org.springframework.jdbc.datasource.DriverManagerDataSource;
    import javax.sql.DataSource;
    import java.util.List;
    /**
     *  使用 JdbcTemplate 实现 StudentDao 单元测试类
     */
    public class StudentDaoTest {
        private ApplicationContext ctx = null;
        private StudentDao studentDao;
    
        @Before
        public void init(){
            ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
            studentDao = ctx.getBean(StudentDao.class);
        }
        @After
        public void destroy(){
            ctx = null;
        }
    
        @Test
        public void listStudentTest(){
            List<Student> studentList = studentDao.listStudent();
            for (Student student : studentList){
                System.out.println(student.toString());
            }
        }
        @Test
        public void saveTest(){
            Student student = new Student("test-spring-jdbcTemplate", 25);
            studentDao.saveStudent(student);
        }
    }

2-6 弊端分析

  • DAO里面代码量太多
  • DAO的实现有很多重复代码
  • 开发分页和其它功能,需要重新进行封装

第3章 Spring Data快速入门

完成该框架的开发环境搭建及单元测试,本课我们将使用IDEA开发并使用Maven构建项目;

3-1 开发环境搭建

Spring Data JPA快速起步

  1. 开发环境搭建
  2. Spring Data JPA HelloWorld开发
  • 添加maven依赖:

    <!--spring data jpa-->
    <dependency>
        <groupId>org.springframework.data</groupId>
        <artifactId>spring-data-jpa</artifactId>
        <version>1.8.0.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-entitymanager</artifactId>
        <version>4.3.6.Final</version>
    </dependency>
  • DataSource & JdbcTemplate注入

    Spring配置文件

    <!-- beans-new.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/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.3.xsd
            http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
        <!-- Spring扫描 -->
        <context:component-scan base-package="com.imooc"/>
    </beans>
    1. 配置数据源

      <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
          <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
          <property name="username" value="root"/>
          <property name="password" value="root"/>
          <property name="url" value="jdbc:mysql:///spring_data"/>
      </bean>
    2. 配置EntityManagerFactory

      <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
          <property name="dataSource" ref="dataSource"/>
          <property name="jpaVendorAdapter">
              <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/>
          </property>
          <property name="packagesToScan" value="com.imooc"/>
          <property name="jpaProperties">
              <props>
                  <prop key="hibernate.ejb.naming_strategy">org.hibernate.cfg.ImprovedNamingStrategy</prop>
                  <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</prop>
                  <prop key="hibernate.show_sql">true</prop>
                  <prop key="hibernate.format_sql">true</prop>
                  <prop key="hibernate.hbm2ddl.auto">update</prop>
              </props>
          </property>
      </bean>
    3. 配置事务管理器

      <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
          <property name="entityManagerFactory" ref="entityManagerFactory"/>
      </bean>
    4. 配置支持注解的事务

      <tx:annotation-driven transaction-manager="transactionManager"/>
    5. 配置spring data

      <jpa:repositories base-package="com.imooc" entity-manager-factory-ref="entityManagerFactory"/>
  • 创建实体类

    /**
     * 雇员:  先开发实体类===>自动生成数据表
     */
    @Data
    @Entity
    public class Employee {
        @Id
        @GeneratedValue
        private Integer id;
        @Column(length = 20, nullable = false)
        private String name;
        private Integer age;
    }
  • 单元测试

    public class SpringDataTest {
        private ApplicationContext ctx = null;
    
        @Before
        public void setup(){
            System.out.println("setup");
            ctx = new ClassPathXmlApplicationContext("beans-new.xml");
        }
        @After
        public void tearDown(){
            System.out.println("tearDown");
            ctx = null;
        }
    
        @Test
        public void testEntityManagerFactory(){
            // 运行单元测试,检查是否有生成一张数据表。有则成功,无则失败。
        }
    }

    END

代码演示:

  1. 创建DB配置文件

    jdbc.url = jdbc:mysql:///springdata
    jdbc.username = root
    jdbc.password = root
    jdbc.driverClass = com.mysql.jdbc.Driver
  2. 创建配置文件类

    package com.myimooc.springdata.jpa.config;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.annotation.PropertySource;
    import org.springframework.stereotype.Component;
    @Data
    @Component
    @PropertySource(value="classpath:db.properties")
    public class PropertiesConfig {
        @Value("${jdbc.driverClass}")
        private String jdbcDriverClass;
        @Value("${jdbc.url}")
        private String jdbcUrl;
        @Value("${jdbc.username}")
        private String jdbcUser;
        @Value("${jdbc.password}")
        private String jdbcPassword;
    }
  3. 配置TransactionManager、EntityManagerFactory和Spring自动扫描注入

    package com.myimooc.springdata.jpa.config;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
    import org.springframework.jdbc.datasource.DriverManagerDataSource;
    import org.springframework.orm.jpa.JpaTransactionManager;
    import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
    import org.springframework.orm.jpa.vendor.Database;
    import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
    import org.springframework.transaction.PlatformTransactionManager;
    import org.springframework.transaction.annotation.EnableTransactionManagement;
    import java.util.Properties;
    /**
     * Spring配置类
     */
    // 声明为配置类
    @Configuration
    // 启用事务管理
    @EnableTransactionManagement
    // 启用自动扫描继承 JpaRepository 接口的类。
    // 注意,此注解需要配置 entityManagerFactory 和 transactionManager
    // 方式一:定义获取Bean方法名为 entityManagerFactory 和 transactionManager
    // 方式二:配置 @EnableJpaRepositories注解的 entityManagerFactoryRef 属性 为自定义获取Bean的方法名。
    @EnableJpaRepositories(basePackages = "com.myimooc.springdata.jpa")
    // 启用自动扫描 @Component 注解的Bean
    @ComponentScan(basePackages = "com.myimooc.springdata.jpa")
    public class SpringConfig {
        @Autowired
        private PropertiesConfig propertiesConfig;
        /**
         * 配置数据源
         * @return
         */
        @Bean
        public DriverManagerDataSource dataSource(){
            DriverManagerDataSource driverManagerDataSource = new DriverManagerDataSource();
            driverManagerDataSource.setDriverClassName(propertiesConfig.getJdbcDriverClass());
            driverManagerDataSource.setUrl(propertiesConfig.getJdbcUrl());
            driverManagerDataSource.setUsername(propertiesConfig.getJdbcUser());
            driverManagerDataSource.setPassword(propertiesConfig.getJdbcPassword());
            return driverManagerDataSource;
        }
        /**
         * 配置事务管理器 JpaTransactionManager
         * @return
         */
        @Bean(name="transactionManager")
        public PlatformTransactionManager transactionManager(){
            JpaTransactionManager transactionManager = new JpaTransactionManager();
            transactionManager.setDataSource(this.dataSource());
            transactionManager.setEntityManagerFactory(this.entityManagerFactory().getObject());
            return transactionManager;
    //        return new DataSourceTransactionManager(this.dataSource());
    //        return new JpaTransactionManager(this.entityManagerFactory().getObject());
        }
        /**
         * 配置JPA的 EntityManagerFactory
         * @return
         */
        @Bean
        public LocalContainerEntityManagerFactoryBean entityManagerFactory(){
            LocalContainerEntityManagerFactoryBean entityManagerFactory = new LocalContainerEntityManagerFactoryBean();
            entityManagerFactory.setDataSource(dataSource());
            HibernateJpaVendorAdapter jpaVendorAdapter = new HibernateJpaVendorAdapter();
            jpaVendorAdapter.setGenerateDdl(true);
            jpaVendorAdapter.setDatabase(Database.MYSQL);
            entityManagerFactory.setJpaVendorAdapter(jpaVendorAdapter);
            entityManagerFactory.setPackagesToScan("com.myimooc.springdata.jpa");
            Properties jpaProperties = new Properties();
    //        jpaProperties.setProperty("hibernate.ejb.naming_strategy","org.hibernate.cfg.ImprovedNamingStrategy");
            jpaProperties.setProperty("hibernate.dialect","org.hibernate.dialect.MySQL5InnoDBDialect");
            jpaProperties.setProperty("hibernate.show_sql","true");
            jpaProperties.setProperty("hibernate.format_sql","true");
            jpaProperties.setProperty("hibernate.hbm2ddl.auto","update");
    
            entityManagerFactory.setJpaProperties(jpaProperties);
            return entityManagerFactory;
        }
    }
  4. 编写实体类:Employee

    package com.myimooc.springdata.jpa.domain;
    import javax.persistence.*;
    /**
     * 雇员:先开发实体类,然后自动生成实体表
     */
    @Data
    @Entity
    @Table(name = "test_employee")
    public class Employee {
        @Id
        @GeneratedValue
        private Integer id;
        @Column(length = 20)
        private String name;
        private Integer age;
    }

3-2 起步程序开发

  1. 编写EmployeeRepository接口

    package com.myimooc.springdata.jpa.repository;
    import com.myimooc.springdata.jpa.domain.Employee;
    import org.springframework.data.repository.Repository;
    /**
     * 使用 Repository 接口
     */
    // 方式二:使用 @RepositoryDefinition 注解
    //  @RepositoryDefinition(domainClass = Employee.class,idClass = Integer.class)
    public interface EmployeeRepository extends Repository<Employee,Integer> { //方式一:继承 Repository 接口
        /**
         * 获取雇员对象通过名称
         */
        Employee findByName(String name);
    }
  2. 编写单元测试类:EmployeeRepositoryTest

    package com.myimooc.springdata.jpa.repository;
    import com.myimooc.springdata.jpa.config.SpringConfig;
    import com.myimooc.springdata.jpa.domain.Employee;
    import com.myimooc.springdata.jpa.repository.EmployeeRepository;
    import com.myimooc.springdata.jpa.service.EmployeeService;
    import org.junit.After;
    import org.junit.Assert;
    import org.junit.Before;
    import org.junit.Test;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
    import java.util.ArrayList;
    import java.util.List;
    /**
     * EmployeeRepository单元测试类
     */
    public class EmployeeRepositoryTest {
        private ApplicationContext ctx = null;
        private EmployeeRepository employeeRepository = null;
    
        @Before
        public void init(){
            ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
            employeeRepository = ctx.getBean(EmployeeRepository.class);
        }
        @After
        public void destroy(){
            ctx = null;
        }
    
        @Test
        public void findByNameTest(){
            // org.springframework.data.ipa.repository.support.SimpleJpaRepository@566
            System.out.println(employeeRepository);
            Employee employee = employeeRepository.findByName("cc");
            System.out.println(employee.toString());
        }
    }

Repository

Repository:Spring Data核心类
RepositoryDefinition:使用该注解进行配置
Repository Query Specification:查询时,方法命名不能乱写
Query Annotation:使用该注解,可以实现原生SQL查询
Update/Delete/Transaction:更新、删除操作,支持事务

Repository Hierarchy:层次结构

CrudRepository:内置了新增、更新、删除、查询方法
PagingAndSortingRespository:分页和排序
JpaRepository:
JpaSpecificationExcutor

第4章 Spring Data JPA进阶

使用Spring Data JPA完成CRUD操作

4-1 关于Repository接口

Repository接口详解

Repository接口是Spring Data的核心接口,不提供任何方法
public interface Repository<T, ID extends Serializable>{}

@RepositoryDefinition注解的使用
@RepositoryDefinition(domainClass = Employee.class, idClass = Integer.class)

Repository类的定义:

  • Repository是一个空接口,标记接口。没有包含方法声明的接口

  • 如果我们定义的接口EmployeeRepository extends Repository,会被Spring管理。
    如果我们自己的接口没有extends Repository,运行时会报错,没有这个Bean:

    org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.imooc.repository.EmployeeRepository' available
  • 添加RepositoryDefinition注解能到达到不用extends Repository的功能

4-2 Repository子接口详解

Repository子接口详解

CrudRepository:继承Repository,实现了CRUD相关的方法
PagingAndSortingRepository:继承CrudRepository,实现了分页排序相关的方法
JpaRepository:继承PagingAndSortingRepositor,实现JPA规范相关的方法

4-3 查询方法定义规则和使用

Repository中查询方法定义规则和使用

了解Spring Data中查询方法名称的定义规则
使用Spring Data完成复杂查询方法名称的命名

查询方法定义规则

Keyword Sample JPQL snippet
And findByLastnameAndFirstname where x.lastname=?1 and x.firstname=?2
Or findByLastnameOrFirstname where x.lastname=?1 or x.firstname=?2
Between findByStartDateBetween where x.startDate between 1? and ?2
LessThan findByAgeLessThan where x.age<?1
GreaterThan findByAgeGreaterThan where x.age>?1
After findByStartDateAfter where x.startDate>?1
Before findByStartDateBefore where x.startDate<?1
IsNull findByAgelsNull where x.age is null
IsNotNul, 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 findByAgeln(Collection ages) where x.age in ?1
Notln findByAgeNotin(Collection age) where x.age not in ?1
TRUE findByActiveTrue where x.active=true
FALSE findByActiveFalse where x.active=false

代码演示:

-- 测试数据
insert into employee (name, age) values ("test1",20);
insert into employee (name, age) values ("test2",21);
insert into employee (name, age) values ("test3",22);
insert into employee (name, age) values ("test4",20);
insert into employee (name, age) values ("test5",21);
insert into employee (name, age) values ("test6",22);
insert into employee (name, age) values ("test16",22);
  1. 在EmployeeRepository接口编写以下代码

    // --- 使用JPA规范查询 ---
    // where name like ?% and age < ?
    List<Employee> findByNameStartingWithAndAgeLessThan(String name,Integer age);
    
    // where name like %? and age < ?
    List<Employee> findByNameEndingWithAndAgeLessThan(String name,Integer age);
    
    // where name in (?, ?...) or age < ?
    List<Employee> findByNameInOrAgeLessThan(List<String> name,Integer age);
    
    // where name in (?, ?...) and age < ?
    List<Employee> findByNameInAndAgeLessThan(List<String> name,Integer age);
  2. 在EmployeeRepositoryTest单元测试类进行测试

    @Test
    public void findByNameStartingWithAndAgeLessThanTest(){
        List<Employee> employees = employeeRepository.findByNameStartingWithAndAgeLessThan("test",22);
    
        for (Employee employee : employees) {
            System.out.println(employee.toString());
        }
    }
    
    @Test
    public void findByNameEndingWithAndAgeLessThanTest(){
        List<Employee> employees = employeeRepository.findByNameEndingWithAndAgeLessThan("6",23);
    
        for (Employee employee : employees) {
            System.out.println(employee.toString());
        }
    }
    
    @Test
    public void findByNameInOrAgeLessThanTest(){
        List<String> names = new ArrayList<String>();
        names.add("test1");
        names.add("test2");
        names.add("test3");
        List<Employee> employees = employeeRepository.findByNameInOrAgeLessThan(names,22);
    
        for (Employee employee : employees) {
            System.out.println(employee.toString());
        }
    }
    
    @Test
    public void findByNameInAndAgeLessThanTest(){
        List<String> names = new ArrayList<String>();
        names.add("test1");
        names.add("test2");
        names.add("test3");
        List<Employee> employees = employeeRepository.findByNameInAndAgeLessThan(names,22);
    
        for (Employee employee : employees) {
            System.out.println(employee.toString());
        }
    }

对于按照方法命名规则来使用的话,有弊端:

1)方法名比较长:约定大于配置
2)对于一些复杂的查询,是很难实现。

使用@Query注解来解决以上弊端。

4-4 Query注解使用

Query注解使用

  • 在Respository方法中使用,不需要遵循查询方法命令规则
  • 只需要将@Query定义在Respository中的方法之上即可
  • 命名参数及索引参数的使用
  • 本地查询
  1. 在EmployeeRepository接口编写以下代码

    // --- 使用@Query注解查询 ---
    // 自定义查询SQL。Employee为类名,不是表名
    @Query("select o from Employee o where id=(select max(id) from Employee t1)")
    Employee getEmployeeByMaxId();
    
    // 使用占位符进行参数绑定
    @Query("select o from Employee o where o.name=?1 and o.age=?2")
    List<Employee> listEmployeeByNameAndAge(String name, Integer age);
    
    // 使用命名参数进行参数绑定
    @Query("select o from Employee o where o.name=:name and o.age=:age")
    List<Employee> listEmployeeByNameAndAge2(@Param("name") String name, @Param("age")Integer age);
    
    // 自定义查询SQL,like,占位符进行参数绑定
    @Query("select o from Employee o where o.name like %?1%")
    List<Employee> listEmployeeByLikeName(String name);
    
    // 自定义查询SQL,like,命名参数进行参数绑定
    @Query("select o from Employee o where o.name like %:name%")
    List<Employee> listEmployeeByLikeName2(@Param("name") String name);
    
    // 使用原生态SQL查询。employee为表名
    @Query(nativeQuery = true,value = "select count(1) from employee")
    long getCount();
  2. 在EmployeeRepositoryTest单元测试类进行测试

    //  使用 @Query 注解查询
    @Test
    public void getEmployeeByMaxIdTest(){
        Employee employee = employeeRepository.getEmployeeByMaxId();
        System.out.println(employee);
    }
    
    @Test
    public void listEmployeeByNameAndAgeTest(){
        List<Employee> employees = employeeRepository.listEmployeeByNameAndAge("zhangsan",20);
        for (Employee employee : employees) {
            System.out.println(employee);
        }
    }
    
    @Test
    public void listEmployeeByNameAndAge2Test(){
        List<Employee> employees = employeeRepository.listEmployeeByNameAndAge2("zhangsan",20);
        for (Employee employee : employees) {
            System.out.println(employee);
        }
    }
    
    @Test
    public void listEmployeeByLikeNameTest(){
        List<Employee> employees = employeeRepository.listEmployeeByLikeName("test1");
        for (Employee employee : employees) {
            System.out.println(employee);
        }
    }
    
    @Test
    public void listEmployeeByLikeName2Test(){
        List<Employee> employees = employeeRepository.listEmployeeByLikeName2("test");
        for (Employee employee : employees) {
            System.out.println(employee);
        }
    }
    
    @Test
    public void getCountTest(){
        long count = employeeRepository.getCount();
        System.out.println(count);
    }

4-5 更新操作整合事务使用

更新及删除操作整合事务的使用

  • @Modifying注解使用
  • @Modifying结合@Query注解执行更新操作
  • @Transaction在Spring Data中的使用
  1. 基于javaconfig在SpringConfig类进行事务配置

    package com.myimooc.springdata.jpa.config;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
    import org.springframework.jdbc.datasource.DriverManagerDataSource;
    import org.springframework.orm.jpa.JpaTransactionManager;
    import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
    import org.springframework.orm.jpa.vendor.Database;
    import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
    import org.springframework.transaction.PlatformTransactionManager;
    import org.springframework.transaction.annotation.EnableTransactionManagement;
    import java.util.Properties;
    /**
     * Spring配置类
     */
    // 声明为配置类
    @Configuration
    // 启用事务管理
    @EnableTransactionManagement
    // 启用自动扫描继承 JpaRepository 接口的类。
    // 注意,此注解需要配置 entityManagerFactory 和 transactionManager
    // 方式一:定义获取Bean方法名为 entityManagerFactory 和 transactionManager
    // 方式二:配置 @EnableJpaRepositories注解的 entityManagerFactoryRef 属性 为自定义获取Bean的方法名。
    @EnableJpaRepositories(basePackages = "com.myimooc.springdata.jpa")
    // 启用自动扫描 @Component 注解的Bean
    @ComponentScan(basePackages = "com.myimooc.springdata.jpa")
    public class SpringConfig{
    
        @Autowired
        private PropertiesConfig propertiesConfig;
    
        // 配置数据源
        @Bean
        public DriverManagerDataSource dataSource(){
            DriverManagerDataSource driverManagerDataSource = new DriverManagerDataSource();
            driverManagerDataSource.setDriverClassName(propertiesConfig.getJdbcDriverClass());
            driverManagerDataSource.setUrl(propertiesConfig.getJdbcUrl());
            driverManagerDataSource.setUsername(propertiesConfig.getJdbcUser());
            driverManagerDataSource.setPassword(propertiesConfig.getJdbcPassword());
            return driverManagerDataSource;
        }
    
        // 配置事务管理器 JpaTransactionManager
        @Bean(name="transactionManager")
        public PlatformTransactionManager transactionManager(){
            JpaTransactionManager transactionManager = new JpaTransactionManager();
            transactionManager.setDataSource(this.dataSource());
            transactionManager.setEntityManagerFactory(this.entityManagerFactory().getObject());
            return transactionManager;
    //        return new DataSourceTransactionManager(this.dataSource());
    //        return new JpaTransactionManager(this.entityManagerFactory().getObject());
        }
    
        // 配置JPA的 EntityManagerFactory
        @Bean
        public LocalContainerEntityManagerFactoryBean entityManagerFactory(){
            LocalContainerEntityManagerFactoryBean entityManagerFactory = new LocalContainerEntityManagerFactoryBean();
            entityManagerFactory.setDataSource(dataSource());
    
            HibernateJpaVendorAdapter jpaVendorAdapter = new HibernateJpaVendorAdapter();
            jpaVendorAdapter.setGenerateDdl(true);
            jpaVendorAdapter.setDatabase(Database.MYSQL);
            entityManagerFactory.setJpaVendorAdapter(jpaVendorAdapter);
            entityManagerFactory.setPackagesToScan("com.myimooc.springdata.jpa");
    
            Properties jpaProperties = new Properties();
    //        jpaProperties.setProperty("hibernate.ejb.naming_strategy","org.hibernate.cfg.ImprovedNamingStrategy");
            jpaProperties.setProperty("hibernate.dialect","org.hibernate.dialect.MySQL5InnoDBDialect");
            jpaProperties.setProperty("hibernate.show_sql","true");
            jpaProperties.setProperty("hibernate.format_sql","true");
            jpaProperties.setProperty("hibernate.hbm2ddl.auto","update");
    
            entityManagerFactory.setJpaProperties(jpaProperties);
            return entityManagerFactory;
        }
    }
  2. 在EmployeeRepository接口编写以下代码

    // 更新数据,需添加@Modifying、@Transactional
    @Modifying
    @Query("update Employee o set o.age = :age where o.id = :id")
    void updateAgeById(@Param("id")Integer id,@Param("age")Integer age);
  3. 定义Service层,实际开发中,需要定义接口,这里为了演示方便,直接使用类。

    package com.myimooc.springdata.jpa.service;
    import com.myimooc.springdata.jpa.domain.Employee;
    import com.myimooc.springdata.jpa.repository.EmployeeCrudRepository;
    import com.myimooc.springdata.jpa.repository.EmployeeRepository;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.annotation.Transactional;
    import java.util.List;
    
    @Service
    public class EmployeeService {
        @Autowired
        private EmployeeRepository employeeRepository;
        @Autowired
        private EmployeeCrudRepository employeeCrudRepository;
    
        @Transactional
        public void updateAgeById(Integer id, Integer age){
            this.employeeRepository.updateAgeById(id,age);
        };
        @Transactional
        public void save(List<Employee> employees){
            this.employeeCrudRepository.save(employees);
        }
    }
  4. 编写EmployeeService单元测试类

    package com.myimooc.springdata.jpa.service;
    import com.myimooc.springdata.jpa.config.SpringConfig;
    import com.myimooc.springdata.jpa.repository.EmployeeRepository;
    import org.junit.After;
    import org.junit.Assert;
    import org.junit.Before;
    import org.junit.Test;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
    import org.springframework.transaction.PlatformTransactionManager;
    /**
     * EmployeeService单元测试类
     */
    public class EmployeeServiceTest {
        private ApplicationContext ctx = null;
        private EmployeeService employeeService = null;
    
        @Before
        public void init(){
            ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
            employeeService = ctx.getBean(EmployeeService.class);
        }
        @After
        public void destroy(){
            ctx = null;
        }
    
        @Test
        public void transactionManagerTest(){
            PlatformTransactionManager transactionManager = (PlatformTransactionManager)ctx.getBean(PlatformTransactionManager.class);
            Assert.assertNotNull(transactionManager);
        }
        // 更新操作
        @Test
        public void updateAgeByIdTest(){
            employeeService.updateAgeById(1,55);
        }
    }

事务在Spring data中的使用:

  1. 事务一般是在Service层
  2. @Query、@Modifying、@Transaction的综合使用

第5章 Spring Data JPA高级

详解Spring Data JPA的Repository核心接口的各种子类的使用

5-1 CrudRepository接口使用详解

CrudRepository接口使用详解

save(entity):保存一个实体
save(entities):保存多个实体
findOne(id):找到一个对象
exists(id):根据ID判断对象是否存在
findAll():找到所有实体对象
delete(id):根据ID删除实体对象
delete(entity):根据实体对象删除实体对象
delete(entities):删除多个实体对象
deleteAll():删除所有实体对象

  1. 编写EmployeeCrudRepository接口

    package com.myimooc.springdata.jpa.repository;
    import com.myimooc.springdata.jpa.domain.Employee;
    import org.springframework.data.repository.CrudRepository;
    /**
     * 使用 CrudRepository 接口
     */
    public interface EmployeeCrudRepository extends CrudRepository<Employee,Integer>{
    }
  2. 编写EmployeeCrudRepositoryTest单元测试类

    package com.myimooc.springdata.jpa.repository;
    import com.myimooc.springdata.jpa.config.SpringConfig;
    import com.myimooc.springdata.jpa.domain.Employee;
    import org.junit.After;
    import org.junit.Before;
    import org.junit.Test;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    import java.util.ArrayList;
    import java.util.List;
    /**
     * EmployeeRepository单元测试类
     */
    public class EmployeeCrudRepositoryTest {
        private ApplicationContext ctx = null;
        private EmployeeService employeeService = null;
    
        @Before
        public void init(){
            ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
            employeeCrudRepository = ctx.getBean(EmployeeService.class);
        }
        @After
        public void destroy(){
            ctx = null;
        }
    
        @Test
        public void saveTest(){
            List<Employee> employees = new ArrayList<Employee>();
            Employee employee = null;
            for(int i=0;i<100;i++){
                employee = new Employee();
                employee.setName("test"+i);
                employee.setAge(100 - i);
                employees.add(employee);
            }
            employeeService.save(employees);
        }
    }

5-2 PagingAndSortingRespsitory接口使用详解 (14:48)

PagingAndSortingRespository接口使用详解

  • 该接口包含分页和排序的功能
  • 带排序的查询:findAll(Sort sort)
  • 带排序的分页查询:findAll(Pageable pageable)
  1. 编写EmployeePagingAndSortingRepository接口

    package com.myimooc.springdata.jpa.repository;
    import com.myimooc.springdata.jpa.domain.Employee;
    import org.springframework.data.repository.PagingAndSortingRepository;
    /**
     * 使用 PagingAndSortingRepository 实现分页和排序功能
     */
    public interface EmployeePagingAndSortingRepository extends PagingAndSortingRepository<Employee,Integer> {
    }
  2. 编写EmployeePagingAndSortingRepositoryTest单元测试类

    package com.myimooc.springdata.jpa.repository;
    import com.myimooc.springdata.jpa.config.SpringConfig;
    import com.myimooc.springdata.jpa.domain.Employee;
    import com.myimooc.springdata.jpa.repository.EmployeePagingAndSortingRepository;
    import com.myimooc.springdata.jpa.service.EmployeeService;
    import org.junit.After;
    import org.junit.Assert;
    import org.junit.Before;
    import org.junit.Test;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    import org.springframework.data.domain.Page;
    import org.springframework.data.domain.PageRequest;
    import org.springframework.data.domain.Pageable;
    import org.springframework.data.domain.Sort;
    import org.springframework.data.repository.PagingAndSortingRepository;
    import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
    import java.util.ArrayList;
    import java.util.List;
    /**
     * PagingAndSortingRepository 单元测试类
     */
    public class EmployeePagingAndSortingRepositoryTest {
        private ApplicationContext ctx = null;
        private EmployeePagingAndSortingRepository employeePagingAndSortingRepository = null;
    
        @Before
        public void init(){
            ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
            employeePagingAndSortingRepository = ctx.getBean(EmployeePagingAndSortingRepository.class);
        }
        @After
        public void destroy(){
            ctx = null;
        }
    
        /**
         * 分页功能测试
         */
        @Test
        public void pageTest(){
            // page: index是从0开始的,不是从1开始的
            Pageable pageable = new PageRequest(0,9);// page,size
            Page<Employee> employeePage = employeePagingAndSortingRepository.findAll(pageable);
            System.out.println("查询的总页数:"+employeePage.getTotalPages());
            System.out.println("查询的总记录数:"+employeePage.getTotalElements());
            System.out.println("查询的当前第几页:"+(employeePage.getNumber() + 1));
            System.out.println("查询的当前页面的集合:"+employeePage.getContent());
            System.out.println("查询的当前页面的记录数:"+employeePage.getNumberOfElements());
    
        }
        /**
         * 分页和排序功能测试
         */
        @Test
        public void pageAndSort(){
            Sort.Order order = new Sort.Order(Sort.Direction.DESC,"id");// 升/降序,规则字段
            Sort sort = new Sort(order);
            // page: index是从0开始的,不是从1开始的
            Pageable pageable = new PageRequest(0,5,sort);// 先排序,再分页
            Page<Employee> employeePage = employeePagingAndSortingRepository.findAll(pageable);
            System.out.println("查询的总页数:"+employeePage.getTotalPages());
            System.out.println("查询的总记录数:"+employeePage.getTotalElements());
            System.out.println("查询的当前第几页:"+(employeePage.getNumber() + 1));
            System.out.println("查询的当前页面的集合:"+employeePage.getContent());
            System.out.println("查询的当前页面的记录数:"+employeePage.getNumberOfElements());
        }
    
    }

5-3 JpaRepository接口使用详解

JpaRepository接口使用详解

finaAll:查询所有记录
findAll(Sort sort):查询所有记录并排序
save(entities):保存多个实体对象
fiush:
deleteInBatch(entities):一个批次里面删除那些实体

  1. 编写EmployeeJpaRepository接口

    package com.myimooc.springdata.jpa.repository;
    import com.myimooc.springdata.jpa.domain.Employee;
    import org.springframework.data.jpa.repository.JpaRepository;
    import org.springframework.data.repository.PagingAndSortingRepository;
    /**
     * 使用 JpaRepository 接口
     */
    public interface EmployeeJpaRepository extends JpaRepository<Employee,Integer> {
    }
  2. 编写EmployeeJpaRepositoryTest单元测试类

    package com.myimooc.springdata.jpa.repository;
    import com.myimooc.springdata.jpa.config.SpringConfig;
    import com.myimooc.springdata.jpa.domain.Employee;
    import com.myimooc.springdata.jpa.repository.EmployeeJpaRepository;
    import org.junit.After;
    import org.junit.Before;
    import org.junit.Test;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    import org.springframework.data.domain.Page;
    import org.springframework.data.domain.PageRequest;
    import org.springframework.data.domain.Pageable;
    import org.springframework.data.domain.Sort;
    import org.springframework.data.jpa.repository.JpaRepository;
    import org.springframework.data.repository.PagingAndSortingRepository;
    /**
     * EmployeeJpaRepository 单元测试类
     */
    public class EmployeeJpaRepositoryTest {
        private ApplicationContext ctx = null;
        private EmployeeJpaRepository employeeJpaRepository = null;
    
        @Before
        public void init(){
            ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
            employeeJpaRepository = ctx.getBean(EmployeeJpaRepository.class);
        }
        @After
        public void destroy(){
            ctx = null;
        }
    
        @Test
        public void findTest(){
            Employee employee = employeeJpaRepository.findOne(99);
            System.out.println("employee" + employee);
            System.out.println("employee(10)" + employeeJpaRepository.exists(10));// true
            System.out.println("employee(102)" + employeeJpaRepository.exists(102));// false
        }
    }

5-4 JpaSpecificationExecutor接口使用详解

JpaSpecificationExecutor接口使用详解(JPA规范执行者)

Specification封装了JPA Criteria(JAP标准)查询条件

Repository接口体系无法携带一些查询条件

代码演示:

  1. 编写EmployeeJpaSpecificationExecutor接口

    package com.myimooc.springdata.jpa.repository;
    import com.myimooc.springdata.jpa.domain.Employee;
    import org.springframework.data.jpa.repository.JpaRepository;
    import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
    /**
     * 使用 JpaSpecificationExecutor 接口
     */
    public interface EmployeeJpaSpecificationExecutor extends JpaRepository<Employee,Integer> , JpaSpecificationExecutor<Employee>{
    }
  2. 编写EmployeeJpaSpecificationExecutorTest单元测试类

    package com.myimooc.springdata.jpa.repository;
    import com.myimooc.springdata.jpa.config.SpringConfig;
    import com.myimooc.springdata.jpa.domain.Employee;
    import org.junit.After;
    import org.junit.Before;
    import org.junit.Test;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    import org.springframework.data.domain.Page;
    import org.springframework.data.domain.PageRequest;
    import org.springframework.data.domain.Pageable;
    import org.springframework.data.domain.Sort;
    import org.springframework.data.jpa.domain.Specification;
    import javax.persistence.criteria.*;
    /**
     * EmployeeJpaSpecificationExecutor 单元测试类
     */
    public class EmployeeJpaSpecificationExecutorTest {
        private ApplicationContext ctx = null;
        private EmployeeJpaSpecificationExecutor employeeJpaSpecificationExecutor = null;
    
        @Before
        public void init(){
            ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
            employeeJpaSpecificationExecutor = ctx.getBean(EmployeeJpaSpecificationExecutor.class);
        }
        @After
        public void destroy(){
            ctx = null;
        }
    
        /**
         * 1、分页
         * 2、排序
         * 3、查询条件:age > 50
         */
        @Test
        public void queryTest(){
            Sort.Order order = new Sort.Order(Sort.Direction.DESC,"id");
            Sort sort = new Sort(order);
            // page: index是从0开始的,不是从1开始的
            Pageable pageable = new PageRequest(0,5,sort);
            /**
             * root : 就是我们要查询的类型 (Employee)
             * query : 添加查询条件
             * cb : 构建 Predicate
             */
            Specification<Employee> specification = new Specification<Employee>() {
                // 查询条件
                public Predicate toPredicate(Root<Employee> root,
                                             CriteriaQuery<?> query,
                                             CriteriaBuilder cb) 
                {
                    // root (employee (age))
                    Path path = root.get("age");
                    return cb.gt(path,50);
                }
            };
            Page<Employee> employeePage = employeeJpaSpecificationExecutor.findAll(specification,pageable);
            System.out.println("查询的总页数:" + employeePage.getTotalPages());
            System.out.println("查询的总记录数:" + employeePage.getTotalElements());
            System.out.println("查询的当前第几页:" + (employeePage.getNumber() + 1));
            System.out.println("查询的当前页面的集合:" + employeePage.getContent());
            System.out.println("查询的当前页面的记录数:" + employeePage.getNumberOfElements());
        }
    }

第6章 课程总结

课程总结

6-1 课程总结

Spring Data概览
传统方式访问数据库
Spring Data快速起步
Spring Data JPA进阶
Spring Data JAP高级


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 tuyrk@qq.com

文章标题:821-轻松愉快之玩转SpringData

文章字数:8.1k

本文作者:神秘的小岛岛

发布时间:2019-06-15, 23:14:34

最后更新:2019-11-05, 19:19:31

原始链接:https://www.tuyrk.cn/imooc/821-SpringData/

版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。

目录
×

喜欢就点赞,疼爱就打赏