SpringData 基础篇

故事背景

最近学习SpringData,系统的总结一下SpringData的相关知识,此篇为算是一篇前言,主要介绍一下SpringData,先讲一个JPA和Hibernate,讲一讲他们的关系,并且给出对应的示例,希望大家可以通过这个示例,了解到这些概念以及其基本的用法。

一:基础概念

1.1 什么是SpringData

Spring Data是Spring Framework的一个子项目,它提供了一种简化数据访问层的方式。它的目标是提供一种统一的、易于使用的编程模型,用于与不同类型的数据存储进行交互,包括关系型数据库、NoSQL数据库、图数据库等。
在这里插入图片描述

1.2 为什么要用SpringData

  1. 其统一和简化了对不同数据库类型的持久化。通过使用SpringData我们可以简化开发,提升开发效率。
  2. springData是一个伞型项目,有多个子项目,不同的子项目针对不同的数据库的实现。

二:JPA与Hibernate、MyBatis关系

2.1 JPA与JDBC

2.1.1 特点

  1. 二者都是与数据库交互的规范。数据库实现了JDBC的规范。ORM(Object、Relational、mapping)框架实现了JPA的规范。
  2. JDBC通过sql语句与数据库通信。JPA用面向对象的方式,通过ORM生成SQL,进行操作。
  3. JPA 是需要 JDBC的,是依赖于JDBC的。

2.1.2 JPA规范提供

  1. ORM映射元数据,注解和xml两种方式
  2. JPA的API,用来操作对象,执行对应的CRUD的操作,让开发者从JDBC和SQL代码中解脱出来
  3. JPQL查询语言,通过面向对象的方式,面向数据库查询

2.1.3 JDBC的不足

  1. 学习成本高
  2. 修改不同数据库时,不容易移植
  3. JAVA对象和数据库的映射比较麻烦

2.2 Hibernate与JPA

2.2.1 关系

  1. Hibernate实现了JPA规范。是JPA的一种实现。

2.3 mybatis 和Hibernate

  1. MyBatis是一个半自动的ORM框架,需要自己写sql。而Hibernate是全自动的ORM框架
  2. MyBatis更加小巧,是对JDBC的封装。Hibernate根据ORM直接生成不同的SQL
  3. MyBatis在国内比较流行,关系比较复杂。Hibernate在国外更加流行,Hibernate不是很适合复杂的关系

三:Hibernate与JPA快速搭建

3.1 新建一个Maven项目并引入对应Pom依赖

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.2</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-core</artifactId>
            <version>5.4.32.Final</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.13</version>
        </dependency>

3.2 hibernate具体配置

需要在我们的Resource目录下,添加对应的配置,这里先添加Hibernate对应的配置

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD//EN"
        "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>

        <!-- 数据库连接配置 -->
        <property name="hibernate.connection.driver_class">com.mysql.cj.jdbc.Driver</property>
        <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/jpa</property>
        <property name="hibernate.connection.username">root</property>
        <property name="hibernate.connection.password">root666</property>
        <property name="hibernate.connection.characterEncoding">UTF-8</property>
        <property name="hibernate.connection.useUnicode">true</property>
        
        <!--        日志中记录sql-->
        <property name="show_sql">true</property>
        <!--        格式化sql-->
        <property name="format_sql">true</property>
        <!--        表的生成策略,自动生成-->
        <property name="hbm2ddl.auto">update</property>

        <!-- 数据库方言,注意版本 -->
        <property name="hibernate.dialect">org.hibernate.dialect.MySQL57Dialect</property>

        <!-- 映射文件位置 -->
        <mapping class="org.example.entity.User"/>

    </session-factory>
</hibernate-configuration>

此配置文件主要是配置我们对应的数据库,以及一些对应的主要功能的配置,我将重要配置都加上了注释。

3.3. 具体使用Hibernate实现操作

3.3.1 项目结构

首先宏观看一下项目结构,这样有利于下面的讲解:
在这里插入图片描述

3.3.2 User类

User类是一个实体类,对应数据库表

@Entity
@Table(name = "user")
public class User {
    
    

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private long id;

    private String userName;

    private String email;
	//get与set 略 

}
这里主要是几个注解来进行标识:

  1. @Entity注解
    表示我们的User类是一个实体类,其应该在数据库内对应一张表
  2. @Table注解
    通过Table注解可以指定对应的表的名称
  3. @Id注解
    每个实体类必须要有一个主键Id,对应数据库表的主键,Id有多种生成策略
  4. @GeneratedValue注解
    指定主键的生成策略,这里使用的是自增的形式

3.3.3 HibernateTest 实现

public class HibernateTest {
    
    

    //Session工厂 代码持久化到数据库的一个桥梁
    private SessionFactory sf;

    @Before
    public void  init() {
    
    

        StandardServiceRegistry registry = new StandardServiceRegistryBuilder().configure("/hibernate.cfg.xml").build();

        sf = new MetadataSources(registry).buildMetadata().buildSessionFactory();
    }

    @Test
    public void test(){
    
    
        //session 进行持久化操作
        try(Session session = sf.openSession()){
    
    

            Transaction tx = session.beginTransaction();

            User user = new User();
            user.setUserName("郝立琢");
            user.setEmail("[email protected]");

            session.save(user);

            tx.commit();

        }

    }

    @Test
    public void test1(){
    
    
        try(Session session = sf.openSession()){
    
    

            Transaction tx = session.beginTransaction();

            User user = session.find(User.class,1L);
            tx.commit();

            System.out.println(user.getUserName());

        }
    }

通过Session会话实现数据库的插入和查询两种操作。

3.4 JPA具体配置

3.5 具体使用JPA进行实现

3.5.1 添加配置文件

首先在Resource下新增一个名为 MEAT-INF的文件夹,然后再其内部增添一个名为persistence的xml文件

<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0">
    <!-- 需要配置persistence-unit节点
    持久化单元:
    name:持久化单元名称
    transaction-type:事务管理的方式
    JTA:分布式事务管理
    RESOURCE_LOCAL:本地事务管理 -->
    <persistence-unit name="hibernateJPA" transaction-type="RESOURCE_LOCAL">
        <!-- jpa的实现方式 -->
        <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>

        <class>org.example.entity.User</class>


        <!-- 可选配置:配置jpa实现方的配置信息 -->
        <properties>
            <!-- 数据库信息
            用户名,javax.persistence.jdbc.user
            密码,javax.persistence.jdbc.password
            驱动,javax.persistence.jdbc.driver
            数据库地址,javax.persistence.jdbc.url -->
            <property name="javax.persistence.jdbc.user" value="root"/>
            <property name="javax.persistence.jdbc.password" value="root666"/>
            <property name="javax.persistence.jdbc.driver" value="com.mysql.cj.jdbc.Driver"/>
            <property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/jpa?serverTimezone=UTC"/>

            <!-- 配置jpa实现方(hibernate)的配置信息
            显示sql:false|true
            自动创建数据库表:hibernate.hbm2ddl.auto
            create:程序运行时创建数据库表(如果有表,先删除表再创建)
            update:程序运行时创建表(如果有表,不会创建表)
            none:不会创建表 -->
            <property name="hibernate.show_sql" value="true"/>
            <property name="hibernate.hbm2ddl.auto" value="update"/>
            <property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5InnoDBDialect"/>
        </properties>
    </persistence-unit>
</persistence>

此处为JPA对应的配置,主要定义了持久化单元、指定了JPA实现的提供者、配置实体类、配置了相关属性。

3.5.2 测试类

public class JpaTest {
    
    

        //EntityManagerFactory类型的属性,用于创建EntityManager对象。
    private EntityManagerFactory factory;

    //是EntityManager类型的属性,用于执行JPA操作,包括实体的持久化、更新、查询等。
    EntityManager em;


    @Before
    public void inti(){
    
    
        //加载配置文件
        factory = Persistence.createEntityManagerFactory("hibernateJPA");
        //获取EntityManager对象
        em = factory.createEntityManager();
    }

    /**
     * 查询全部
     * jqpl:from cn.itcast.domain.Customer
     * sql:SELECT * FROM cst_customer
     */
    @Test
    public void testR_HQL() {
    
    
        //2.开启事务
        EntityTransaction tx = em.getTransaction();
        tx.begin();
        //3.查询全部
        String jpql = "select c from User c";
        Query query = em.createQuery(jpql);//创建Query查询对象,query对象才是执行jqpl的对象

        //发送查询,并封装结果集
        List list = query.getResultList();

        for (Object obj : list) {
    
    
            User user = (User)obj;
            System.out.print(user.getUserName());
        }

        //4.提交事务
        tx.commit();
        //5.释放资源
        em.close();
    }

    @Test
    public void testR() {
    
    
        //2.开启事务
        EntityTransaction tx = em.getTransaction();
        tx.begin();

        User user = em.getReference(User.class, 1L);
        System.out.println("===========================");
        System.out.println(user);
        //4.提交事务
        tx.commit();
        //5.释放资源
        em.close();
    }
}

使用JPA的规范进行的调用,我们可以更好的移植其他对JPA的实现。

四:JPA中对象的四种状态

4.1 jpa的对象4种状态

  • 临时状态:刚创建出来,∙没有与entityManager发生关系,没有被持久化,不处于entityManager中的对象
  • 持久状态:∙与entityManager发生关系,已经被持久化,您可以把持久化状态当做实实在在的数据库记录。
  • 删除状态:执行remove方法,事物提交之前
  • 游离状态:游离状态就是提交到数据库后,事务commit后实体的状态,因为事务已经提交了,此时实体的属
    性任你如何改变,也不会同步到数据库,因为游离是没人管的孩子,不在持久化上下文中。

4.2 persist方法

public void persist(Object entity)
persist方法可以将实例转换为managed(托管)状态。在调用flush()方法或提交事物后,实
例将会被插入到数据库中。
对不同状态下的实例A,persist会产生以下操作:

  1. 如果A是一个new状态的实体,它将会转为managed状态;
  2. 如果A是一个managed状态的实体,它的状态不会发生任何改变。但是系统仍会在数据库执行INSERT操作;
  3. 如果A是一个removed(删除)状态的实体,它将会转换为受控状态;
  4. 如果A是一个detached(分离)状态的实体,该方法会抛出IllegalArgumentException异常,具体异常根据不同的
    JPA实现有关。

4.3 merge方法

public void merge(Object entity)
merge方法的主要作用是将用户对一个detached状态实体的修改进行归档,归档后将产生
一个新的managed状态对象。
对不同状态下的实例A,merge会产生以下操作:

  1. 如果A是一个detached状态的实体,该方法会将A的修改提交到数据库,并返回一个新的managed状态的实例A2;
  2. 如果A是一个new状态的实体,该方法会产生一个根据A产生的managed状态实体A2;
  3. 如果A是一个managed状态的实体,它的状态不会发生任何改变。但是系统仍会在数据库执行UPDATE操作;
  4. 如果A是一个removed状态的实体,该方法会抛出IllegalArgumentException异常。

4.4 refresh方法

public void refresh(Object entity)
refresh方法可以保证当前的实例与数据库中的实例的内容一致。
对不同状态下的实例A,refresh会产生以下操作:

  1. 如果A是一个new状态的实例,不会发生任何操作,但有可能会抛出异常,具体情况根据不同JPA实现有关;
  2. 如果A是一个managed状态的实例,它的属性将会和数据库中的数据同步;
  3. 如果A是一个removed状态的实例,该方法将会抛出异常: Entity not managed
  4. 如果A是一个detached状态的实体,该方法将会抛出异常。

4.5 remove方法

public void remove(Object entity)
remove方法可以将实体转换为removed状态,并且在调用flush()方法或提交事物后删除数据库中的数据。
对不同状态下的实例A,remove会产生以下操作:

  1. 如果A是一个new状态的实例,A的状态不会发生任何改变,但系统仍会在数据库中执行DELETE语句;
  2. 如果A是一个managed状态的实例,它的状态会转换为removed;
  3. 如果A是一个removed状态的实例,不会发生任何操作;
  4. 如果A是一个detached状态的实体,该方法将会抛出异常

五:总结&提升

本文主要讲解了SpringData的基本概念,以及什么是JPA,JPA与我们熟知的Hibernate、MyBatis之间的关系。并且给出了Hibernate和JPA的具体示例代码,通过此文,我们可以了解到什么是JPA,了解JPA规范的作用,为我们接下来深入学习SpringData打下基础。

猜你喜欢

转载自blog.csdn.net/hlzdbk/article/details/130961532