目标
- 理解ORM思想和该数
- 理解JPA和hibernate的关系
- 掌握maven单构件jpa项目并进行增删改查操作
- 掌握JPQL语句进行条件查询
1. ORM思想
1. 概述
ORM(Object-Relational Mapping) 表示对象关系映射。通过ORM,就可以把对象映射到关系型数据库中。
简单的说:ORM就是建立实体类和数据库表之间的关系,从而达到操作实体类就相当于操作数据库表的目的。
2. 目的
主要目的:操作实体类相当于操作数据库表
需要建立两个映射关系:
实体类和表的映射关系
实体类中属性和表中字段的映射关系
3. 实现ORM思想的框架
mybatis和hibernate
2. hibernate与JPA的概述
1. hibernate介绍
Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,它将POJO与数据库表建立映射关系,是一个全自动的orm框架。
2. JPA
1. 介绍
JPA的全称是Java Persistence API, 即Java 持久化API,是SUN公司推出的一套基于ORM的规范,内部是由一系列的接口和抽象类构成。
JPA通过JDK 5.0注解描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中
2. 优势
- 标准化
- 容器级特性的支持
- 简单方便
- 查询能力
- 高级特性
3. JPA和hibernate的关系
JPA规范本质上就是一种ORM规范,注意不是ORM框架——因为JPA并未提供ORM实现,它只是制订了一些规范,提供了一些编程的API接口,但具体实现则由服务厂商来提供实现。
3. JPA的入门案例
1. 需求介绍
实现功能是保存一个客户到数据库的客户表中
2. 开发包介绍
只需要导入JPA提供商的jar包
3. 搭建开发环境
1. 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>
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;
创建客户的实体类
3. 编写实体类和数据库表的映射配置
实体类上使用JPA注解的形式配置映射关系
@Entity//声明实体类
@Table(name = "cst_customer")//配置实体类和表的映射关系
public class Customer implements Serializable {
@Id//声明主键的配置
@GeneratedValue(strategy = GenerationType.IDENTITY)//配置主键的生成策略,自增
@Column(name = "cust_id")//配置属性和字段的映射关系
private Long custId;
@Column(name = "cust_name")
private String custName;
@Column(name = "cust_source")
private String custSource;
@Column(name = "cust_industry")
private String custIndustry;
@Column(name = "cust_level")
private String custLevel;
@Column(name = "cust_address")
private String custAddress;
@Column(name = "cust_phone")
private String custPhone;
// getter/setter以及toString
常用注解的说明:
@Entity
作用:指定当前类是实体类。
@Table
作用:指定实体类和表之间的对应关系。
属性:
name:指定数据库表的名称
@Id
作用:指定当前字段是主键。
@GeneratedValue
作用:指定主键的生成方式。。
属性:
strategy :指定主键生成策略。
GenerationType.IDENTITY 自增,mysql
底层数据库必须支持自动增长
GenerationType.SEQUENCE 序列,Oracle
底层数据库必须支持序列
GenerationType.TABLE jpa提供的一种机制,通过一张数据库表的形式帮我们完成主键自增
GenerationType.AUTO 由程序自动帮助我们选择主键生成策略
@Column
作用:指定实体类属性和数据库表之间的对应关系
属性:
name:指定数据库表的列名称。
unique:是否唯一
nullable:是否可以为空
inserttable:是否可以插入
updateable:是否可以更新
columnDefinition: 定义建表时创建此列的DDL
secondaryTable: 从表名。如果此列不建在主表上(默认建在主表),该属性定义该列所在从表的名字搭建开发环境[重点]
4. 配置JPA的核心配置文件
在java工程的src路径下创建一个名为META-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:事务管理的方式
RESOURCE_LOCAL:本地事务管理
JTA:分布式事务管理
-->
<persistence-unit name="myJpa" transaction-type="RESOURCE_LOCAL">
<!--jpa的实现方式-->
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<properties>
<!--数据库信息-->
<property name="javax.persistence.jdbc.user" value="root"/>
<property name="javax.persistence.jdbc.password" value="root"/>
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
<property name="javax.persistence.jdbc.url" value="jdbc:mysql:///jpa"/>
<!--可选配置:配置jpa实现方(hibernate)的配置信息
显示SQL :false,true
自动创建数据库表:
create:程序运行时创建数据库表(如果有表,先删除表再创建)
update:程序运行时创建表(如果有表,不会创建表)
none:不会创建表
-->
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.hbm2ddl.auto" value="create"/>
</properties>
</persistence-unit>
</persistence>
4. 实现保存操作
test下创建JpaTest.java文件
jpa的操作步骤
- 加载配置文件创建工厂(实体管理类工厂)对象
- 通过实体管理类工厂获取实体管理器
- 获取事务对象,开启事务
- 完成增删改查操作
- 提交事务(回滚事务)
- 释放资源
public class JpaTest {
@Test
public void testSave(){
// 1.加载配置文件创建工厂(实体管理器工厂)对象
EntityManagerFactory factory = Persistence.createEntityManagerFactory("myJpa");
// 2.通过实体管理器工厂获取实体管理器
EntityManager em = factory.createEntityManager();
// 3.获取事务对象,开启事务
EntityTransaction tx = em.getTransaction();
tx.begin();//开启事务
// 4.完成正删改查操作,保存一个客户到数据库
Customer customer = new Customer();
customer.setCustName("tom");
customer.setCustIndustry("电商");
// 保存
em.persist(customer);
// 5. 提交事务
tx.commit();
// 6.释放资源
em.clear();
factory.close();
}
5. API介绍
1. Persistence对象
作用:创建实体管理器工厂EntityManagerFactory
调用createEntityMnagerFactory静态方法,根据持久化单元名称创建实体管理器工厂
2. EntityManagerFactory
接口,主要用来创建EntityManager对象,方法:createEntityManager
内部维护的很多的内容:数据库信息,缓存信息,所有的实体管理器对象
在创建EntityManagerFactory的过程中会根据配置创建数据库表
特点:是个线程安全的对象,创建过程比较耗费资源。
- 如何解决EntityManagerFactory的创建过程浪费资源(耗时)的问题?
思路:创建一个公共的EntityManagerFactory的对象, 用静态代码块的形式创建EntityManagerFactory
3. EntityManager对象
实体类管理器
- beginTransaction : 创建事务对象
- presist : 保存
- merge : 更新
- remove : 删除
- find/getRefrence : 根据id查询
4. Transaction 对象
- begin:开启事务
- commit:提交事务
- rollback:回滚
5. 查询
使用find方法查询:(立即加载)
- 查询的对象就是当前客户对象本身;
- 在调用find方法时,会发送SQL语句查询数据库
使用getReference方法查询:(延迟加载,懒加载)
-
获取的对象是一个动态代理对象
-
调用getReference方法不会立即发送SQL语句查询数据库
当调用查询结果对象的时候,才会发送查询的SQL语句,什么时候用,什么时候发送
6. 示范代码
public class JpaTest {
private EntityManager em;
private EntityTransaction tx;
private EntityManagerFactory factory;
@Before
public void init(){
// 1.加载配置文件创建工厂(实体管理器工厂)对象
factory = Persistence.createEntityManagerFactory("myJpa");
// 2.通过实体管理器工厂获取实体管理器
em = factory.createEntityManager();
// 3.获取事务对象,开启事务
tx = em.getTransaction();
tx.begin();//开启事务
}
@After
public void close(){
// 5. 提交事务
tx.commit();
// 6.释放资源
em.clear();
factory.close();
}
@Test
public void testSave(){
// 4.完成正删改查操作,保存一个客户到数据库
Customer customer = new Customer();
customer.setCustName("pony");
customer.setCustIndustry("电商");
// 保存
em.persist(customer);
}
// 根据id查询客户
//
@Test
public void testFind(){
Customer customer = em.find(Customer.class, 1L);
System.out.println(customer);
}
// 根据id查询客户
@Test
public void testReference(){
Customer customer = em.getReference(Customer.class, 1L);
System.out.println(customer);
}
// 删除客户
@Test
public void testRemove(){
// 查询客户
Customer customer = em.getReference(Customer.class, 1L);
// 删除客户
em.remove(customer);
}
// 更新客户的操作
@Test
public void testUpdate(){
// 查询客户
Customer customer = em.getReference(Customer.class, 2L);
customer.setCustIndustry("p2p");
// 更新客户
em.merge(customer);
}
}
7. JPA的复杂查询
1. JPQL
全称Java Persistence Query Language
基于首次在EJB2.0中引入的EJB查询语言(EJB QL),Java持久化查询语言(JPQL)是一种可移植的查询语言,旨在以面向对象表达式语言的表达式,将SQL语法和简单查询语义绑定在一起·使用这种语言编写的查询是可移植的,可以被编译成所有主流数据库服务器上的SQL。
特征与原生SQL语句类似,并且完全面向对象,通过类名和属性访问,而不是表名和表的属性
2. 查询步骤
- 创建query查询对象
- 对参数进行赋值
- 查询,并得到返回结果
3. 查询类型
- 查询全部
- 排序查询
- 统计客户的总数
- 分页查询
- 条件查询
4. 代码
public class JpqlTest {
private EntityManager em;
private EntityTransaction tx;
private EntityManagerFactory factory;
@Before
public void init(){
// 1.加载配置文件创建工厂(实体管理器工厂)对象
factory = Persistence.createEntityManagerFactory("myJpa");
// 2.通过实体管理器工厂获取实体管理器
em = factory.createEntityManager();
// 3.获取事务对象,开启事务
tx = em.getTransaction();
tx.begin();//开启事务
}
@After
public void close(){
// 5. 提交事务
tx.commit();
// 6.释放资源
em.clear();
factory.close();
}
// 查询全部
@Test
public void testFindAll(){
String jpql = "from cn.itcast.domain.Customer";
Query query = em.createQuery(jpql);
// 发送查询,封装结果集
List list = query.getResultList();
for (Object o : list) {
System.out.println(o);
}
}
// 排序查询
@Test
public void testOrders(){
String jpql = "from Customer order by custId desc";
Query query = em.createQuery(jpql);
// 发送查询,封装结果集
List list = query.getResultList();
for (Object o : list) {
System.out.println(o);
}
}
// 统计客户的总数
@Test
public void testCount(){
String jpql = "select count(custId) from Customer";
Query query = em.createQuery(jpql);
// 发送查询,封装结果集
Object result = query.getSingleResult();
System.out.println(result);
}
// 分页查询
@Test
public void testPage(){
String jpql = "from Customer";
Query query = em.createQuery(jpql);
query.setFirstResult(0);
query.setMaxResults(5);
// 发送查询,封装结果集
List list = query.getResultList();
for (Object o : list) {
System.out.println(o);
}
}
// 条件查询 查询以电商开头的
@Test
public void testCondition(){
String jpql = "from Customer where custIndustry like ?";
Query query = em.createQuery(jpql);
// 对参数赋值--占位符参数
// 第一个参数:占位符位置,第二个参数:取值
query.setParameter(1,"电商%");
// 发送查询,封装结果集
List list = query.getResultList();
for (Object o : list) {
System.out.println(o);
}
}
}