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.auto
create : 程序运行时创建数据库表(如果有表,先删除表再创建)
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=InnoDB
AUTO_INCREMENT=1
DEFAULT 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 {
/**
* 保存一个客户到数据库中
*/
@Test
public void saveCustomerTest(){
//1.加载配置文件创建 EntityManagerFactory
EntityManagerFactory factory = Persistence.createEntityManagerFactory("myJpa");
//2.根据实体管理器工厂 EntityManagerFactory,创建实体管理器 EntityManager
EntityManager 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.xml
1. 在 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.auto
create : 程序运行时创建数据库表(如果有表,先删除表再创建)
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语句
@Test
public void findCustomer(){
EntityManager entityManager = JpaUtils.getEntityManger();
EntityTransaction tx = em.getTransaction();
tx.begin();
// select * from customer where id = xxx
Customer 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(); } ```