阅读 28

01.【Spring Data专题】 - 初相识

Spring Data

1.概述(了解)

Spring Data JPA旨在通过减少实际需要的工作量来显着改善数据访问层的实现。作为开发人员,您编写存储库接口,包括自定义查找器方法,Spring将自动提供实现。

特性概述

  • 基于Spring和JPA构建存储库的复杂支持
  • 支持Querydsl谓词,从而支持类型安全的JPA查询
  • 透明审核域类
  • 分页支持,动态查询执行,集成自定义数据访问代码的能力
  • @Query在引导时验证注释查询
  • 支持基于XML的实体映射
  • 通过引入基于JavaConfig的存储库配置@EnableJpaRepositories

Spring Data : Spring 的一个子项目。用于简化数据库访问,支持NoSQL 和 关系数据存储。其 主要目标是使数据库的访问变得方便快捷。

SpringData 项目所支持 NoSQL 存储:

  • MongoDB (文档数据库)

  • Neo4j(图形数据库)

  • Redis(键/值存储)

  • Hbase(列族数据库)

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

  • JDBC

  • JPA

核心思想:JPA Spring Data : 致力于减少数据访问层 (DAO) 的开发量,开发者唯一要做的,就只是声明持久层的接口,其他都交给 Spring Data JPA 来帮你完成。

框架怎么可能代替开发者实现业务逻辑呢?
比如:当有一个 UserDao.findUserById() 这样一个方法声明,大致应该能判断出这是根据给定条件的 ID 查询出满足条件的 User 对象。Spring Data JPA 做的便是规范方法的名字,根据符合规范的名字来确定方法需要实现什么样的逻辑。
复制代码

技术的再怎么进化,多少都需要有人的维护?约定优于配置的思想,简化了我们很多的操作。

2.Spring Data JPA 配置

使用 Spring Data JPA 进行持久层开发需要的四个步骤:

  • 配置 Spring 整合 JPA
  • 在 Spring 配置文件中配置 Spring Data,让 Spring 为声明的接口创建代理对象。配置了<jpa:repositories> 后,Spring 初始化容器时将会扫描 base-package 指定的包目录及其子目录(这步我出现了问题,后面告知解决方式),为继承 Repository 或其子接口的接口创建代理对象,并将代理对象注册为 Spring Bean,业务层便可以通过 Spring 自动封装的特性来直接使用该对象。
  • 声明持久层的接口,该接口继承 Repository 接口,Repository 是一个标记型接口,它不包含任何方法,如必要,Spring Data 可实现 Repository 其他子接口,其中定义了一些常用的增删改查,以及分页相关的方法。
  • 在接口中声明需要的方法。Spring Data 将根据给定的策略(具体策略稍后讲解)来为其生成实现代码。

(1)配置pom.xml文件

<dependencies>
    <!-- Spring Data和Spring相关的下载 -->
    <dependency>
        <groupId>org.springframework.data</groupId>
        <artifactId>spring-data-jpa</artifactId>
        <version>2.2.4.RELEASE</version>
    </dependency>
	<!-- JPA相关的配置 -->
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-entitymanager</artifactId>
        <version>5.4.10.Final</version>
    </dependency>
    <!-- 数据源 -->
    <dependency>
        <groupId>c3p0</groupId>
        <artifactId>c3p0</artifactId>
        <version>0.9.1.2</version>
    </dependency>
	<!-- 驱动包 -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.47</version>
    </dependency>
</dependencies>
复制代码

(2)建立持久化类

package com.os.model;

import javax.persistence.*;
import java.util.Date;

@Entity
@Table(name = "jpa_book")
public class Book {

    private Integer bookId;
    private String bookName;
    private Double price;
    private String author;
    private Date createDate;

    public Book() {
    }

    public Book(String bookName, Double price) {
        this.bookName = bookName;
        this.price = price;
    }
    public Book(String bookName, Double price, String author, Date createDate) {
        this.bookName = bookName;
        this.price = price;
        this.author = author;
        this.createDate = createDate;
    }

    @Id
    @Column(name = "book_id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    public Integer getBookId() {
        return bookId;
    }

    public void setBookId(Integer bookId) {
        this.bookId = bookId;
    }
    @Column(name = "book_name")
    public String getBookName() {
        return bookName;
    }

    public void setBookName(String bookName) {
        this.bookName = bookName;
    }

    public Double getPrice() {
        return price;
    }

    public void setPrice(Double price) {
        this.price = price;
    }

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }
    @Column(name = "create_date")
    public Date getCreateDate() {
        return createDate;
    }

    public void setCreateDate(Date createDate) {
        this.createDate = createDate;
    }

    @Override
    public String toString() {
        return "Book{" +
                "bookId=" + bookId +
                ", bookName='" + bookName + '\'' +
                ", price=" + price +
                ", author='" + author + '\'' +
                ", createDate=" + createDate +
                '}';
    }
}
复制代码

(3)新建持久化接口

package com.os.dao;

import com.os.model.Book;
import org.springframework.data.repository.Repository;

public interface BookDao extends Repository<Book,Integer> {
    Book getByBookName(String bookName);//BookName为Book类中的属性
}
复制代码

(4)配置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" xmlns:p="http://www.springframework.org/schema/p"
       xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jpa="http://www.springframework.org/schema/data/jpa"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.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 http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
    <!-- 这个配置,因为我后面报错误了! -->
    <context:component-scan base-package="com.os.**.dao"></context:component-scan>
    <!-- 配置数据源 -->
    <bean class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close" id="dataSource">
        <property name="driverClass" value="com.mysql.jdbc.Driver"/>
        <property name="jdbcUrl" value="jdbc:mysql://127.0.0.1:3306/yf01_mybatis"/>
        <property name="user" value="root"/>
        <property name="password" value=""/>

        <!-- 配置其他属性 -->
    </bean>

    <!-- 2. 配置 JPA 的 EntityManagerFactory -->
    <bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="entityManagerFactory">
        <property name="dataSource" ref="dataSource"/>
        <property name="jpaVendorAdapter">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/>
        </property>
        <property name="packagesToScan" value="com.os.**.model"/>
        <property name="jpaProperties">
            <props>
                <!-- 生成的数据表的列的映射策略 -->
                <prop key="hibernate.ejb.naming_strategy">org.hibernate.cfg.ImprovedNamingStrategy</prop>
                <!-- hibernate 基本属性 -->
                <prop key="hibernate.dialect">org.hibernate.dialect.MySQL57Dialect</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 class="org.springframework.orm.jpa.JpaTransactionManager" id="transactionManager"
    p:entityManagerFactory-ref="entityManagerFactory"
    />
    <!-- 4.启动事务注解 -->
    <tx:annotation-driven transaction-manager="transactionManager"/>
    <!-- 5.配置Spring Data -->
    <!-- 注意加入JPA的命名空间 -->
    <!-- base-package: 扫描 Repository Bean 所在的 package -->
    <jpa:repositories base-package="com.os.**.dao" entity-manager-factory-ref="entityManagerFactory"/>
</beans>
复制代码

(5)进行测试

package com.os.test;

import com.os.dao.BookDao;
import com.os.model.Book;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class SpringDataTest {

    private ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
    @Test
    public void test01(){
        BookDao bookDao = applicationContext.getBean(BookDao.class);
        
        Book book = bookDao.getByBookName("西游记");

        System.out.println("book = " + book);
    }
}
复制代码

在进行测试的时候,我们报错:EntityPathResolver must not be null! 要配置包扫描,使扫描到repository

<!--扫描spring 組件-->
<context:component-scan base-package="com.os.**.dao"></context:component-scan>
复制代码

(6)运行结果

Hibernate: 
    select
        book0_.book_id as book_id1_0_,
        book0_.author as author2_0_,
        book0_.book_name as book_nam3_0_,
        book0_.create_date as create_d4_0_,
        book0_.price as price5_0_ 
    from
        spring_data_book book0_ 
    where
        book0_.book_name=?
book = Book{bookId=1, bookName='西游记', price=100.0, author='吴承恩', createDate=2020-02-22 14:53:36.0}
复制代码

基本上入门的示例就这样了,大家就是先熟悉一下!后面会对接口进行详细的说明!

关注下面的标签,发现更多相似文章
评论