ORM思想
-
ORM(Object-Relational Mapping) 表示对象关系映射。在面向对象的软件开发中,通过ORM,就可以把对象映射到关系型数据库中。只要有一套程序能够做到建立对象与数据库的关联,操作对象就可以直接操作数据库数据,就可以说这套程序实现了ORM对象关系映射
简单的说:ORM就是建立实体类和数据库表之间的关系,从而达到操作实体类就相当于操作数据库表的目的。 -
主要目的:操作实体类就像操作数据库表
-
建立两个映射关系;
- 实体类和表的映射关系
- 实体类中属性和表中字段的映射关系
-
不在重点关注sql语句
-
实现了ORM思想的框架:Mybatis,hibernate,Jpa等
JPA概述
- JPA的全称是Java Persistence API, 即Java 持久化API,是SUN公司推出的一套基于ORM的规范,内部是由一系列的接口和抽象类构成。类似于JDBC规范
- JPA规范本质上就是一种ORM规范,注意不是ORM框架——因为JPA并未提供ORM实现,它只是制订了一些规范,提供了一些编程的API接口,但具体实现则由服务厂商来提供实现。
JPA的入门案例
本案例使用Hibernate演示JPA
-
JPA与hibernate的关系
- JPA和Hibernate的关系就像JDBC和JDBC驱动的关系,JPA是规范,Hibernate除了作为ORM框架之外,它也是一种JPA实现。JPA怎么取代Hibernate呢?JDBC规范可以驱动底层数据库吗?答案是否定的,也就是说,如果使用JPA规范进行数据库操作,底层需要hibernate作为其实现类完成数据持久化工作。
- JPA和Hibernate的关系就像JDBC和JDBC驱动的关系,JPA是规范,Hibernate除了作为ORM框架之外,它也是一种JPA实现。JPA怎么取代Hibernate呢?JDBC规范可以驱动底层数据库吗?答案是否定的,也就是说,如果使用JPA规范进行数据库操作,底层需要hibernate作为其实现类完成数据持久化工作。
-
一.导入相关jar包
- 1.官方下载地址 http://sourceforge.net/projects/hibernate/files/hibernate-orm/5.0.7.Final/
- 2.Maven坐标
<!-- hibernate对jpa的支持包 --> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-entitymanager</artifactId> <version>${project.hibernate.version}</version> </dependency>
- 1.官方下载地址 http://sourceforge.net/projects/hibernate/files/hibernate-orm/5.0.7.Final/
-
二. 创建客户的数据库表和客户的实体类并配置映射关系以及get/set方法
import javax.persistence.*;
/**
* 客户实体类
* 配置映射关系
* 1.实体类和表的映射关系
* @Entity //声明此类是一个实体类
* @Table(name="cst_customer") //配置实体类和表的映射关系
* name属性配置数据库表的名称
* 2.实体类属性和表中字段的映射关系
*/
@Entity //声明此类是一个实体类
@Table(name="cst_customer") //配置实体类和表的映射关系 name属性配置数据库表的名称
public class Customer {
/**
* @Id :声明主键的配置
* @GeneratedValue :配置主键的生成策略
* GenerationType.IDENTITY:自增
* 底层数据库必须支持自增
* GenerationType.SEQUENCE:序列 oracle
* 底层数据库必须支持序列
* GenerationType.TABLE: jpa提供的一种机制,通过一张数据库表的形式帮助我们完成主键递增
* GenerationType.AUTO :由程序自动帮助我们选择生成策略
* @Column :配置数据库表字段和属性的映射关系
* name:数据库表中字段的名称
*/
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "cust_id")
private Long custId; //客户ID
@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; //客户联系方式
public Long getCustId() {
return custId;
}
public void setCustId(Long custId) {
this.custId = custId;
}
public String getCustName() {
return custName;
}
public void setCustName(String custName) {
this.custName = custName;
}
public String getCustSource() {
return custSource;
}
public void setCustSource(String custSource) {
this.custSource = custSource;
}
public String getCustIndustry() {
return custIndustry;
}
public void setCustIndustry(String custIndustry) {
this.custIndustry = custIndustry;
}
public String getCustLevel() {
return custLevel;
}
public void setCustLevel(String custLevel) {
this.custLevel = custLevel;
}
public String getCustAddress() {
return custAddress;
}
public void setCustAddress(String custAddress) {
this.custAddress = custAddress;
}
public String getCustPhone() {
return custPhone;
}
public void setCustPhone(String custPhone) {
this.custPhone = custPhone;
}
}
常用注解说明
@Entity
作用:指定当前类是实体类。
@Table
作用:指定实体类和表之间的对应关系。
属性:
name:指定数据库表的名称
@Id
作用:指定当前字段是主键。
@GeneratedValue
作用:指定主键的生成方式。。
属性:
strategy :指定主键生成策略。
@Column
作用:指定实体类属性和数据库表之间的对应关系
属性:
name:指定数据库表的列名称。
unique:是否唯一
nullable:是否可以为空
inserttable:是否可以插入
updateable:是否可以更新
columnDefinition: 定义建表时创建此列的DDL
secondaryTable: 从表名。如果此列不建在主表上(默认建在主表),该属性定义该列所在从表的名字搭建开发环境[重点]
- 三.配置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: 事务管理(jpa:分布式事务 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>
<property name="javax.persistence.jdbc.password" value="123456"></property>
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"></property>
<property name="javax.persistence.jdbc.url" value="jdbc:mysql:///study"></property>
<!-- 配置jpa实现方式(hibernate)的配置信息
显示sql :hibernate.show_sql false|true
自动创建数据库表 : hibernate.hbm2ddl.auto
create: 程序运行时创建数据库表(如果有表先删除表在创建)
update: 程序运行时创建表(如果有表不会创建表)
none: 不会创建表
-->
<property name="hibernate.show_sql" value="true"></property>
<property name="hibernate.hbm2ddl.auto" value="update"></property>
</properties>
</persistence-unit>
</persistence>
- 四.JPA的操作步骤
- JPA的操作步骤
- 1.加载配置文件创建实体管理器工厂
- Persistence静态方法createEntityManagerFactory(“持久化单元名称”)(根据持久化单元名称创建实体管理器工厂)
- 作用:创建实体管理器工厂
- 2.根据实体管理器工厂,创建实体管理器
- EntityManagerFactory:获取 EntityManager
- 方法:createEntityManager()
- 内部维护了很多内容
- 内部维护了数据库信息
- 维护了缓存信息
- 维护了所有的实体管理器对象
- 在创建EntityManagerFactory的过程中会根据配置创建数据库表
- EntityManagerFactory的创建过程比较浪费资源
- 特点 线程安全的对象
- 多个线程访问同一个EntityManagerFactory不会有线程安全问题
- 解决创建过程浪费资源:静态代码块的形式创建EntityManagerFactory
- 3.创建事务对象,开启事务
- EntityManager对象:实体类管理器
- beginTransaction:创建事务对象
- presist:保存
- merge:更新
- remove:删除
- find/getRefrence:根据Id查询
- Transaction 对象:事务
- begin:开启事务
- commit 提交事务
- rollback:回滚事务
- EntityManager对象:实体类管理器
- 4.增删改查操作
- 5.提交事务
- 6.释放资源
- 1.加载配置文件创建实体管理器工厂
- 五.测试方法
- 测试保存方法
@Test
public void testSave(){
/* //1.加载配置文件创建工厂(实体管理类)对象
EntityManagerFactory factory = Persistence.createEntityManagerFactory("myjpa");
//2.通过实体管理类工厂获取实体管理器
EntityManager entityManager = factory.createEntityManager();*/
EntityManager entityManager = JpaUtils.getEntityManager();
//3.获取事务对象,开启事务
EntityTransaction tx = entityManager.getTransaction();
tx.begin();//开启事务
//4.完成增删改查操作
Customer customer = new Customer();
customer.setCustName("小明");
customer.setCustIndustry("架构师");
//保存
entityManager.persist(customer);//保存操作
//5.提交事务
tx.commit();
//6.释放资源
entityManager.close();
//factory.close();
}
- Find查询方法
@Test
public void testFind(){
//1.通过工具类获取EntityManager
EntityManager entityManager = JpaUtils.getEntityManager();
//2.开启事务
EntityTransaction tx = entityManager.getTransaction();
tx.begin();
//3增删改查(根据Id查询客户)
/**
* find 根据Id查询客户
* class:查询数据的结果需要包装的实体类类型字节码
* id:查询的主键的取值
*/
Customer customer = entityManager.find(Customer.class, 1l);
//Customer customer = entityManager.getReference(Customer.class,1L);
System.out.println(customer);
//4.提交事务
tx.commit();
//5.释放资源
entityManager.close();
}
- getReference方法查询
@Test
public void testReference(){
//1.通过工具类获取EntityManager
EntityManager entityManager = JpaUtils.getEntityManager();
//2.开启事务
EntityTransaction tx = entityManager.getTransaction();
tx.begin();
//3增删改查(根据Id查询客户)
/**
* find 根据Id查询客户
* class:查询数据的结果需要包装的实体类类型字节码
* id:查询的主键的取值
*/
// Customer customer = entityManager.find(Customer.class, 1l);
Customer customer = entityManager.getReference(Customer.class, 1l);
System.out.println(customer);
//4.提交事务
tx.commit();
//5.释放资源
entityManager.close();
}
- 更新和删除方法
@Test
public void testRemove(){
//1.通过工具类获取EntityManager
EntityManager entityManager = JpaUtils.getEntityManager();
//2.开启事务
EntityTransaction tx = entityManager.getTransaction();
tx.begin();
//3增删改查(根据Id查询客户)
//i 根据id查询客户
//调用remove方法完成删除操作
Customer customer = entityManager.find(Customer.class, 1l);
entityManager.remove(customer);
//4.提交事务
tx.commit();
//5.释放资源
entityManager.close();
}
@Test
public void testUpdata(){
//1.通过工具类获取EntityManager
EntityManager entityManager = JpaUtils.getEntityManager();
//2.开启事务
EntityTransaction tx = entityManager.getTransaction();
tx.begin();
//3增删改查(根据Id查询客户)
//客户的更新操作
//i查询客户
Customer customer = entityManager.find(Customer.class, 2l);
//ii 更新客户
customer.setCustIndustry("高级开发工程师");
entityManager.merge(customer);
//4.提交事务
tx.commit();
//5.释放资源
entityManager.close();
}
getReference和find方法的区别
- 使用find方法查询(立即加载)
- 1.查询的对象就是当前客户对象本身
- 2.在调用find方法的时候,就会发送sql语句,查询数据库
- 使用getRefrence方法
- 1.获取的对象是一个动态代理对象
- 2.调用不会立即发送sql语句查询数据库(延迟加载/懒加载)
- 3.当调用查询结果对象的时候,才会发送sql语句查询数据库(什么时候用,什么时候发送sql语句查询)
- 4.得到的是一个动态代理对象