一、ORM思想
主要目的:操作实体类就相当于操作数据库表
需要建立两个映射关系:
①实体类和表的映射关系
②实体类中属性和表中字段的关系
实现了ORM思想的框架:mybatis、hibernate
二、hibernate框架介绍
:Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,它将POJO(Java实体类对象)与数据库表建立映射关系,是一个全自动的orm框架,hibernate可以自动生成SQL语句,自动执行,使得Java程序员可以随心所欲的使用对象编程思维来操纵数据库。
三、JPA规范
:JPA是Java Persistence API的简称,中文名Java持久层API,是JDK 5.0注解或XML描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中。是SUN公司推出的一款基于ORM的规范,内部是由一系列的接口和抽象类构成。
JPA的优势
标准化
JPA 是 JCP 组织发布的 Java EE 标准之一,因此任何声称符合 JPA 标准的框架都遵循同样的架构,提供相同的访问API,这保证了基于JPA开发的企业应用能够经过少量的修改就能够在不同的JPA框架下运行。
容器级特性的支持
JPA框架中支持大数据集、事务、并发等容器级事务,这使得 JPA 超越了简单持久化框架的局限,在企业应用发挥更大的作用。
简单方便
JPA的主要目标之一就是提供更加简单的编程模型:在JPA框架下创建实体和创建Java 类一样简单,没有任何的约束和限制,只需要使用 javax.persistence.Entity进行注释,JPA的框架和接口也都非常简单,没有太多特别的规则和设计模式的要求,开发者可以很容易地掌握。JPA基于非侵入式原则设计,因此可以很容易地和其它框架或者容器集成。
查询能力
JPA的查询语言是面向对象而非面向数据库的,它以面向对象的自然语法构造查询语句,可以看成是Hibernate HQL的等价物。JPA定义了独特的JPQL(Java Persistence Query Language),JPQL是EJB QL的一种扩展,它是针对实体的一种查询语言,操作对象是实体,而不是关系数据库的表,而且能够支持批量更新和修改、JOIN、GROUP BY、HAVING 等通常只有 SQL 才能够提供的高级查询特性,甚至还能够支持子查询。
高级特性
JPA 中能够支持面向对象的高级特性,如类之间的继承、多态和类之间的复杂关系,这样的支持能够让开发者最大限度的使用面向对象的模型设计企业应用,而不需要自行处理这些特性在关系数据库的持久化。
四、JPA的基本操作
1.搭建环境的过程
①创建maven工程,导入坐标
资料来自bill bill用户:Cappuccinoべ
<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>6.0.0.Alpha7</version> </dependency> <!-- c3p0 --> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-c3p0</artifactId> <version>6.0.0.Alpha8</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>8.0.22</version> </dependency> </dependencies>
②配置JPA的核心配置文件
位置:配置到类路径下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:事务管理的方式 JTA:分布式事务管理 RESOURCE_LOCAL:本地事务管理 --> <persistence-unit name="myjpa" transaction-type="RESOURCE_LOCAL"> <!--jpa的实现方式--> ><provider>org.hibernate.jpa.HibernatePersistenceProvider</provider> <properties> <!--数据库信息 mysql方言:org.hibernate.dialect.MySQLDialect 用户名:javax.persistence.jdbc.user 密码:javax.persistence.jdbc.password 驱动:javax.persistence.jdbc.driver 数据库地址:javax.persistence.jdbc.url --> <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/> <property name="javax.persistence.jdbc.user" value="root"/> <property name="javax.persistence.jdbc.password" value="abc1234."/> <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/> <property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/jpa?useSSl=false&requireSSL=false&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai"/> <!--(可选的配置)配置jpa实现方的配置信息 显示sql,false/true 自动创建数据库表, create:程序运行时创建数据库表(如果有表,先删除再创建) update:程序运行时创建表(如果有表不会创建表) none:不会创建表 --> <property name="hibernate.show_sql" value="true"/> <property name="hibernate.hbm2ddl.auto" value="create"/> </properties> </persistence-unit> </persistence>
③编写客户实体类
配置映射关系
1.实体类和表的映射关
@Entity:声明此类是实体类
@Table:配置实体类中的映射关系
name:配置数据库表的名称
2.实体类中属性和表中package cn.Itcast.domain; /* * 客户实体类 * */ public class Customer { private Long custId;//客户主键 private String custName;//客户名称 private String custSource;//客户来源 private String custLevel;//客户级别 private String custIndustry;//客户所属行业 private String custPhone;//客户的联系方式 private String custAddress;//客户地址 //省略setter、getter和toString方法 }
④配置实体类和表、类中属性和表中字段的映射关系(重要)
客户实体类
配置映射关系
1.实体类和表的映射关系
@Entity:声明此类是实体类
@Table:配置实体类中的映射关系
name:配置数据库表的名称
2.实体类中属性和表中字段的映射关系
@Id:声明主键的配置
@GeneratedValue:配置主键的生成策略
GenerationType.IDENTITY:自增(底层数据库必须支持自增,如mysql)
GenerationType.SEQUENCE:序列(底层数据库必须支持序,如Oracle)
GenerationType.TABLE:jpa提供的一种机制,通过一张数据库表的形式完成主键自增
GenerationType.AUTO:程序自动的帮助我们选择主键生成策略
@Column:配置属性和字段的映射关系
name:数据库表中字段的名称package cn.Itcast.domain; import javax.persistence.*; @Entity @Table(name = "cst_customer") public class Customer { @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_level") private String custLevel;//客户级别 @Column(name = "cust_industry") private String custIndustry;//客户所属行业 @Column(name = "cust_phone") private String custPhone;//客户的联系方式 @Column(name = "cust_address") private String custAddress;//客户地址 //省略setter、getter和toString方法 }
⑤保存客户到数据库中
JPA的操作步骤:
1.加载配置文件创工厂(实体管理类工厂)对象
2.通过实体管理类工厂获取实体管理器
3.获取事务对象,开启事务
4.完成增删改查
5.提交事务(回滚事务)
6.释放资源
package cn.Itcast.test; import cn.Itcast.domain.Customer; import org.junit.Test; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.EntityTransaction; import javax.persistence.Persistence; 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("传智播客"); customer.setCustIndustry("教育"); em.persist(customer);//保存操作 /*5.提交事务(回滚事务)*/ tx.commit(); /*6.释放资源*/ em.close(); factory.close(); } }
输出结果:
Hibernate: drop table if exists cst_customer
Hibernate: create table cst_customer (cust_id bigint not null auto_increment, cust_address varchar(255), cust_industry varchar(255), cust_level varchar(255), cust_name varchar(255), cust_phone varchar(255), cust_source varchar(255), primary key (cust_id)) engine=InnoDB
Hibernate: insert into cst_customer (cust_address, cust_industry, cust_level, cust_name, cust_phone, cust_source) values (?, ?, ?, ?, ?, ?)
2.完成基本的CRUD案例(增删改查)
工具类
解决实体管理器工厂的浪费资源和耗时问题:
通过静态代码块的形式,当程序第一次访问此工具类时,
创建一个公共的实体管理器工厂对象。流程:
第一次访问getEntityManager方法:经过静态代码块创建一个factory对象,再调用EntityManager对象。
第二次访问getEntityManager方法:直接通过一个已经创建好的factory对象,调用EntityManager对象。package cn.Itcast.utils; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.Persistence; public class JpaUtils { private static EntityManagerFactory factory; static { /*1.加载配置文件创工厂(实体管理类工厂)对象*/ factory=Persistence.createEntityManagerFactory("myjpa"); } /*获取EntityManager对象*/ public static EntityManager getEntityManager(){ return factory.createEntityManager(); } }
public class JpaTest { @Test public void testSave(){ //通过工具类获取EntityManager 对象 EntityManager em= JpaUtils.getEntityManager(); /*3.获取事务对象,开启事务*/ EntityTransaction tx=em.getTransaction();//获取事务对象 tx.begin();//开启事务 /*4.完成增删改查*/ Customer customer=new Customer(); customer.setCustName("传智播客"); customer.setCustIndustry("教育"); em.persist(customer);//保存操作 /*5.提交事务(回滚事务)*/ tx.commit(); /*6.释放资源*/ em.close(); } }
find():根据id查询数据 //立即加载
1.查询的对象就是当前客户对象本身
2.在调用find方法的时候,就会发送sql语句查询数据库class属性:查询数据的结果需要包装的实体类类型的字节码
id属性:查询到主键的取值/* 根据id查询客户 */ @Test public void testFind(){ //1.通过工具类获取EntityManager对象 EntityManager entityManager=JpaUtils.getEntityManager(); //2.开启事务 EntityTransaction tx=entityManager.getTransaction();//获取事务对象 tx.begin();//开启事务 //3.增删改查 /* find:根据id查询数据 class:查询数据的结果需要包装的实体类类型的字节码 id:查询到主键的取值 */ Customer customer=entityManager.find(Customer.class,1l); System.out.println(customer); //4.提交事务 tx.commit(); //5.释放资源 entityManager.close(); }
getReference():根据id查询客户//延迟加载(懒加载)
1.获取的对象是一个动态代理对象
2.调用getReference不会立即发送sql语句查询数据
当调用查询结果对象的时候,才会发送查询的sql语句,
即什么时候用什么时候发送sql语句查询数据库class属性:查询数据的结果需要包装的实体类类型的字节码
id属性:查询到主键的取值@Test public void testReference(){ //1.通过工具类获取EntityManager对象 EntityManager entityManager=JpaUtils.getEntityManager(); //2.开启事务 EntityTransaction tx=entityManager.getTransaction();//获取事务对象 tx.begin();//开启事务 //3.增删改查 Customer customer=entityManager.getReference(Customer.class,1l); System.out.println(customer); //4.提交事务 tx.commit(); //5.释放资源 entityManager.close(); }
remove():根据id查询信息,再根据返回的对象删除信息
@Test public void testRemove(){ //1.通过工具类获取EntityManager对象 EntityManager entityManager=JpaUtils.getEntityManager(); //2.开启事务 EntityTransaction tx=entityManager.getTransaction();//获取事务对象 tx.begin();//开启事务 //3.增删改查 //根据id查询客户 Customer customer=entityManager.getReference(Customer.class,1l); //再调用remove方法完成删除操作 if (customer!=null){ entityManager.remove(customer); } //4.提交事务 tx.commit(); //5.释放资源 entityManager.close(); }
merge():用于在使用setter方法更新数据后,发送更新
属性T:传入已更新数据的对象@Test public void testUpdate(){ //1.通过工具类获取EntityManager对象 EntityManager entityManager=JpaUtils.getEntityManager(); //2.开启事务 EntityTransaction tx=entityManager.getTransaction();//获取事务对象 tx.begin();//开启事务 //3.增删改查 //根据id查询客户 Customer customer=entityManager.getReference(Customer.class,2l); //再将更新客户 customer.setCustIndustry("it教育"); //调用方法发送更新 entityManager.merge(customer); //4.提交事务 tx.commit(); //5.释放资源 entityManager.close(); }
测试jpql查询
查询全部:
jpql:from 全限定名称;
sql:select * from 表名;package cn.Itcast.test; import cn.Itcast.domain.Customer; import cn.Itcast.utils.JpaUtils; import org.junit.Test; import javax.persistence.EntityManager; import javax.persistence.EntityTransaction; import javax.persistence.Query; import java.util.List; public class JpqlTest { @Test public void testFindAll(){ //1.通过工具类获取EntityManager对象 EntityManager entityManager=JpaUtils.getEntityManager(); //2.开启事务 EntityTransaction tx=entityManager.getTransaction();//获取事务对象 tx.begin();//开启事务 //3.增删改查 String jpql= "from cn.Itcast.domain.Customer"; //创建Query查询对象,query对象才是执行jqpl的对象 Query query= entityManager.createQuery(jpql); //发送查询并封装结果集 List list=query.getResultList(); for (Object object:list){ System.out.println(object); } //4.提交事务 tx.commit(); //5.释放资源 entityManager.close(); } }
jpql排序查询:
根据id倒序查询全部:
jpql:from 全限定名称 order by 字段 desc;
sql:select * from 表名 order by 字段 desc;@Test public void testOrders(){ //1.通过工具类获取EntityManager对象 EntityManager entityManager=JpaUtils.getEntityManager(); //2.开启事务 EntityTransaction tx=entityManager.getTransaction();//获取事务对象 tx.begin();//开启事务 //3.增删改查 String jpql= "from cn.Itcast.domain.Customer order by custId desc"; //创建Query查询对象,query对象才是执行jqpl的对象 Query query= entityManager.createQuery(jpql); //发送查询并封装结果集 List list=query.getResultList(); for (Object object:list){ System.out.println(object); } //4.提交事务 tx.commit(); //5.释放资源 entityManager.close(); }
jpql统计查询:
jpql:select COUNT(字段) from 全限定名称;
sql:select count(字段) from 表名;@Test public void testCount(){ //1.通过工具类获取EntityManager对象 EntityManager entityManager=JpaUtils.getEntityManager(); //2.开启事务 EntityTransaction tx=entityManager.getTransaction();//获取事务对象 tx.begin();//开启事务 //3.增删改查 String jpql= "select COUNT(custId) from cn.Itcast.domain.Customer"; //创建Query查询对象,query对象才是执行jqpl的对象 Query query= entityManager.createQuery(jpql); //发送查询并封装结果集 /* getResultList:直接将查询结果封装为list集合 getSingleResult:得到唯一的结果集 */ Object result=query.getSingleResult(); System.out.println(result); //4.提交事务 tx.commit(); //5.释放资源 entityManager.close(); }
jpql分页查询:
jpql:from 全限定名称;
sql:select * from 表名 limit ?,?;@Test public void testPaged(){ //1.通过工具类获取EntityManager对象 EntityManager entityManager=JpaUtils.getEntityManager(); //2.开启事务 EntityTransaction tx=entityManager.getTransaction();//获取事务对象 tx.begin();//开启事务 //3.增删改查 String jpql= "from cn.Itcast.domain.Customer"; //创建Query查询对象,query对象才是执行jqpl的对象 Query query= entityManager.createQuery(jpql); //对分页参数赋值 query.setFirstResult(1);//起始索引 query.setMaxResults(2);//每页查询的条数 //发送查询并封装结果集 List list=query.getResultList(); for (Object object:list){ System.out.println(object); } //4.提交事务 tx.commit(); //5.释放资源 entityManager.close(); }
jpql条件查询:
查询以“传智播客”开头的客户
jpql:from 全限定名称 where 字段 like ?;
sql:select * from 表名 where 字段 like '传智播客%';@Test public void testCondition(){ //1.通过工具类获取EntityManager对象 EntityManager entityManager=JpaUtils.getEntityManager(); //2.开启事务 EntityTransaction tx=entityManager.getTransaction();//获取事务对象 tx.begin();//开启事务 //3.增删改查 String jpql= "from cn.Itcast.domain.Customer where custName like ?1"; //创建Query查询对象,query对象才是执行jqpl的对象 Query query= entityManager.createQuery(jpql); //对占位符参数赋值 query.setParameter(1,"传智播客%");//第一个参数:占位符的索引位置;第二个参数:取值 //发送查询并封装结果集 List list=query.getResultList(); for (Object object:list){ System.out.println(object); } //4.提交事务 tx.commit(); //5.释放资源 entityManager.close(); }