Spring Data
- 故事背景
- 一:基础概念
- 1.1 什么是SpringData
- 1.2 为什么要用SpringData
- 二:JPA与Hibernate、MyBatis关系
- 2.1 JPA与JDBC
- 2.1.1 特点
- 2.1.2 JPA规范提供
- 2.1.3 JDBC的不足
- 2.2 Hibernate与JPA
- 2.2.1 关系
- 2.3 mybatis 和Hibernate
- 三:Hibernate与JPA快速搭建
- 3.1 新建一个Maven项目并引入对应Pom依赖
- 3.2 hibernate具体配置
- 3.3. 具体使用Hibernate实现操作
- 3.3.1 项目结构
- 3.3.2 User类
- 3.3.3 HibernateTest 实现
- 3.4 JPA具体配置
- 3.5 具体使用JPA进行实现
- 3.5.1 添加配置文件
- 3.5.2 测试类
- 四:JPA中对象的四种状态
- 4.1 jpa的对象4种状态
- 4.2 persist方法
- 4.3 merge方法
- 4.4 refresh方法
- 4.5 remove方法
- 五:总结&提升
故事背景
最近学习SpringData,系统的总结一下SpringData的相关知识,此篇为算是一篇前言,主要介绍一下SpringData,先讲一个JPA和Hibernate,讲一讲他们的关系,并且给出对应的示例,希望大家可以通过这个示例,了解到这些概念以及其基本的用法。
一:基础概念
1.1 什么是SpringData
Spring Data是Spring Framework的一个子项目,它提供了一种简化数据访问层的方式。它的目标是提供一种统一的、易于使用的编程模型,用于与不同类型的数据存储进行交互,包括关系型数据库、NoSQL数据库、图数据库等。
1.2 为什么要用SpringData
- 其统一和简化了对不同数据库类型的持久化。通过使用SpringData我们可以简化开发,提升开发效率。
- springData是一个伞型项目,有多个子项目,不同的子项目针对不同的数据库的实现。
二:JPA与Hibernate、MyBatis关系
2.1 JPA与JDBC
2.1.1 特点
- 二者都是与数据库交互的规范。数据库实现了JDBC的规范。ORM(Object、Relational、mapping)框架实现了JPA的规范。
- JDBC通过sql语句与数据库通信。JPA用面向对象的方式,通过ORM生成SQL,进行操作。
- JPA 是需要 JDBC的,是依赖于JDBC的。
2.1.2 JPA规范提供
- ORM映射元数据,注解和xml两种方式
- JPA的API,用来操作对象,执行对应的CRUD的操作,让开发者从JDBC和SQL代码中解脱出来
- JPQL查询语言,通过面向对象的方式,面向数据库查询
2.1.3 JDBC的不足
- 学习成本高
- 修改不同数据库时,不容易移植
- JAVA对象和数据库的映射比较麻烦
2.2 Hibernate与JPA
2.2.1 关系
- Hibernate实现了JPA规范。是JPA的一种实现。
2.3 mybatis 和Hibernate
- MyBatis是一个半自动的ORM框架,需要自己写sql。而Hibernate是全自动的ORM框架
- MyBatis更加小巧,是对JDBC的封装。Hibernate根据ORM直接生成不同的SQL
- 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 略
}
这里主要是几个注解来进行标识:
- @Entity注解
表示我们的User类是一个实体类,其应该在数据库内对应一张表 - @Table注解
通过Table注解可以指定对应的表的名称 - @Id注解
每个实体类必须要有一个主键Id,对应数据库表的主键,Id有多种生成策略 - @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("123456@163.com");
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会产生以下操作:
- 如果A是一个new状态的实体,它将会转为managed状态;
- 如果A是一个managed状态的实体,它的状态不会发生任何改变。但是系统仍会在数据库执行INSERT操作;
- 如果A是一个removed(删除)状态的实体,它将会转换为受控状态;
- 如果A是一个detached(分离)状态的实体,该方法会抛出IllegalArgumentException异常,具体异常根据不同的
JPA实现有关。
4.3 merge方法
public void merge(Object entity)
merge方法的主要作用是将用户对一个detached状态实体的修改进行归档,归档后将产生
一个新的managed状态对象。
对不同状态下的实例A,merge会产生以下操作:
- 如果A是一个detached状态的实体,该方法会将A的修改提交到数据库,并返回一个新的managed状态的实例A2;
- 如果A是一个new状态的实体,该方法会产生一个根据A产生的managed状态实体A2;
- 如果A是一个managed状态的实体,它的状态不会发生任何改变。但是系统仍会在数据库执行UPDATE操作;
- 如果A是一个removed状态的实体,该方法会抛出IllegalArgumentException异常。
4.4 refresh方法
public void refresh(Object entity)
refresh方法可以保证当前的实例与数据库中的实例的内容一致。
对不同状态下的实例A,refresh会产生以下操作:
- 如果A是一个new状态的实例,不会发生任何操作,但有可能会抛出异常,具体情况根据不同JPA实现有关;
- 如果A是一个managed状态的实例,它的属性将会和数据库中的数据同步;
- 如果A是一个removed状态的实例,该方法将会抛出异常: Entity not managed
- 如果A是一个detached状态的实体,该方法将会抛出异常。
4.5 remove方法
public void remove(Object entity)
remove方法可以将实体转换为removed状态,并且在调用flush()方法或提交事物后删除数据库中的数据。
对不同状态下的实例A,remove会产生以下操作:
- 如果A是一个new状态的实例,A的状态不会发生任何改变,但系统仍会在数据库中执行DELETE语句;
- 如果A是一个managed状态的实例,它的状态会转换为removed;
- 如果A是一个removed状态的实例,不会发生任何操作;
- 如果A是一个detached状态的实体,该方法将会抛出异常
五:总结&提升
本文主要讲解了SpringData的基本概念,以及什么是JPA,JPA与我们熟知的Hibernate、MyBatis之间的关系。并且给出了Hibernate和JPA的具体示例代码,通过此文,我们可以了解到什么是JPA,了解JPA规范的作用,为我们接下来深入学习SpringData打下基础。