1. 配置JPA环境
- maven工程导入坐标:
```xml
UTF-8 5.0.7.Final
- 配置 JPA 的核心配置文件- 位置:配置到类路径下的一个叫做 META-INF 的文件夹下- 命名:persistence.xml```xml<?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/jpaTest" /><!-- 数据库用户名 --><property name="javax.persistence.jdbc.user" value="root" /><!-- 数据库密码 --><property name="javax.persistence.jdbc.password" value="123456" /><!-- Hibernate特有的配置 --><!-- 在 console 打印生成的sql --><property name="hibernate.show_sql" value="true" /><!-- Pretty print the SQL in the log and console. --><property name="hibernate.format_sql" value="true" /><!-- 自动创建数据库表 : hibernate.hbm2ddl.autocreate : 程序运行时创建数据库表(如果有表,先删除表再创建)update :程序运行时创建数据库表(如果有表,不会创建表)none :不会创建表 --><property name="hibernate.hbm2ddl.auto" value="create" /></properties></persistence-unit></persistence>
创建客户的数据库表
/*创建客户表*/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=InnoDBAUTO_INCREMENT=1DEFAULT CHARSET=utf8;
创建客户实体类
public class Customer implements Serializable {private Long custId;private String custName;private String custSource;private String custLevel;private String custIndustry;private String custPhone;private String custAddress;// getter setter and toString}
配置实体类和表的映射关系:
@Entity@Table(name = "cst_customer")public class Customer implements Serializable {....}
配置字段和表的映射关系:
配置主键
@Id@GeneratedValue(strategy = GenerationType.AUTO)@Column(name = "cust_id")private Long custId;
其他属性,直接使用@Column
@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;
实现保存操作:
public class JPATest {/*** 保存一个客户到数据库中*/@Testpublic void saveCustomerTest(){//1.加载配置文件创建 EntityManagerFactoryEntityManagerFactory factory = Persistence.createEntityManagerFactory("myJpa");//2.根据实体管理器工厂 EntityManagerFactory,创建实体管理器 EntityManagerEntityManager entityManager = factory.createEntityManager();//3.创建事务对象,开启事务EntityTransaction transaction = entityManager.getTransaction();//获取事务对象transaction.begin();//开启事务//4.增删改查操作: 保存一个客户到数据库中Customer customer = new Customer();customer.setCustName("IBM");customer.setCustAddress("Canada");customer.setCustIndustry("IT");//保存entityManager.persist(customer);//5.提交事务transaction.commit();//6.释放资源entityManager.close();factory.close();}}
查看 Console Output: ```java Hibernate: drop table if exists cst_customer Hibernate: drop table if exists hibernate_sequence Hibernate: create table cst_customer (
cust_id bigint not null,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)
) Hibernate: create table hibernate_sequence (
next_val bigint
) Hibernate: insert into hibernate_sequence values ( 1 ) Hibernate: select
next_val as id_val
from
hibernate_sequence for update
Hibernate: update hibernate_sequence set next_val= ? where next_val=? Hibernate: insert into cst_customer (cust_address, cust_industry, cust_level, cust_name, cust_phone, cust_source, cust_id) values (?, ?, ?, ?, ?, ?, ?)
<a name="xZs9k"></a># 2. JPA的基本操作<a name="DhFHZ"></a>## A. JPA 核心配置1. *位置:配置到类路径下的一个叫做 META-INF 的文件夹下<br />*命名:persistence.xml1. 在 persistence.xml 中配置数据库连接信息:```xml<!-- 数据库驱动 --><property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver" /><!-- 数据库地址 --><property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/jpaTest" /><!-- 数据库用户名 --><property name="javax.persistence.jdbc.user" value="root" /><!-- 数据库密码 --><property name="javax.persistence.jdbc.password" value="123456" />
c. 配置Hibernate的特定配置
<!-- 在 console 打印生成的sql --><property name="hibernate.show_sql" value="true" /><!-- Pretty print the SQL in the log and console. --><property name="hibernate.format_sql" value="true" /><!-- 自动创建数据库表 : hibernate.hbm2ddl.autocreate : 程序运行时创建数据库表(如果有表,先删除表再创建)update :程序运行时创建表(如果有表,不会创建表)none :不会创建表 --><property name="hibernate.hbm2ddl.auto" value="update" />
B. JPA 注解
- 实体类和表的映射:
@Entity- 指定当前类是实体类。@Table- 指定实体类和表之间的对应关系。
属性:name- 指定数据库表的名称
- 主键字段的映射:
@Id- 声明主键的配置@GeneratedValue- 配置主键的生成策略
属性:strategy- GenerationType.IDENTITY :自增,mysql
底层数据库必须支持自动增长(底层数据库支持的自动增长方式,对id自增) - GenerationType.SEQUENCE : 序列,oracle
底层数据库必须支持序列 - GenerationType.TABLE : jpa提供的一种机制,通过在数据库中建立一个 table hibernate_sequences, 来记录自增主键。
- GenerationType.IDENTITY :自增,mysql

- GenerationType.AUTO : 由程序自动的帮助我们选择主键生成策略 ==> 一般会选择TABLE
普通字段的映射:
加载配置文件, 创建 EntityMnagerFactory
Persisitence:静态方法(根据持久化单元名称创建实体管理器工厂)
createEntityMnagerFactory() EntityManagerFactory factory = Persistence.createEntityManagerFactory("myJpa");- EntityMnagerFactory内部维护的很多的内容:
- 内部维护了数据库信息,
- 维护了缓存信息
- 维护了所有的实体管理器对象
- 在创建EntityManagerFactory的过程中会根据配置创建数据库表
- EntityManagerFactory的创建过程比较浪费资源:
- 特点:线程安全的对象
多个线程访问同一个EntityManagerFactory不会有线程安全问题 - 如何解决创建浪费的问题?
通过静态代码块的形式,当程序第一次访问此工具类时,创建一个公共的实体管理器工厂对象 ```java /*
- 特点:线程安全的对象
- 第一次访问getEntityManager方法:经过静态代码块创建一个factory对象,再调用方法创建一个EntityManager对象
- 第二次方法getEntityManager方法:直接通过一个已经创建好的factory对象,创建EntityManager对象 */ public class JpaUtils { private static EntityManagerFactory factory; static { factory = Persistence.createEntityManagerFactory(“myJpa”); }
public static EntityManager getEntityManager() { return factory.createEntityManager(); }
public static void closeFactory(){ factory.close(); } }
`` b. 创建实体管理器 EntityManager<br />EntityManager em = factory.createEntityManager();`
EntityManager对象:实体类管理器:- getTransaction(): 创建事务对象
- presist(): 保存
- merge(): 更新
- remove(): 删除
- find/getRefrence(): 根据id查询
c. 创建事务对象,开启事务EntityTransaction tx = em.getTransaction(); //获取事务对象tx.begin();//开启事务
Transaction 对象 :
- begin():开启事务- commit():提交事务- rollback():回滚
d. 增删改查操作
e. 提交事务:tx.commit()
f. 释放资源:em.close()factory.close() //通过调用 JpaUtils 关闭
D. JPA相关操作的基本语法 - 增删改查
查询:
- T find(T, id)
- getReference方法:延迟加载
- 1.获取的对象是一个动态代理对象
- 2.调用getReference方法不会立即发送sql语句查询数据库
- 3.当调用查询结果对象的时候(System.out.println(customer);),才会发送查询的sql语句
@Testpublic void findCustomer(){EntityManager entityManager = JpaUtils.getEntityManger();EntityTransaction tx = em.getTransaction();tx.begin();// select * from customer where id = xxxCustomer customer = entityManager.find(Customer.class, 1L);//Customer customer = entityManager.getReference(Customer.class, 1L);tx.commit();entityManager.close();System.out.println(customer);}
添加:entityManager.persist(obj)
Customer customer = new Customer();customer.setCustName("传智播客");customer.setCustIndustry("教育");entityManager.persist(customer); //保存操作
删除:entityManager.remove(obj)
entityManager.remove(customer);
更新:entityManager.merge(customer)
customer.setCustIndustry("it教育");entityManager.merge(customer);
E. JPQL查询
JPQL 是 JPA 提供一种查询语言。
sql:查询的是表和表中的字段。
- jpql:Java Persistence Query Language, 查询的是实体类和类中的属性, jpql和sql语句的语法相似。
写码思路:
- 创建query查询对象: String jpql = “from Customer where custName like ? “; Query query = em.createQuery(jpql);
- 对参数进行赋值: query.setParameter(1,”传智播客%”);
- 第一个参数:占位符的索引位置(从1开始)
- 第二个参数:取值
查询,并得到返回结果:
- List list = query.getResultList() : 直接将查询结果封装为list集合
- Object obj = query.getSingleResult() : 得到唯一的结果集
1. 查询全部:
```java /**
测试jqpl查询 */ public class JpqlTest {
/**
- 查询全部
- jqpl:from cn.itcast.domain.Customer
sql:SELECT FROM cst_customer / @Test public void testFindAll() { //1.获取entityManager对象 EntityManager em = JpaUtils.getEntityManager(); //2.开启事务 EntityTransaction tx = em.getTransaction(); tx.begin(); //3.查询全部 String jpql = “from Customer “; Query query = em.createQuery(jpql);//创建Query查询对象,query对象才是执行jqpl的对象
//发送查询,并封装结果集 List list = query.getResultList();
for (Object obj : list) { System.out.print(obj); }
//4.提交事务 tx.commit(); //5.释放资源 em.close(); } } ```
2. 排序查询:倒序
```java /**
- 排序查询: 倒序查询全部客户(根据id倒序)
- sql:SELECT * FROM cst_customer ORDER BY cust_id DESC
jpql:from Customer order by custId desc */ @Test public void testOrders() { //1.获取entityManager对象 EntityManager em = JpaUtils.getEntityManager(); //2.开启事务 EntityTransaction tx = em.getTransaction(); tx.begin(); //3.查询全部 String jpql = “from Customer order by custId desc”; Query query = em.createQuery(jpql);//创建Query查询对象,query对象才是执行jqpl的对象
//发送查询,并封装结果集 List list = query.getResultList();
for (Object obj : list) { System.out.println(obj); }
//4.提交事务 tx.commit(); //5.释放资源 em.close(); }
```3. 条件查询
```java /**
- 条件查询
- 案例:查询客户名称以‘传智播客’开头的客户
- sql:SELECT * FROM cst_customer WHERE cust_name LIKE ?
jpql : from Customer where custName like ? */ @Test public void testCondition() { //1.获取entityManager对象 EntityManager em = JpaUtils.getEntityManager(); //2.开启事务 EntityTransaction tx = em.getTransaction(); tx.begin(); //3.查询全部 //i.根据jpql语句创建Query查询对象 String jpql = “from Customer where custName like ? “; Query query = em.createQuery(jpql); //ii.对参数赋值 — 占位符参数 //第一个参数:占位符的索引位置(从1开始),第二个参数:取值 query.setParameter(1,”传智播客%”);
//iii.发送查询,并封装结果
/**
- getResultList : 直接将查询结果封装为list集合
- getSingleResult : 得到唯一的结果集 */ List list = query.getResultList();
for(Object obj : list) { System.out.println(obj); }
//4.提交事务 tx.commit(); //5.释放资源 em.close(); } ```
4. 统计查询
如果使用SQL的统计函数,JPQL可以使用
select count(*) from ...```java /**- 使用jpql查询,统计客户的总数
- sql:SELECT COUNT(cust_id) FROM cst_customer
jpql:select count(custId) from Customer */ @Test public void testCount() { //1.获取entityManager对象 EntityManager em = JpaUtils.getEntityManager(); //2.开启事务 EntityTransaction tx = em.getTransaction(); tx.begin(); //3.查询全部 //i.根据jpql语句创建Query查询对象 String jpql = “select count(custId) from Customer”; Query query = em.createQuery(jpql); //ii.对参数赋值 //iii.发送查询,并封装结果
/**
- getResultList : 直接将查询结果封装为list集合
- getSingleResult : 得到唯一的结果集 */ Object result = query.getSingleResult();
System.out.println(result);
//4.提交事务 tx.commit(); //5.释放资源 em.close(); } ```
5. 分页查询
```java /**
- 分页查询
- sql:select * from cst_customer limit ?,? (如果只有?就意味着从 0 开始查找?条数据)
jqpl : from Customer */ @Test public void testPaged() { //1.获取entityManager对象 EntityManager em = JpaUtils.getEntityManager(); //2.开启事务 EntityTransaction tx = em.getTransaction(); tx.begin(); //3.查询全部 //i.根据jpql语句创建Query查询对象 String jpql = “from Customer”; Query query = em.createQuery(jpql); //ii.对参数赋值 — 分页参数 //起始索引 query.setFirstResult(0); //每页查询的条数 query.setMaxResults(2);
//iii.发送查询,并封装结果 List list = query.getResultList();
for(Object obj : list) { System.out.println(obj); }
//4.提交事务 tx.commit(); //5.释放资源 em.close(); } ```
