📒 程序员小王的博客:(https://www.wolai.com/wnaghengjie/ahNwvAUPG2Hb1Sy7Z8waaF)
🎉 欢迎点赞 👍 收藏 ⭐留言 📝
😊 如有编辑错误联系作者,如果有比较好的文章欢迎分享给我,我会取其精华去其糟粕
一、ORM思想
1、原始JDBC操作数据库出现的问题
-
操作繁琐
-
占位符赋值麻烦
2、JDBC问题解决思路
-
操作繁琐 就将jdbc封装到工具类
-
占位符值麻烦
1. 建立实体类和表的关系
2. 建立实体类中属性和表中字段的关系
3、ORM思想
-
ORM(Object-Relational Mapping) 表示对象关系映射。在面向对象的软件开发中,通过ORM,就可以把对象映射到关系型数据库中。只要有一套程序能够做到建立对象与数据库的关联,操作对象就可以直接操作数据库数据,就可以说这套程序实现了ORM对象关系映射
-
简单的说:ORM就是建立实体类和数据库表之间的关系,从而达到操作实体类就相当于操作数据库表的目的。
-
主要目的: 操作实体类就相当于操作数据库表
-
建立两个映射关系:
实体类和表的映射关系 实体类中属性和表中字段的映射关系
-
当实现一个应用程序时(不使用O/R Mapping),我们可能会写特别多数据访问层的代码,从数据库保存数据、修改数据、删除数据,而这些代码都是重复的。而使用ORM则会大大减少重复性代码。对象关系映射(Object Relational Mapping,简称ORM),主要实现程序对象到关系数据库数据的映射。
-
实现ORM的框架:Mybatis,Hirbernate
二、实现ORM思想的框架Hirbernate介绍
-
Hibernate是一个开放源代码的对象关系映射框架
-
它对JDBC进行了非常轻量级的对象封装,
-
它将POJO(java实体类对象)与数据库表建立映射关系,是一个全自动的orm框架
-
hibernate可以自动生成SQL语句,自动执行,使得Java程序员可以随心所欲的使用对象编程思维来操纵数据库。
三、JPA规范
JPA的全称是Java Persistence API, 即Java 持久化API,是SUN公司推出的一套基于ORM的规范,内部是由一系列的接口和抽象类构成。
JPA通过JDK 5.0注解描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中。
-
JPA是一套规范,实现JPA规范,内部由接口和抽象类组成
-
JDBC规范和JPA规范比较
四、JPA的基本操作(CRUD)
1、案例:添加一个客户到数据库的客户表中。
-
客户:就是一家公司
2、搭建环境
(1)创建maven工程导入依赖
-
创建项目jpa_basic
-
导入依赖
由于JPA
是sun公司制定的API规范,所以我们不需要导入额外的JPA相关的jar包,只需要导入JPA的提供商的jar包。我们选择Hibernate作为JPA的提供商,所以需要导入Hibernate的相关jar包。
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<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>8.0.27</version>
</dependency>
</dependencies>
(2)需要配置jpa的核心配置文件
-
配置到类路径下的一个叫做META-INF的文件夹下
-
创建文件吗,命名:persistence.xml
-
导入约束 选择约束模板
选择persistence_2.xml版本
将模板的约束复制放入MEAT_INFO文件下的persistence.xml中
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0">
</persistence>
-
配置persistence-unit节点(持久化单元)
- name:持久化单元名称
- transaction-type:事务管理方式
Jta:分布式事务管理
Resource_Local:本地事务管理
- Provider:jpa的实现方式
- 数据库信息
- 可选配置:配置jpa实现方式的配置信息
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0">
<!--1.配置persistence-unit节点(持久化单元)
transaction-type:事务管理方式
Jta:分布式事务管理
Resource_Local:本地事务管理
-->
<persistence-unit name="my_jpa" transaction-type="RESOURCE_LOCAL">
<!--jpa的实现方式-->
<!--数据库信息-->
<!--可选配置,配置jpa实现方的配置信息-->
</persistence-unit>
</persistence>
(3)编写客户数据库表(cust_customer)和实体类(customer)
-
顾客的数据库表
CREATE TABLE cust_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;
-
实体类(customer)并配置实体类和表,类中的属性和表字段成一一对应关系
/**
* @author 王恒杰
* @date 2022/2/21 9:47
* @Description:
*/
@Entity //声明实体类
@Table(name = "cust_customer") //建立实体类和表的映射关系
public class Customer implements Serializable {
@Id //声明私有属性为主键
@GeneratedValue(strategy= GenerationType.IDENTITY) //配置主键的生成策略
@Column(name = "cust_id")
private Long custId;
@Column(name = "cust_name")
private String custName;
@Column(name = "custSource")
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 Customer() {
}
public Customer(Long custId, String custName, String custSource, String custIndustry, String custLevel, String custAddress, String custPhone) {
this.custId = custId;
this.custName = custName;
this.custSource = custSource;
this.custIndustry = custIndustry;
this.custLevel = custLevel;
this.custAddress = custAddress;
this.custPhone = 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;
}
@Override
public String toString() {
return "Customer{" +
"custId=" + custId +
", custName='" + custName + '\'' +
", custSource='" + custSource + '\'' +
", custIndustry='" + custIndustry + '\'' +
", custLevel='" + custLevel + '\'' +
", custAddress='" + custAddress + '\'' +
", custPhone='" + custPhone + '\'' +
'}';
}
}
(5)配置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">
<!--1.配置persistence-unit节点(持久化单元)
transaction-type:事务管理方式
Jta:分布式事务管理
Resource_Local:本地事务管理
-->
<persistence-unit name="myJpa" transaction-type="RESOURCE_LOCAL">
<!--jpa的实现方式 配置JPA规范的服务提供商 -->
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<!--数据库信息-->
<properties>
<!--数据库驱动-->
<property name="javax.persistence.jdbc.driver" value="com.mysql.cj.jdbc.Driver"/>
<!--数据库地址-->
<property name="javax.persistence.jdbc.url"
value="jdbc:mysql://localhost:3306/customer?serverTimezone=UTC"/>
<!--数据库名-->
<property name="javax.persistence.jdbc.user" value="root"/>
<!--数据库密码-->
<property name="javax.persistence.jdbc.password" value="root"/>
<!--可选配置,配置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"/>
</properties>
</persistence-unit>
</persistence>
(6)测试类·实现添加操作
/**
* @author 王恒杰
* @date 2022/2/21 11:32
* @Description:
*/
public class InsertCustomerTest{
public static void main(String[] args) {
/**
* 创建实体管理类工厂,借助Persistence的静态方法获取
* 其中传递的参数为持久化单元名称,需要jpa配置文件中指定
*/
EntityManagerFactory factory = Persistence.createEntityManagerFactory("myJpa");
//创建实体管理类
EntityManager em = factory.createEntityManager();
//获取事务对象
EntityTransaction tx = em.getTransaction();
//开启事务
tx.begin();
Customer c = new Customer();
c.setCustName("王恒杰");
c.setCustAddress("天津商业大学");
c.setCustPhone("15120308630");
//保存操作
em.persist(c);
//提交事务
tx.commit();
//释放资源
em.close();
factory.close();
}
}
五、JPA中的主键生成策略
通过annotation
(注解)来映射hibernate实体的,基于annotation的hibernate主键标识为@Id, 其生成规则由@GeneratedValue
(生成值)设定的.这里的@id
和@GeneratedValue
都是JPA的标准用法。
JPA提供的四种标准用法为TABLE,SEQUENCE(sequence),IDENTITY(identity),AUTO(auto)。
具体说明如下:
1、IDENTITY:主键由数据库自动生成(主要是自动增长型)
用法:
@Id //声明私有属性为主键
@GeneratedValue(strategy= GenerationType.IDENTITY) //配置主键的生成策略
@Column(name = "cust_id")
private Long custId;
2、SEQUENCE:根据底层数据库的序列来生成主键,条件是数据库支持序列。
用法:
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE,generator="payablemoney_seq")
@SequenceGenerator(name="payablemoney_seq", sequenceName="seq_payment")
private Long custId;
//@SequenceGenerator源码中的定义
@Target({TYPE, METHOD, FIELD})
@Retention(RUNTIME)
public @interface SequenceGenerator {
//表示该表主键生成策略的名称,它被引用在@GeneratedValue中设置的“generator”值中
String name();
//属性表示生成策略用到的数据库序列名称。
String sequenceName() default "";
//表示主键初识值,默认为0
int initialValue() default 0;
//表示每次主键值增加的大小,例如设置1,则表示每次插入新记录后自动加1,默认为50
int allocationSize() default 50;
}
3、AUTO:主键由程序控制
用法:
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long custId;
4、TABLE:使用一个特定的数据库表格来保存主键
用法:
@Id
@GeneratedValue(strategy = GenerationType.TABLE, generator="payablemoney_gen")
@TableGenerator(name = "pk_gen",
table="tb_generator",
pkColumnName="gen_name",
valueColumnName="gen_value",
pkColumnValue="PAYABLEMOENY_PK",
allocationSize=1
)
private Long custId;
//@TableGenerator的定义:
@Target({TYPE, METHOD, FIELD})
@Retention(RUNTIME)
public @interface TableGenerator {
//表示该表主键生成策略的名称,它被引用在@GeneratedValue中设置的“generator”值中
String name();
//表示表生成策略所持久化的表名,例如,这里表使用的是数据库中的“tb_generator”。
String table() default "";
//catalog和schema具体指定表所在的目录名或是数据库名
String catalog() default "";
String schema() default "";
//属性的值表示在持久化表中,该主键生成策略所对应键值的名称。例如在“tb_generator”中将“gen_name”作为主键的键值
String pkColumnName() default "";
//属性的值表示在持久化表中,该主键当前所生成的值,它的值将会随着每次创建累加。例如,在“tb_generator”中将“gen_value”作为主键的值
String valueColumnName() default "";
//属性的值表示在持久化表中,该生成策略所对应的主键。例如在“tb_generator”表中,将“gen_name”的值为“CUSTOMER_PK”。
String pkColumnValue() default "";
//表示主键初识值,默认为0。
int initialValue() default 0;
//表示每次主键值增加的大小,例如设置成1,则表示每次创建新记录后自动加1,默认为50。
int allocationSize() default 50;
UniqueConstraint[] uniqueConstraints() default {};
}
//这里应用表tb_generator,定义为 :
CREATE TABLE tb_generator (
id NUMBER NOT NULL,
gen_name VARCHAR2(255) NOT NULL,
gen_value NUMBER NOT NULL,
PRIMARY KEY(id)
)
六、JPA的API介绍
1、 Persistence对象
Persistence对象主要作用是用于获取EntityManagerFactory对象的 。通过调用该类的createEntityManagerFactory静态方法,根据配置文件中持久化单元名称创建EntityManagerFactory。
@Test
public void test(){
/**
* 1、创建EntityManagerFactory
*/
String unitName="myJpa";
EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory(unitName);
}
2、EntityManagerFactory
EntityManagerFactory 接口主要用来创建 EntityManager 实例
/**
* 2、创建实体管理类
* EntityManagerFactory 接口主要用来创建 EntityManager 实例
*/
EntityManager entityManager = entityManagerFactory.createEntityManager();
注意: 由于EntityManagerFactory
是一个线程安全的对象(即多个线程访问同一个EntityManagerFactory
对象不会有线程安全问题),并且EntityManagerFactory
的创建极其浪费资源,所以在使用JPA编程时,我们可以对EntityManagerFactory
的创建进行优化,只需要做到一个工程只存在一个EntityManagerFactory
即可
3、EntityManager
在 JPA 规范中, EntityManager
是完成持久化操作的核心对象。实体类作为普通 java对象,只有在调用 EntityManager将其持久化后才会变成持久化对象。EntityManager对象在一组实体类与底层数据源之间进行 O/R 映射的管理。它可以用来管理和更新 Entity Bean, 根椐主键查找 Entity Bean, 还可以通过JPQL语句查询实体。
我们可以通过调用EntityManager的方法完成获取事务,以及持久化数据库的操作
方法说明:
GetTransaction : 获取事务对象
Persist : 保存操作
Merge : 更新操作
Remove : 删除操作
Find/GetReference : 根据id查询
-
实现代码
/**
* 3、entityManager相关操作
*
* 1.GetTransaction : 获取事务对象
* 2.Persist(坚持) : 保存操作
* 3.Merge (合并): 更新操作
* 4.Remove(删除) : 删除操作
* 5.Find/GetReference(查找/获取引用) : 根据id查询
*/
//获取事务对象
EntityTransaction transaction = entityManager.getTransaction();
//开启事务
transaction.begin();
//提交事务·
transaction.commit();
//回滚事务
transaction.rollback();
//添加操作
entityManager.persist();
//更新操作
entityManager.merge();
//删除操作
entityManager.remove();
//查询操作
entityManager.find();
4、EntityTransaction
在 JPA 规范中, EntityTransaction是完成事务操作的核心对象,对于EntityTransaction在我们的java代码中承接的功能比较简单
//获取事务对象
EntityTransaction transaction = entityManager.getTransaction();
//开启事务
transaction.begin();
//提交事务·
transaction.commit();
//回滚事务
transaction.rollback();
七、JPA的工具类 JpaUtil
1、工具类JpaUtil
/**
* @author 王恒杰
* @date 2022/2/21 13:19
* @Description:
*/
public class JpaUtil {
/**
* Jpa的实体类管理工具:相当于Hirbernate的SessionFactory
*/
private static EntityManagerFactory em;
//静态代码块赋值
static {
//注意:该方法参数必须和persistence.xml中persistence-unit标签name属性取值一致
em = Persistence.createEntityManagerFactory("myJpa");
}
/**
* 使用管理器工厂生产一个管理器对象
* @return 管理器对象
*/
public static EntityManager getEntityManager() {
EntityManager entityManager = em.createEntityManager();
return entityManager;
}
}
2、使用工具类实现添加操作
/**
* 使用工具类实现添加操作
*/
@Test
public void test() {
//1.获取事务对象
EntityManager entityManager = JpaUtil.getEntityManager();
EntityTransaction transaction = entityManager.getTransaction();
//2.开启事务
transaction.begin();
Customer customer = new Customer(null, "天津以琳快讯科技有限公司", "58同城", "IT行业", "1级别", "古城创业大厦", "123456");
//3.添加操作
entityManager.persist(customer);
//4.提交事务·
transaction.commit();
//5.关闭资源
entityManager.close();
}
-
底层实现的Sql语句
insert into
cust_customer
(cust_Address, cust_industry, cust_level, cust_name, cust_phone, custSource)
values (?, ?, ?, ?, ?, ?)
八、使用JPA完成增删改查操作
1、添加数据
/**
* @author 王恒杰
* @date 2022/2/21 10:13
* @Description:
*/
public class JpaTest {
/**
* 使用工具类实现添加操作
*/
@Test
public void InsertCustomer() {
//1.获取事务对象
EntityManager entityManager = JpaUtil.getEntityManager();
EntityTransaction transaction = entityManager.getTransaction();
//2.开启事务
transaction.begin();
Customer customer = new Customer(null, "天津商业大学", "今日校园", "教育", "、特殊级别", "天津北辰天穆镇", "8888888");
//3.添加操作
entityManager.persist(customer);
//4.提交事务·
transaction.commit();
//5.关闭资源
entityManager.close();
}
}
-
底层实现Sql语句
insert into
cust_customer
(cust_Address, cust_industry, cust_level, cust_name, cust_phone, cust_Source)
values (?, ?, ?, ?, ?, ?)
2、修改数据(先查询出来再修改)
/**
* 修改数据
*/
@Test
public void update() {
//1. 获取实体类管理器
EntityManager entityManager = JpaUtil.getEntityManager();
//获取事务
EntityTransaction transaction = entityManager.getTransaction();
//开启事务
transaction.begin();
//查询出来需要修改的数据 id=5
Customer customer = entityManager.find(Customer.class, 5L);
// 修改id=5 的顾客 地址为贵州省遵义市播州区
customer.setCustAddress("贵州省遵义市播州区");
//修改数据
Customer merge = entityManager.merge(customer);
System.out.println("数据修改成功后数据" + merge);
// 提交事务
transaction.commit();
//关闭链接
entityManager.close();
}
-
底层实现的SQL语句
update cust_customer
set cust_Address=?, cust_industry=?, cust_level=?, cust_name=?, cust_phone=?, cust_Source=?
where cust_id=?
3、查询数据
(1)根据id查询,使用立即加载的策略
@Test
public void selectCustomerById(){
EntityManager entityManager = JpaUtil.getEntityManager();
EntityTransaction transaction = entityManager.getTransaction();
transaction.begin();
//查询id=5的顾客
Customer customer = entityManager.find(Customer.class, 5l);
System.out.println(customer);
}
(2)查询实体的缓存问题
@Test
public void selectCustomerById() {
EntityManager entityManager = JpaUtil.getEntityManager();
EntityTransaction transaction = entityManager.getTransaction();
transaction.begin();
//查询id=5的顾客
Customer customer1 = entityManager.find(Customer.class, 5l);
Customer customer2 = entityManager.find(Customer.class, 5l);
// 输出结果是true,EntityManager也有缓存
System.out.println(customer1==customer2);
}
(3)延迟加载策略的方法:Reference
@Test
public void selectCustomerByIdAndReference() {
EntityManager entityManager = JpaUtil.getEntityManager();
EntityTransaction transaction = entityManager.getTransaction();
transaction.begin();
//查询id=5的顾客
Customer customer1 = entityManager.getReference(Customer.class,5L);
// 输出结果是true,EntityManager也有缓存
System.out.println(customer1);
}
4、删除数据
/**
* 删除数据
*/
@Test
public void deleteCustomer() {
EntityManager entityManager = JpaUtil.getEntityManager();
EntityTransaction transaction = entityManager.getTransaction();
transaction.begin();
//查询id=5的顾客
Customer customer= entityManager.getReference(Customer.class, 5L);
//删除
entityManager.remove(customer);
//提交事务
transaction.commit();
//关闭资源
entityManager.close();
}
-
实现Sql语句
delete from cust_customer where cust_id=?