SpringData专题(一)-JPA入门

1.ORM概述

ORM(Object-Relational Mapping) 表示对象关系映射。在面向对象的软件开发中,通过ORM,就可以把对象映射到关系型数据库中。只要有一套程序能够做到建立对象与数据库的关联,操作对象就可以直接操作数据库数据,就可以说这套程序实现了ORM对象关系映射。

简单的说:ORM就是建立实体类和数据库表之间的关系,从而达到操作实体类就相当于操作数据库表的目的。

常见的ORM框架有哪些?

ORM框架就是把数据库表映射为Java中类、字段映射为属性、字段的类型映射为属性的类型

MyBatis

Hibernate

SpringData Jpa

1.1 为什么使用ORM

当实现一个应用程序时(不使用O/R Mapping),我们可能会写特别多数据访问层的代码,从数据库保存数据、修改数据、删除数据,而这些代码都是重复的。而使用ORM则会大大减少重复性代码。对象关系映射(Object Relational Mapping,简称ORM),主要实现程序对象到关系数据库数据的映射。

性能:原生JDBC > MyBatis

效率: MyBatis > 原生JDBC

1.2 常见ORM框架

常见的orm框架:Mybatis(ibatis)、Hibernate、SpringData Jpa

2.JPA概述

2.1传统持久层解决方案

在这里插入图片描述

在传统的方式,使用JDBC操作数据库。如果要更换数据库,代码其实不用做任何的更改,只需要更换数据库驱动包和连接字符串就可以了。本质就是JDBC其实是一种代码规范(接口),不同的数据库驱动把这个规范实现了!

2.2.JPA概述

JPA: Java Persistence Api 支持XML、JDK5.0注解俩种元数据的形式,是SUN公司引入的JPA ORM规范
Java EE 5.0 平台标准的 ORM (实体关系映射)规范,使得应用程序以统一的方式访问持久层
JPA是一套规范、有很多框架支持(如Hibernate3.2以上、Toplink)一般用Hibernate就行
在这里插入图片描述
JPA规范本质上就是一种ORM规范,注意不是ORM框架——因为JPA并未提供ORM实现,它只是制订了一些规范,提供了一些编程的API接口,但具体实现则由服务厂商来提供实现,JBoss应用服务器底层就以Hibernate作为JPA的实现。

既然JPA作为一种规范——也就说JPA规范中提供的只是一些接口,显然接口不能直接拿来使用。虽然应用程序可以面向接口编程,但JPA底层一定需要某种JPA实现,否则JPA依然无法使用。
Sun之所以提出JPA规范,其目的是以官方的身份来统一各种ORM框架的规范,包括著名的Hibernate、TopLink等。不过JPA规范给开发者带来了福音:开发者面向JPA规范的接口,但底层的JPA实现可以任意切换:觉得Hibernate好的,可以选择Hibernate JPA实现;觉得TopLink好的,可以选择TopLink JPA实现……这样开发者可以避免为使用Hibernate学习一套ORM框架,为使用TopLink又要再学习一套ORM框架。

2.3.JPA和Hibernate的关系

JPA规范本质上就是一种ORM规范,注意不是ORM框架——因为JPA并未提供ORM实现,它只是制订了一些规范,提供了一些编程的API接口,但具体实现则由服务厂商来提供实现。
在这里插入图片描述
JPA和Hibernate的关系就像JDBC和JDBC驱动的关系,JPA是规范,Hibernate除了作为ORM框架之外,它也是一种JPA实现。JPA怎么取代Hibernate呢?JDBC规范可以驱动底层数据库吗?答案是否定的,也就是说,如果使用JPA规范进行数据库操作,底层需要hibernate作为其实现类完成数据持久化工作。

2.4.JPA 的供应商

JPA 的目标之一是制定一个可以由很多供应商实现的 API,目前Hibernate 3.2+、TopLink 10.1+ 以及 OpenJPA 都提供了 JPA 的实现

  • Hibernate
    JPA 的始作俑者就是 Hibernate 的作者
    Hibernate 从 3.2 开始兼容 JPA
  • OpenJPA
    OpenJPA 是 Apache 组织提供的开源项目
  • TopLink
    TopLink 以前需要收费,如今开源了

2.5.JPA的优势

  • 标准化: 提供相同的 API,这保证了基于JPA 开发的企业应用能够经过少量的修改就能够在不同的 JPA 框架下运行。
  • 简单易用,集成方便: JPA 的主要目标之一就是提供更加简单的编程模型,在 JPA 框架下创建实体和创建 Java 类一样简单,只需要使用 javax.persistence.Entity 进行注解;JPA 的框架和接口也都非常简单。
  • 可媲美JDBC的查询能力: JPA的查询语言是面向对象的,JPA定义了独特的JPQL,而且能够支持批量更新和修改、JOIN、GROUP BY、HAVING 等通常只有 SQL 才能够提供的高级查询特性,甚至还能够支持子查询。
  • 支持面向对象的高级特性: JPA 中能够支持面向对象的高级特性,如类之间的继承、多态和类之间的复杂关系,最大限度的使用面向对象的模型。非常方便的关联查询!@one2many、@many2one …

2.6.JPA 包括 3方面的技术

  • ORM映射元数据:JPA 支持 XML 和 JDK 5.0 注解两种元数据的形式,元数据描述对象和表之间的映射关系,框架据此将实体对象持久化到数据库表中。
  • JPA 的 API:用来操作实体对象,执行CRUD操作,框架在后台完成所有的事情,开发者从繁琐的 JDBC和 SQL代码中解脱出来。
  • 查询语言(JPQL):这是持久化操作中很重要的一个方面,通过面向对象而非面向数据库的查询语言查询数据,避免程序和具体的 SQL 紧密耦合。

3.JPA的入门案例

3.1.需求介绍

实现的功能是保存一个客户到数据库的客户表中。

3.2.开发包介绍

由于JPA是sun公司制定的API规范,所以我们不需要导入额外的JPA相关的jar包,只需要导入JPA的提供商的jar包。我们选择Hibernate作为JPA的提供商,所以需要导入Hibernate的相关jar包

下载地址:
http://sourceforge.net/projects/hibernate/files/hibernate-orm/5.0.7.Final/
页面显示如下图:
在这里插入图片描述

3.3. 搭建开发环境
3.3.1.导入jar包

对于JPA操作,只需要从hibernate提供的资料中找到我们需要的jar导入到工程中即可。

  • 传统工程导入jar包-过时
    在这里插入图片描述
  • maven工程导入坐标

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <!--集中定义版本号-->
        <project.hibernate.version>5.0.7.Final</project.hibernate.version>
    </properties>

    <dependencies>
        <!-- junit -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>

        <!-- hibernate对jpa的支持包 -->
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-entitymanager</artifactId>
            <version>${project.hibernate.version}</version>
        </dependency>

        <!-- c3p0 -->
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-c3p0</artifactId>
            <version>${project.hibernate.version}</version>
        </dependency>

        <!-- log日志 -->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>

        <!-- Mysql and MariaDB -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.6</version>
        </dependency>
    </dependencies>
3.3.2.创建客户的数据库表和客户的实体类
  • 创建客户的数据库表
   /*创建客户表*/
    CREATE TABLE cst_customer (
      cust_id bigint(32) NOT NULL AUTO_INCREMENT COMMENT '客户编号(主键)',
      cust_name varchar(32) NOT NULL COMMENT '客户名称(公司名称)',
      cust_source varchar(32) DEFAULT NULL COMMENT '客户信息来源',
      cust_industry varchar(32) DEFAULT NULL COMMENT '客户所属行业',
      cust_level varchar(32) DEFAULT NULL COMMENT '客户级别',
      cust_address varchar(128) DEFAULT NULL COMMENT '客户联系地址',
      cust_phone varchar(64) DEFAULT NULL COMMENT '客户联系电话',
      PRIMARY KEY (`cust_id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
  • 创建客户的实体类
public class Customer implements Serializable {
    
	private Long custId;
	private String custName;
	private String custSource;
	private String custIndustry;
	private String custLevel;
	private String custAddress;
	private String custPhone;
	
	public Long getCustId() {
		return custId;
	}
	public void setCustId(Long custId) {
		this.custId = custId;
	}
	public String getCustName() {
		return custName;
	}
	public void setCustName(String custName) {
		this.custName = custName;
	}
	public String getCustSource() {
		return custSource;
	}
	public void setCustSource(String custSource) {
		this.custSource = custSource;
	}
	public String getCustIndustry() {
		return custIndustry;
	}
	public void setCustIndustry(String custIndustry) {
		this.custIndustry = custIndustry;
	}
	public String getCustLevel() {
		return custLevel;
	}
	public void setCustLevel(String custLevel) {
		this.custLevel = custLevel;
	}
	public String getCustAddress() {
		return custAddress;
	}
	public void setCustAddress(String custAddress) {
		this.custAddress = custAddress;
	}
	public String getCustPhone() {
		return custPhone;
	}
	public void setCustPhone(String custPhone) {
		this.custPhone = custPhone;
	}
}	
3.3.3.编写实体类和数据库表的映射配置[重点]
  • 在实体类上使用JPA注解的形式配置映射关系
/**
 * * 所有的注解都是使用JPA的规范提供的注解,
 * * 所以在导入注解包的时候,一定要导入javax.persistence下的
 */
@Entity //声明实体类
@Table(name = "cst_customer") //建立实体类和表的映射关系
public class Customer {

    @Id//声明当前私有属性为主键
    @GeneratedValue(strategy = GenerationType.IDENTITY) //配置主键的生成策略
    @Column(name = "cust_id") //指定和表中cust_id字段的映射关系
    private Long custId;

    @Column(name = "cust_name") //指定和表中cust_name字段的映射关系
    private String custName;

    @Column(name = "cust_source")//指定和表中cust_source字段的映射关系
    private String custSource;

    @Column(name = "cust_industry")//指定和表中cust_industry字段的映射关系
    private String custIndustry;

    @Column(name = "cust_level")//指定和表中cust_level字段的映射关系
    private String custLevel;

    @Column(name = "cust_address")//指定和表中cust_address字段的映射关系
    private String custAddress;

    @Column(name = "cust_phone")//指定和表中cust_phone字段的映射关系
    private String custPhone;

    public Long getCustId() {
        return custId;
    }

    public void setCustId(Long custId) {
        this.custId = custId;
    }

    public String getCustName() {
        return custName;
    }

    public void setCustName(String custName) {
        this.custName = custName;
    }

    public String getCustSource() {
        return custSource;
    }

    public void setCustSource(String custSource) {
        this.custSource = custSource;
    }

    public String getCustIndustry() {
        return custIndustry;
    }

    public void setCustIndustry(String custIndustry) {
        this.custIndustry = custIndustry;
    }

    public String getCustLevel() {
        return custLevel;
    }

    public void setCustLevel(String custLevel) {
        this.custLevel = custLevel;
    }

    public String getCustAddress() {
        return custAddress;
    }

    public void setCustAddress(String custAddress) {
        this.custAddress = custAddress;
    }

    public String getCustPhone() {
        return custPhone;
    }

    public void setCustPhone(String custPhone) {
        this.custPhone = custPhone;
    }
}

  • 常用注解的说明

​ @Entity
​ 作用:指定当前类是实体类。
​ @Table
​ 作用:指定实体类和表之间的对应关系。
​ 属性:
​ name:指定数据库表的名称
​ @Id
​ 作用:指定当前字段是主键。
​ @GeneratedValue
​ 作用:指定主键的生成方式。。
​ 属性:
​ strategy :指定主键生成策略。
​ @Column
​ 作用:指定实体类属性和数据库表之间的对应关系
​ 属性:
​ name:指定数据库表的列名称。
​ unique:是否唯一
​ nullable:是否可以为空
​ inserttable:是否可以插入
​ updateable:是否可以更新
​ columnDefinition: 定义建表时创建此列的DDL
​ secondaryTable: 从表名。如果此列不建在主表上(默认建在主表),该属性定义该列所在从表的名字搭建开发环境

3.3.4.配置JPA的核心配置文件

在java工程的src路径下创建一个名为META-INF的文件夹,在此文件夹下创建一个名为persistence.xml的配置文件。注意此文件要位于类路径下,这里放在 resources/META-INF 下。
在这里插入图片描述

<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
    http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
             version="2.0">
    <!--配置持久化单元
        name:持久化单元名称
        transaction-type:事务类型
             RESOURCE_LOCAL:本地事务管理
             JTA:分布式事务管理 -->
    <persistence-unit name="myJpa" transaction-type="RESOURCE_LOCAL">
        <!--配置JPA规范的服务提供商 -->
        <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
        <properties>
            <!-- 数据库驱动 -->
            <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver" />
            <!-- 数据库地址 -->
            <property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/empdb" />
            <!-- 数据库用户名 -->
            <property name="javax.persistence.jdbc.user" value="root" />
            <!-- 数据库密码 -->
            <property name="javax.persistence.jdbc.password" value="123" />

            <!--jpa提供者的可选配置:我们的JPA规范的提供者为hibernate,所以jpa的核心配置中兼容hibernate的配 -->
            <property name="hibernate.show_sql" value="true" />
            <property name="hibernate.format_sql" value="true" />
            <property name="hibernate.hbm2ddl.auto" value="update" />
        </properties>
    </persistence-unit>
</persistence>
3.4.实现保存操作
/**
 * @author bruceliu
 * @create 2019-07-05 12:35
 * @description
 */
public class TestJpa {

    @Test
    public void test() {
        /**
         * 创建实体管理类工厂,借助Persistence的静态方法获取
         * 其中传递的参数为持久化单元名称,需要jpa配置文件中指定
         */
        EntityManagerFactory factory = Persistence.createEntityManagerFactory("myJpa");
        //创建实体管理类
        EntityManager em = factory.createEntityManager();
        //获取事务对象
        EntityTransaction tx = em.getTransaction();
        //开启事务
        tx.begin();
        Customer c = new Customer();
        c.setCustName("测试");
        //保存操作
        em.persist(c);
        //提交事务
        tx.commit();
        //释放资源
        em.close();
        factory.close();
    }
}
3.5.测试结果

在这里插入图片描述

4.小结

  • 创建 persistence.xml, 在这个文件中配置持久化单元
    需要指定跟哪个数据库进行交互;
    需要指定 JPA 使用哪个持久化的框架以及配置该框架的基本属性
  • 创建实体类, 使用 annotation 来描述实体类跟数据库表之间的映射关系.
  • 使用 JPA API 完成数据增加、删除、修改和查询操作
    创建 EntityManagerFactory (对应 Hibernate 中的 SessionFactory);
    创建 EntityManager (对应 Hibernate 中的Session);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值