Spring Data
故事背景
最近学习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打下基础。