黑马程序员技术交流社区
标题:
【广州校区】【原创】springdata jpa
[打印本页]
作者:
wuwei丶
时间:
2019-8-22 14:13
标题:
【广州校区】【原创】springdata jpa
##### 入门
* 导入依赖
```
<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>
```
* 创建数据库表
```
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;
```
* ==编写实体类和数据库表的映射配置[重点]==
```
import javax.persistence.*;
import java.io.Serializable;
@Entity // 声明实体类是JPA的ORM类
@Table(name = "cst_customer") // 指定该类与哪个表映射
public class Customer implements Serializable {
@Id // 指定主键
@Column(name = "cust_id") // 指定映射的列
@GeneratedValue(strategy = GenerationType.IDENTITY) // 配置主键的生成策略
private Long custId;
@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;
"setter and getter methods"
}
```
* 常用注解的说明
* @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"
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/test"/>
<!-- 数据库用户名 -->
<property name="javax.persistence.jdbc.user" value="root"/>
<!-- 数据库密码 -->
<property name="javax.persistence.jdbc.password" value="root"/>
<!--jpa提供者的可选配置:我们的JPA规范的提供者为hibernate,所以jpa的核心配置中兼容hibernate的配 -->
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.format_sql" value="true"/>
<property name="hibernate.hbm2ddl.auto" value="create"/>
</properties>
</persistence-unit>
</persistence>
```
```
@Test
public void test01() {
// 创建实体管理类工厂,借助Persistence的静态方法获取
// 其中传递的参数为持久化单元名称,需要jpa配置文件中指定
EntityManagerFactory facotry = Persistence.createEntityManagerFactory("myJpa");
// 创建实体管理类
EntityManager manager = facotry.createEntityManager();
// 获取事务对象
EntityTransaction tx = manager.getTransaction();
// 开启事务
tx.begin();
// 保存数据
Customer customer = new Customer();
customer.setCustName("余浩宏");
manager.persist(customer);
// 提交事务
tx.commit();
// 释放资源
manager.close();
facotry.close();
}
```
###### JPA中的主键生成策略
* 键标识为@Id, 其生成规则由@GeneratedValue设定的
* JPA提供的四种标准用法为TABLE,SEQUENCE,IDENTITY,AUTO
1. IDENTITY:主键由数据库自动生成(主要是自动增长型)
```
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long custId;
```
2. SEQUENCE:根据底层数据库的序列来生成主键,条件是数据库支持序列
```
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE,generator="payablemoney_seq")
@SequenceGenerator(name="payablemoney_seq", sequenceName="seq_payment")
private Long custId;
```
3. AUTO:主键由程序控制
```
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long custId;
```
4. TABLE:使用一个特定的数据库表格来保存主键
```
@Id
@GeneratedValue(strategy = GenerationType.TABLE, generator="payablemoney_gen")
@TableGenerator(name = "payablemoney_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介绍
* Persistence对象
* Persistence对象主要作用是用于获取EntityManagerFactory对象的
```
EntityManagerFactory factory= Persistence.createEntityManagerFactory(unitName);
```
* EntityManagerFactory
* EntityManagerFactory 接口主要用来创建 EntityManager 实例
* 由于EntityManagerFactory 是一个线程安全的对象
* 并且EntityManagerFactory 的创建极其浪费资源
* 所以在使用JPA编程时,只需要做到一个工程只存在一个EntityManagerFactory 即可
```
EntityManager em = factory.createEntityManager();
```
* EntityManager
* EntityManager是完成持久化操作的核心对象
* 实体类作为普通 java对象,只有在调用 EntityManager将其持久化后才会变成持久化对象
* EntityManager对象在一组实体类与底层数据源之间进行 O/R 映射的管理
* 我们可以通过调用EntityManager的方法完成获取事务,以及持久化数据库的操作
```
getTransaction : 获取事务对象
persist : 保存操作
merge : 更新操作
remove : 删除操作
find/getReference : 根据id查询
```
* EntityTransaction
* EntityTransaction是完成事务操作的核心对
```
begin:开启事务
commit:提交事务
rollback:回滚事务
```
###### 抽取JPAUtil工具类
```
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
public class JPAUtil {
// JPA的实体管理器工厂
private static EntityManagerFactory em;
// 使用静态代码块赋值
static {
// 注意:该方法参数必须和persistence.xml中persistence-unit标签name属性取值一致
em = Persistence.createEntityManagerFactory("myJpa");
}
// 使用管理器工厂生产一个管理器对象
public static EntityManager getEntityManager() {
return em.createEntityManager();
}
}
```
###### 使用JPA完成增删改查操作
* 添加
```
@Test
public void testAdd() {
Customer customer = new Customer();
customer.setCustName("余浩宏");
customer.setCustLevel("VIP");
customer.setCustSource("电线杆");
customer.setCustIndustry("咸鱼");
customer.setCustAddress("广州市天河区");
customer.setCustPhone("888888");
EntityManager em = null;
EntityTransaction tx = null;
try {
em = JPAUtil.getEntityManager();
tx = em.getTransaction();
tx.begin();
em.persist(customer);
tx.commit();
}catch (Exception ex) {
ex.printStackTrace();
if (tx != null) {
tx.rollback();
}
}finally {
em.close();
}
}
```
* 修改
```
@Test
public void testMerge() {
//定义对象
EntityManager em = null;
EntityTransaction tx = null;
try {
em = JPAUtil.getEntityManager();
tx = em.getTransaction();
tx.begin();
Customer customer = em.find(Customer.class, 2L);
customer.setCustName("余不懂");
em.clear();//把c1对象从缓存中清除出去
em.merge(customer);
tx.commit();
}catch (Exception ex) {
ex.printStackTrace();
if (tx != null) {
tx.rollback();
}
}finally {
if (em != null) {
em.close();
}
}
}
```
* 删除
```
@Test
public void testRemove() {
// 定义对象
EntityManager em = null;
EntityTransaction tx = null;
try {
// 获取实体管理对象
em = JPAUtil.getEntityManager();
// 获取事务对象
tx = em.getTransaction();
// 开启事务
tx.begin();
// 执行操作
Customer c1 = em.find(Customer.class, 1L);
em.remove(c1);
// 提交事务
tx.commit();
} catch (Exception e) {
// 回滚事务
tx.rollback();
e.printStackTrace();
} finally {
// 释放资源
em.close();
}
}
```
* 查询
```
public void testGetOne() {
EntityManager em = null;
EntityTransaction tx = null;
try {
em = JPAUtil.getEntityManager();
tx = em.getTransaction();
tx.begin();
Customer c1 = em.find(Customer.class, 1L);
tx.commit();
System.out.println(c1);
} catch (Exception e) {
tx.rollback();
e.printStackTrace();
} finally {
em.close();
}
}
```
```
@Test
public void testGetOne() {
EntityManager em = null;
EntityTransaction tx = null;
try {
em = JPAUtil.getEntityManager();
tx = em.getTransaction();
tx.begin();
Customer c1 = em.find(Customer.class, 1L);
Customer c2 = em.find(Customer.class, 1L);
System.out.println(c1 == c2);// 输出结果是true,EntityManager也有缓存
tx.commit();
System.out.println(c1);
} catch (Exception e) {
tx.rollback();
e.printStackTrace();
} finally {
em.close();
}
}
```
```
@Test
public void testLoadOne() {
EntityManager em = null;
EntityTransaction tx = null;
try {
em = JPAUtil.getEntityManager();
tx = em.getTransaction();
tx.begin();
Customer c1 = em.getReference(Customer.class, 1L);
tx.commit();
System.out.println(c1);
"com.study.springDataJpa.Customer@3b2c0e88"
"得到代理对象"
} catch (Exception e) {
tx.rollback();
e.printStackTrace();
} finally {
em.close();
}
}
```
###### JPA中的复杂查询
* JPQL全称Java Persistence Query Language
* 其特征与原生SQL语句类似,并且完全面向对象,通过类名和属性访问,而不是表名和表的属性
* 查询全部
```
@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<Customer> list = query.getResultList(); // 得到集合返回类型
for (Customer customer : list) {
System.out.println(customer.getCustName());
}
tx.commit();
} catch (Exception e) {
tx.rollback();
e.printStackTrace();
} finally {
em.close();
}
}
```
* 分页
```
@Test
public void findPaged () {
EntityManager em = null;
EntityTransaction tx = null;
try {
em = JPAUtil.getEntityManager();
tx = em.getTransaction();
tx.begin();
String jpql = "from Customer";
Query query = em.createQuery(jpql);
//起始索引
query.setFirstResult(0);
//每页显示条数
query.setMaxResults(2);
//查询并得到返回结果
List<Customer> list = query.getResultList(); //得到集合返回类型
for (Customer customer : list) {
System.out.println(customer.getCustName());
}
tx.commit();
} catch (Exception e) {
tx.rollback();
e.printStackTrace();
} finally {
em.close();
}
}
```
* 条件
```
@Test
public void findCondition() {
EntityManager em = null;
EntityTransaction tx = null;
try {
em = JPAUtil.getEntityManager();
tx = em.getTransaction();
tx.begin();
String jpql = "from Customer where custName like ? ";
Query query = em.createQuery(jpql);
//对占位符赋值,从1开始
query.setParameter(1, "余不%");
//查询并得到返回结果
Customer customer = (Customer) query.getSingleResult();
System.out.println(customer.getCustName());
tx.commit();
} catch (Exception e) {
tx.rollback();
e.printStackTrace();
} finally {
em.close();
}
}
```
* 排序查询
```
@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<Customer> list = query.getResultList(); // 得到集合返回类型
for (Customer customer : list) {
System.out.println(customer.getCustId() + " === " + customer.getCustName());
}
tx.commit();
} catch (Exception e) {
// 回滚事务
tx.rollback();
e.printStackTrace();
} finally {
// 释放资源
em.close();
}
}
```
* 统计查询
```
@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();
}
}
```
欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/)
黑马程序员IT技术论坛 X3.2