·SpringDataJpa
第一 orm思想
主要目的:操作实体类就相当于操作数据库表
建立两个映射关系:
实体类和表的映射关系
实体类中属性和表中字段的映射关系
不再重点关注:sql语句
实现了ORM思想的框架:mybatis,hibernate
第二 hibernate框架介绍
Hibernate是一个开放源代码的对象关系映射框架,
它对JDBC进行了非常轻量级的对象封装,
它将POJO与数据库表建立映射关系,是一个全自动的orm框架
第三 JPA规范
jpa规范,实现jpa规范,内部是由接口和抽象类组成
第四 jpa的基本操作
案例:是客户的相关操作(增删改查)
客户:就是一家公司
客户表:
jpa操作的步骤:
(1)导入依赖
<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)创建客户的数据库表和客户的实体类
1.创建客户的数据库表
/创建客户表/
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;
2. 创建客户的实体类
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;
//getter , setter
}
(3)编写实体类和数据库表的映射配置[重点]
1.在实体类上使用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;
//getter , setter
}
注意(常见的注解的说明)
@Entity
作用:指定当前类是实体类。
@Table
作用:指定实体类和表之间的对应关系。
属性:
name:指定数据库表的名称
@Id
作用:指定当前字段是主键。
@GeneratedValue
作用:指定主键的生成方式。。
属性:
strategy :指定主键生成策略。
@Column
作用:指定实体类属性和数据库表之间的对应关系
属性:
name:指定数据库表的列名称。
unique:是否唯一
nullable:是否可以为空
inserttable:是否可以插入
updateable:是否可以更新
columnDefinition: 定义建表时创建此列的DDL
secondaryTable: 从表名。如果此列不建在主表上(默认建在主表),该属性定义该列所在从表的名字搭建开发环境[重点]
(4)配置JPA的核心配置文件
在java工程的src路径下resources下创建一个名为META-INF的文件夹,在此文件夹下创建一个名为persistence.xml的配置文件
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>
<!--可选配置:配置jpa实现方的配置信息-->
<properties>
<!-- 数据库信息
用户名,javax.persistence.jdbc.user
密码, javax.persistence.jdbc.password
驱动, javax.persistence.jdbc.driver
数据库地址 javax.persistence.jdbc.url
-->
<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
自动创建数据库表 : hibernate.hbm2ddl.auto
create : 程序运行时创建数据库表(如果有表,先删除表再创建)
update :程序运行时创建表(如果有表,不会创建表)
none :不会创建表
-->
<property name="hibernate.show_sql" value="true" />
<property name="hibernate.hbm2ddl.auto" value="update" />
<property name="hibernate.format_sql" value="true" />
</properties>
</persistence-unit>
</persistence>
(5)实现保存操作
@Test
public void test() {
/**
* 测试jpa的保存
* 案例:保存一个客户到数据库中
* Jpa的操作步骤
* 1.加载配置文件创建工厂(实体管理器工厂)对象
* 2.通过实体管理器工厂获取实体管理器
* 3.获取事务对象,开启事务
* 4.完成增删改查操作
* 5.提交事务(回滚事务)
* 6.释放资源
*/
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();
}
JPA中的主键生成策略
/**
- 客户的实体类
-
配置映射关系
- 1.实体类和表的映射关系
-
@Entity:声明实体类
-
@Table : 配置实体类和表的映射关系
-
name : 配置数据库表的名称
- 2.实体类中属性和表中字段的映射关系
*/
@Entity
@Table(name = "cst_customer")
public class Customer {
/**
* @Id:声明主键的配置
* @GeneratedValue:配置主键的生成策略
* strategy
* GenerationType.IDENTITY :自增,mysql
* * 底层数据库必须支持自动增长(底层数据库支持的自动增长方式,对id自增)
* GenerationType.SEQUENCE : 序列,oracle
* * 底层数据库必须支持序列
*(了解) GenerationType.TABLE : jpa提供的一种机制,通过一张数据库表的形式帮助我们完成主键自增
*(了解) GenerationType.AUTO : 由程序自动的帮助我们选择主键生成策略
* @Column:配置属性和字段的映射关系
* name:数据库表中字段的名称
*/
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "cust_id")
private Long custId; //客户的主键 UUID-在hibernate中可以配置
@Column(name = "cust_name")
private String custName;//客户名称
@Column(name="cust_source")
// @Transient
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;//客户地址
jpa操作的操作步骤
1.加载配置文件创建实体管理器工厂
Persisitence:静态方法(根据持久化单元名称创建实体管理器工厂)
createEntityMnagerFactory(持久化单元名称)
作用:创建实体管理器工厂
例:
Persisitence.createEntityMnagerFactory(“myJpa”);
2.根据实体管理器工厂,创建实体管理器
EntityManagerFactory :获取EntityManager对象
方法:createEntityManager
例:
factory.createEntityManager();
* 内部维护的很多的内容
内部维护了数据库信息,
维护了缓存信息
维护了所有的实体管理器对象
再创建EntityManagerFactory的过程中会根据配置创建数据库表
* EntityManagerFactory的创建过程比较浪费资源
特点:线程安全的对象
多个线程访问同一个EntityManagerFactory不会有线程安全问题
* 如何解决EntityManagerFactory的创建过程浪费资源(耗时)的问题?
思路:创建一个公共的EntityManagerFactory的对象
* 静态代码块的形式创建EntityManagerFactory
3.创建事务对象,开启事务
EntityManager对象:实体类管理器
beginTransaction : 创建事务对象
presist : 保存
merge : 更新
remove : 删除
find/getRefrence : 根据id查询
根据id查询客户
getReference方法
1.获取的对象是一个动态代理对象
2.调用getReference方法不会立即发送sql语句查询数据库
* 当调用查询结果对象的时候,才会发送查询的sql语句:什么时候用,什么时候发送sql语句查询数据库
延迟加载(懒加载)
* 得到的是一个动态代理对象
* 什么时候用,什么使用才会查询
Transaction 对象 : 事务
begin:开启事务
commit:提交事务
rollback:回滚
4.增删改查操作
5.提交事务
6.释放资源
示例1:
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();
示例2:
Customer c = new Customer();
c.setCustName("传智学院");
EntityManager em = null;
EntityTransaction tx = null;
try {
// 获取实体管理对象
em = JpaUtils.getEntityManager();
// 获取事务对象
tx = em.getTransaction();
// 开启事务
tx.begin();
// 执行操作
em.persist(c);
// 提交事务
tx.commit();
} catch (Exception e) {
// 回滚事务
tx.rollback();
e.printStackTrace();
} finally {
// 释放资源
em.close();
}
JpaUtils
这是为了创建一个可以重复使用的工厂,使用时不在需要释放工厂资源,但是实体管理器对象资源需要关闭。
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
/**
* 解决实体管理器工厂的浪费资源和耗时问题
* 通过静态代码块的形式,当程序第一次访问此工具类时,创建一个公共的实体管理器工厂对象
*执行逻辑 :
* 第一次访问getEntityManager方法:经过静态代码块创建一个factory对象,再调用方法创建一个EntityManager对象
* 第二次方法getEntityManager方法:直接通过一个已经创建好的factory对象,创建EntityManager对象
*/
public class JpaUtils {
private static EntityManagerFactory factory;
static {
//1.加载配置文件,创建entityManagerFactory
factory = Persistence.createEntityManagerFactory("myJpa");
}
/**
* 获取EntityManager对象
*/
public static EntityManager getEntityManager() {
return factory.createEntityManager();
}
}
JPA中的复杂查询
JPQL全称Java Persistence Query Language基于首次在EJB2.0中引入的EJB查询语言(EJB QL),
Java持久化查询语言(JPQL)是一种可移植的查询语言,旨在以面向对象表达式语言的表达式,
将SQL语法和简单查询语义绑定在一起·使用这种语言编写的查询是可移植的,可以被编译成所有主流数据库服务器上的SQL。
其特征与原生SQL语句类似,并且完全面向对象,通过类名和属性访问,而不是表名和表的属性。
jpql使用的传入的参数是实体类中的属性,而sql中传入的数据是数据库中的字段值;
(1)查询全部
sql: select * from Customer;
jpql: from Customer;
//查询所有客户
@Test
public void findAll() {
EntityManager em = null;
EntityTransaction tx = null;
try {
//获取实体管理对象
em = JPAUtil.getEntityManager();
//获取事务对象
tx = em.getTransaction();
tx.begin();
// 创建query对象
String jpql = "from Customer";
Query query = em.createQuery(jpql);
// 查询并得到返回结果(直接将查询结果封装成list集合)
List list = query.getResultList(); // 得到集合返回类型
for (Object object : list) {
System.out.println(object);
}
tx.commit();
} catch (Exception e) {
// 回滚事务
tx.rollback();
e.printStackTrace();
} finally {
// 释放资源
em.close();
}
}
(2)分页查询
sql:
jpql:
//分页查询客户
@Test
public void findPaged () {
EntityManager em = null;
EntityTransaction tx = null;
try {
//获取实体管理对象
em = JPAUtil.getEntityManager();
//获取事务对象
tx = em.getTransaction();
tx.begin();
//创建query对象
String jpql = "from Customer";
Query query = em.createQuery(jpql);
//起始索引
query.setFirstResult(0);
//每页显示条数
query.setMaxResults(2);
//查询并得到返回结果
List list = query.getResultList(); //得到集合返回类型
for (Object object : list) {
System.out.println(object);
}
tx.commit();
} catch (Exception e) {
// 回滚事务
tx.rollback();
e.printStackTrace();
} finally {
// 释放资源
em.close();
}
}
(3)条件查询
sql: select * from Customer where cst_Name like ?;
jpql: from Customer where custName like ? ;
//条件查询
@Test
public void findCondition () {
EntityManager em = null;
EntityTransaction tx = null;
try {
//获取实体管理对象
em = JPAUtil.getEntityManager();
//获取事务对象
tx = em.getTransaction();
tx.begin();
//创建query对象
String jpql = "from Customer where custName like ? ";
Query query = em.createQuery(jpql);
//对占位符赋值,从1开始
query.setParameter(1, "传智播客%");
//查询并得到返回结果
Object object = query.getSingleResult(); //得到唯一的结果集对象
System.out.println(object);
tx.commit();
} catch (Exception e) {
// 回滚事务
tx.rollback();
e.printStackTrace();
} finally {
// 释放资源
em.close();
}
}
(4)排序查询
sql: select * from Customer order by cst_Id desc;
jpql: from Customer order by custId desc;
//根据客户id倒序查询所有客户
//查询所有客户
@Test
public void testOrder() {
EntityManager em = null;
EntityTransaction tx = null;
try {
//获取实体管理对象
em = JPAUtil.getEntityManager();
//获取事务对象
tx = em.getTransaction();
tx.begin();
// 创建query对象
String jpql = "from Customer order by custId desc";
Query query = em.createQuery(jpql);
// 查询并得到返回结果
List list = query.getResultList(); // 得到集合返回类型
for (Object object : list) {
System.out.println(object);
}
tx.commit();
} catch (Exception e) {
// 回滚事务
tx.rollback();
e.printStackTrace();
} finally {
// 释放资源
em.close();
}
}
(5)统计查询
sql: select count(cst_Id) from Customer;
jpql:select count(custId) from Customer:
@Test
public void findCount() {
EntityManager em = null;
EntityTransaction tx = null;
try {
//获取实体管理对象
em = JPAUtil.getEntityManager();
//获取事务对象
tx = em.getTransaction();
tx.begin();
// 查询全部客户
// 1.创建query对象
String jpql = "select count(custId) from Customer";
Query query = em.createQuery(jpql);
// 2.查询并得到返回结果
Object count = query.getSingleResult(); // 得到集合返回类型
System.out.println(count);
tx.commit();
} catch (Exception e) {
// 回滚事务
tx.rollback();
e.printStackTrace();
} finally {
// 释放资源
em.close();
}
}