orm思想,hibernate,jpa

一:orm思想,hibernate,jpa概述,jpa基本操作

1.orm思想

  1. 回顾JDBC如何完成基本的保存操作
  • 操作繁琐

  • 需要挨个对占位符进行赋值,麻烦

    public class User{
    	private String userId;
    	private String userName;
    	private String address;
    	//省略setter,getter方法
    }
    
    create table t_user(
    	id int auto_increament,
    	username varchar,
    	address varchar
    )
    
    //SQL语句
    String sql="insert into t_user(username,address) values(?,?)";
    
    //1.过去连接
    Connection conn=DriverManager.getConnection(username,password,url)
    //2.创建statement对象
    PrepareStatement pst=conn.prepareStatement(sql); 
    //3.对占位符进行赋值
    pst.setString(1,user.getUserName())
    pst.setString(2,user.getAdress())
    //4.发送查询
    pst.executeUpdate();
    
  1. 如何解决传统JDBC中遇到的问题
    在这里插入图片描述

  2. 如何建立实体与表和实体属性与表中字段的关系 (QRM思想:即操作实体类相当于操作数据库表)

    • 实体类与表的映射关系
    • 实体类属性与数据库表字段的映射关系
      实现了orm思想的框架:mybatis,hibernate

2.实现啦orm思想的框架:hibernate

hibernate是一个开源的对象映射框架,它对JDBC进行了非常轻量级的封装,它将POJO与数据表建立映射厝没完成一个全自动的orm框架

3.JPA规范

jpa规范,实现jpa规范,内部是由接口和抽象类组成的(并不干活,干活的是每个狂阶的生产厂商,例如hibernate)
在这里插入图片描述
在这里插入图片描述

4.JPA基本操作

案例: 对客户的基本操作

  • 客户表:
DROP TABLE IF EXISTS `cst_customer`;

CREATE TABLE `cat_customer` (
  `cust_id` bigint(32) NOT NULL COMMENT '客戶编码',
  `cust_name` varchar(32) NOT NULL COMMENT '客户名称',
  `cust_source` varchar(32) DEFAULT NULL COMMENT '客户信息来源',
  `cust_industy` 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 DEFAULT CHARSET=utf8;

1. 搭建JPA环境的过程

1.1 创建Maven工程导入坐标
<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>

        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-c3p0</artifactId>
            <version>${project.hibernate.version}</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.6</version>
        </dependency>

        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>

    </dependencies>
1.2 配置JPA的核心配置文件

JPA 规范要求在类路径的 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:持久化单元名称指定 JPA  的事务处理策略
                JTA:分布式事务管理
                RESOURCE_LOCAL:本地事务管理

                RESOURCE_LOCAL:默认值,数据库级别的事务,只能针对一种数据库,不支持分布式事务。
                如果需要支持分布式事务,使用JTA:transaction-type="JTA"

        -->
    <persistence-unit name="myJpa" transaction-type="RESOURCE_LOCAL">

        <!--jpa的实现方式-->
        <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>

        <properties>
            <!--数据库信息:
                    用户名:javax.persistence.jdbc.user
                    密码:javax.persistence.jdbc.password
                    驱动:javax.persistence.jdbc.driver
                    数据库地址:javax.persistence.jdbc.url
            -->
            <property name="javax.persistence.jdbc.driver"  value="com.mysql.jdbc.Driver" />
            <property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3305/test"/>
            <property name="javax.persistence.jdbc.user" value="root" />
            <property name="javax.persistence.jdbc.password" value="mmwan980815" />


            <!--orm框架的基本信息:
                可选配置:jpa实现方(hibernate)的配置信息
                    hibernate.show_sql,:显示SQL,true|false
                    hibernate.hbm2ddl.auto:自动创建创建数据库表,
                        create:程序运行时创建数据库表(如果有表,先删除再创建)
                        update:程序运行时创建数据库表(如果有表,不会创建表)
                        none:不会创建表
            -->
            <property name="hibernate.hbm2ddl.auto" value="create"/>
            <property name="hibernate.show_sql" value="true"/>
            <property name="hibernate.format_sql" value="true"/>
        </properties>
    </persistence-unit>

</persistence>
1.3编写客户实体类
public class Customer {
    private Long custId;//客户主键
    private String custName;//客户名称
    private String custSource;//客户来源
    private String custLevel;//客户级别
    private String custIndustry;//客户所属行业
    private String custPhone;//客户电话
    private String custAddress;//客户地址
    
    //此处省略setter,getter,toString方法
}

1.4配置实体类和表,勒种属性和表中字段的映射关系

/**
 * 客户的实体类:
 *      配置映射关系
 *          1.实体类和表的映射关系
 *          @Entity:声明实体类
 *          @Table:配置实体类和表的映射关系
 *          2.实体类中属性和表中字段的映射关系
 */

@Entity
@Table(name ="cst_customer")
public class Customer {

    @Id//声明该属性对应数据库表中的主键
    @GeneratedValue(strategy = GenerationType.IDENTITY)//主键生成策略
    @Column(name ="cust_id")//配置属性和字段的映射关系
    private Long custId;//客户主键
    @Column(name = "cust_name")
    private String custName;//客户名称
    @Column(name = "cust_source")
    private String custSource;//客户来源
    @Column(name ="cust_industy" )
    private String custIndustry;//客户所属行业
    @Column(name = "cust_level")
    private String custLevel;//客户级别
    @Column(name = "cust_phone")
    private String custPhone;//客户电话
    @Column(name = "cust_address")
    private String custAddress;//客户地址
      
     //此处省略setter,getter,toString方法
}

2. 完成基本的CRUD

2.1案例+CRUD操作步骤

保存一个客户到数据库中

利用JPA进行CRUD的操作步骤:
1.加载配置文件创建工厂(实体管理器工厂)对象
2.通过实体管理类工厂获取实体管理器
3.获取事务对象,开启事务
4.完成增删改查操作
5.提交事务(回滚事务)
6.释放资源

public class JpaTest {

    @Test
    public void testSave(){
        //1.加载配置文件创建工厂(实体管理器工厂)对象
        EntityManagerFactory factory = Persistence.createEntityManagerFactory("myJpa");
        //2.通过实体管理类工厂获取实体管理器
        EntityManager manager = factory.createEntityManager();
        //3.获取事务对象,开启事务
        EntityTransaction tx = manager.getTransaction();//获取事务对象
        tx.begin();//开启事务
        Customer customer=new Customer();
        customer.setCustName("name");
        customer.setCustIndustry("industry");
        //4.完成增删改查操作
        manager.persist(customer);//保存操作
        // 5.提交事务(回滚事务)
        tx.commit();
        //6.释放资源(反向关闭)
        manager.close();
        factory.close();
    }
}

运行结果:
在这里插入图片描述

5.主键生成策略

strategy
1. GenerationType.IDENTITY:自增,数据库必须支持自增长得方式,对ID自增(mysql)
2. GenerationType.SEQUENCE:序列,数据库必须支持序列(Oracle)
3. GenerationType.TABLE:jpa提供的一种机制,通过一张数据库表的形式帮助我们完成主键自
4. GenerationType.AUTO:有程序自助帮我们选择主键生成策略

@Id//声明该属性对应数据库表中的主键
@GeneratedValue(strategy = GenerationType.IDENTITY)//主键生成策略
@Column(name ="cust_id")//配置属性和字段的映射关系

二:Jpa基本操作

1. jpa的操作步骤:

1.1加载配置文件创建工厂(实体管理器工厂)对象

Persistence的静态方法:
	createEntityManagerFactory(持久化单元名称)
	作用:创建实体管理器工厂

 EntityManagerFactory factory = Persistence.createEntityManagerFactory("myJpa");
  • 内部维护了数据信息,维护了缓存信息,维护了所有的实体管理器对象
  • 在创建EntityManagerFactory 的过程中会根据配置创建数据库表
  • EntityManagerFactory 的创建过程比较浪费资源
  • 特点:线程安全,多个线程同时访问同一个EntityManagerFactory 时不会出现线程安全的问题
  • 如何解决EntityManagerFactory 创建过程耗时的问题?
    思路:创建一个公共的EntityManagerFactory 对象

1.2.通过实体管理类工厂获取实体管理器

EntityManagerFactory :实体管理器工厂,用来获取/创建EntityManager (实体管理器)
	createEntityManager();
EntityManager manager = factory.createEntityManager();

1.3获取事务对象,开启事务

EntityManager 对象:实体类管理器
	persist():保存
	merge():更新
	remove():删除
	find()/getRefrence():根据id查询
Transaction 对象:事务
	begin():开启事务
	commit():提交事务
	rollback():回滚

1.4完成增删改查操作

1.5提交事务(回滚事务)

1.6释放资源

2.如何解决EntityManagerFactory 创建过程耗时的问题?

“1.1有提到EntityManagerFactory 的创建过程比较浪费资源,多个线程同时访问同一个EntityManagerFactory 时不会出现线程安全问题”,因此我们可以试着创建一个公共的EntityManagerFactory 对象

2.1 jpa工具类
/**
 *解决实体类管理器工厂的浪费资源和耗时问题
 *     通过静态代码块的执行,当程序第一次访问次工具类的时候,创建一个公共的实体管理器工厂
 * 第一次访问getEntityManager方法,经过静态代码块创建一个factory对象,在调用方法创建一个EntityManager对象
 * 第一次访问getEntityManager方法,直接通过已经创建好的factory对象,创建一个EntityManager对象
 */

//JPA工具类
public class JpaUtils {
    private static EntityManagerFactory factory;
     static {
         //1.加载配置文件,创建EntityManagerFactory工厂
         factory= Persistence.createEntityManagerFactory("myJpa");
     }
     
     /**
      * 获取EntityManager对象
      */
    public static EntityManager getEntityManager(){
        return factory.createEntityManager();
    }
}

3.基本操作

3.1 增加客户(persist)
    @Test
    public void testSave2(){
//        //1.加载配置文件创建工厂(实体管理器工厂)对象
//        EntityManagerFactory factory = Persistence.createEntityManagerFactory("myJpa");

        //2.通过写好的工具类获取实体管理器
        EntityManager manager = JpaUtils.getEntityManager();
        //3.获取事务对象,开启事务
        EntityTransaction tx = manager.getTransaction();//获取事务对象
        tx.begin();//开启事务
        Customer customer=new Customer();
        customer.setCustName("name");
        customer.setCustIndustry("industry");
        //4.完成增删改查操作
        manager.persist(customer);//保存操作
        // 5.提交事务(回滚事务)
        tx.commit();
        //6.释放资源(反向关闭)
        manager.close();
//        factory.close();此处我们不需要再关闭工厂,关闭后其他方法将无法使用
    }

在这里插入图片描述

3.2 根据ID查询客户(find / getReference)

find(Customer.class, 1)
getReference(Customer.class, 1)得
这两个方法得到的结果是一样的,均可查询到我们要的数据

    @Test
    public void testFind(){
        //1.通过工具类获取EntityManager实体类管理器对象
        EntityManager manager = JpaUtils.getEntityManager();
        //2.开启事务
        EntityTransaction tx = manager.getTransaction();
        tx.begin();
        //3.增删查改
        /**
         * find():查询数据的结果需要包装的实体类类型的字节码
         *  class属性:查询数据的结果需要包装的实体类类型的字节码
         *  id属性:查询主键的取值
         */
        Customer customer = manager.find(Customer.class, 1);//
//        Customer customer = manager.getReference(Customer.class, 1);

        System.out.println(customer);
        //4.提交事务
        tx.commit();
        //5.释放资源
        manager.close();
    }

在这里插入图片描述

3.3 根据ID删除客户(remove)
  1. 先根据ID进行查询,得到要删除的客户对象
  2. 调用remove方法,传入第一步查询得到的客户对象,从而根据该对象的ID进行删除操作
/**
     * 根据ID删除客户
     * remove:
     *  o:要删除的对象
     */
    @Test
    public void tesRemove() {
        //1.通过工具类获取EntityManager实体类管理器对象
        EntityManager manager = JpaUtils.getEntityManager();
        //2.开启事务
        EntityTransaction tx = manager.getTransaction();
        tx.begin();
        //3.增删查改
        /**
         * 1.根据ID查询客户
         * 2.调用remove传入查询的客户对象从而进行删除
         */
        Customer customer = manager.getReference(Customer.class, 1);
        manager.remove(customer);
        //4.提交事务
        tx.commit();
        //5.释放资源
        manager.close();
    }

在这里插入图片描述

3.4 客户更新操作(merge)
  1. 根据ID查询客户
  2. 更新客户
    a. 更新客户属性
    b. 调用merge方法,传入更新了属性的客户对象
/**
     * 客户更新操作
     */
    @Test
    public void tesUpdate() {
        //1.通过工具类获取EntityManager实体类管理器对象
        EntityManager manager = JpaUtils.getEntityManager();
        //2.开启事务
        EntityTransaction tx = manager.getTransaction();
        tx.begin();
        //3.增删查改
        /**
         * 1.根据ID查询客户
         * 2.更新客户
         *      更新客户属性
         *      调用merge方法,传入更新了属性的客户对象
         */
        Customer customer = manager.getReference(Customer.class, 2);
        customer.setCustAddress("西安工程大学");
        manager.merge(customer);
        //4.提交事务
        tx.commit();
        //5.释放资源
        manager.close();
    }

在这里插入图片描述

4. 延迟加载与立即加载

3.2中根据Id查询客户信息时,我们可以发现find / getReference均可得到我们想要的结果,那它们区别是什么呢?

4.1 使用find方法查询(立即加载)
  • 查询的对象就是当前对象本身
  • 在调用find方法时,就会发送SQL语句查询数据库
4.2使用getReference方法查询(延迟加载)
  • 查询的对象就是当前对象的一个代理对象
  • 在调用getReference方法时,不会立即发送SQL语句查询数据库,当我们调用查询结果对象的视乎,才会发送SQL语句,什么时候用,什么时候发送SQL语句

推荐使用getReference方法进行查询,这样不会产生不必要的查询

三:JPQL中的复杂查询

1.简介

jpql其特征与原生的SQL语句类似,并且完全面向对象,通过类名和属性进行访问,而不是表名和属性

  1. SQL:查询的是表和表中的字段
  2. JPQL:查询的是实体类和类中的属性
  3. JPQL和SQL语句的语法相似

2.基于JPQL的查询

实现步骤:
  1. 编写jpql语句:from com.yolo.domain.Customer(全限定类名)

    String jpql="from com.yolo.domain.Customer";//jpql:from com.yolo.domain.Customer(全限定类名)
    
  2. 创建Query查询对象query,query才是执行jpql的对象

    	Query query = em.createQuery(jpql);
    
  3. 对参数赋值

  4. 发送查询,并封装结果集

     List rs = query.getResultList();//list结果集
     Object rs = query.getSingleResultList();//单一结果,得到的是一个Object 对象
    
2.1 查询全部

查询全部
List rs = query.getResultList();

 /**
     * 查询全部
     *      jpql:from com.yolo.domain.Customer(全限定类名)
     *      sql:SELECT * FROM cst_customer;
     */

    @Test
    public void testFindAll(){
        //1.获取EntityManager对象
        EntityManager em = JpaUtils.getEntityManager();
        //2.开启事务
        EntityTransaction tx = em.getTransaction();
        tx.begin();
        //3.查询全部
        String jpql="from com.yolo.domain.Customer";//jpql:from com.yolo.domain.Customer(全限定类名)
        //创建Query查询对象query,query才是执行jpql的对象
        Query query = em.createQuery(jpql);
        //发送查询,并封装结果集
        List rs = query.getResultList();
        for (Object obj : rs) {
            System.out.println(obj);
        }
        //4.提交事务
        tx.commit();
        //5.释放资源
        em.close();
    }

在这里插入图片描述
根据ID倒序查询全部客户

  1. SQL:SELECT * FROM cst_customer ORDER BY cust_id DESC;
  2. JPQL:from Customer order by custId desc
    只需修改上述查询全部代码中的jpql语句即可完成倒序查询
    在这里插入图片描述
2.2 分页查询
  1. 对参数进行赋值,分页参数
    query.setFirstResult(1);//每次从1开始查,不包含1
    query.setMaxResults(2);//每次查询两条
 /**
     * 分页查询
     *  sql:SELECT * FROM cst_customer LIMIT ?,?;
     *  jpql:from com.yolo.domain.Customer
     */
    @Test
    public void testPage(){
        //1.获取EntityManager对象
        EntityManager em = JpaUtils.getEntityManager();
        //2.开启事务
        EntityTransaction tx = em.getTransaction();
        tx.begin();
        //3.查询全部
        //a.jpql语句
        String jpql="from com.yolo.domain.Customer";
        //b.创建Query查询对象query,query才是执行jpql的对象
        Query query = em.createQuery(jpql);
        //c.对参数进行赋值,分页参数
        query.setFirstResult(1);//每次从1开始查,不包含1
        query.setMaxResults(2);//每次查询两条
        //发送查询,并封装结果集
        List rs = query.getResultList();
        for (Object r : rs) {
            System.out.println(r);
        }
        //4.提交事务
        tx.commit();
        //5.释放资源
        em.close();
    }

在这里插入图片描述

2.3 统计查询
  1. sql:SELECT COUNT(cust_id) FROM cst_customer;
  2. jpql:select count(custId) from Customer

Object rs = query.getSingleResultList();//单一结果,得到的是一个Object 对象

/**
     * 统计查询
     * sql:SELECT COUNT(cust_id) FROM cst_customer;
     * jpql:select count(custId) from Customer
     */
    @Test
    public void testCount(){
        //1.获取EntityManager对象
        EntityManager em = JpaUtils.getEntityManager();
        //2.开启事务
        EntityTransaction tx = em.getTransaction();
        tx.begin();
        //3.查询全部
        String jpql="select count(custId) from Customer";
        //创建Query查询对象query,query才是执行jpql的对象
        Query query = em.createQuery(jpql);
        //发送查询,并封装结果集
        Object rs = query.getSingleResult();
        System.out.println(rs);
        //4.提交事务
        tx.commit();
        //5.释放资源
        em.close();
    }

在这里插入图片描述

2.4 条件查询

案例:查询客户名称以“郭”开头的

  1. SQL:SELECT * FROM cst_customer WHERE cust_name LIKE “郭%”
  2. JPQL: from com.yolo.domain.Customer where custName like ?1
    注意:like后的占位符要写为 ?---->?1,这是新的JPA样式,否则会出现下方的异常
Caused by: 
org.hibernate.QueryException: Legacy-style query parameters (`?`) are no longer supported; 
use JPA-style ordinal parameters (e.g., `?1`) instead : 

/**
     * 条件查询
     *  案例:查询客户名称以“郭”开头的
     *  SQL:SELECT * FROM cst_customer WHERE cust_name LIKE "郭%"
     *  jpql:from com.yolo.domain.Customer where custName like ?1
     */
    @Test
    public void testCondition(){
        //1.获取EntityManager对象
        EntityManager em = JpaUtils.getEntityManager();
        //2.开启事务
        EntityTransaction tx = em.getTransaction();
        tx.begin();
        
        //a.jpql语句
        String jpql="from Customer where custName like ?1";
        //b.创建Query查询对象query,query才是执行jpql的对象
        Query query = em.createQuery(jpql);
        /**c.对参数进行赋值,占位符参数.
         第一个参数:占位符的索引位置(1开始)
         第二个参数:
         */
        query.setParameter(1,"郭%");
        
        //发送查询,并封装结果集
        List rs = query.getResultList();
        for (Object r : rs) {
            System.out.println(r);
        }
        //4.提交事务
        tx.commit();
        //5.释放资源
        em.close();
    }

在这里插入图片描述

2.5 排序
  1. SQL:SELECT * FROM cst_customer ORDER BY cust_id DESC;
  2. JPQL:from Customer order by custId desc

List rs = query.getResultList();

/**
     * 根据ID倒序查询所有客户
     * SQL:SELECT * FROM cst_customer ORDER BY cust_id DESC;
     * JPQL:from Customer order by custId desc
     */
    @Test
    public void testOrders(){
        //1.获取EntityManager对象
        EntityManager em = JpaUtils.getEntityManager();
        //2.开启事务
        EntityTransaction tx = em.getTransaction();
        tx.begin();
        //3.查询全部
        String jpql="from Customer order by custId desc";
        //创建Query查询对象query,query才是执行jpql的对象
        Query query = em.createQuery(jpql);
        //发送查询,并封装结果集
        List rs = query.getResultList();
        for (Object obj : rs) {
            System.out.println(obj);
        }
        //4.提交事务
        tx.commit();
        //5.释放资源
        em.close();
    }

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值