黑马程序员技术交流社区

标题: 【广州校区】【原创】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