SpringData JPA (一) JPA、Hibernate入门

1.ORM概述


ORM(Object-Relational Mapping) 表示对象关系映射。在面向对象的软件开发中,通过ORM,就可以把对象映射到关系型数据库中。只要有一套程序能够做到建立对象与数据库的关联,操作对象就可以直接操作数据库数据,就可以说这套程序实现了ORM对象关系映射。

简单的说:ORM就是建立实体类和数据库表之间的关系,从而达到操作实体类就相当于操作数据库表的目的。

1.1 为什么使用ORM

当实现一个应用程序时(不使用O/R Mapping),我们可能会写特别多数据访问层的代码,从数据库保存数据、修改数据、删除数据,而这些代码都是重复的。而使用ORM则会大大减少重复性代码。对象关系映射(Object Relational Mapping,简称ORM),主要实现程序对象到关系数据库数据的映射。

1.2 常见ORM框架

常见的orm框架:Mybatis(ibatis)、Hibernate、Jpa

2 hibernate与JPA的概述


2.1 hibernate概述

Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,它将POJO与数据库表建立映射关系,是一个全自动的orm框架,hibernate可以自动生成SQL语句,自动执行,使得Java程序员可以随心所欲的使用对象编程思维来操纵数据库。

2.2 JPA概述

JPA的全称是Java Persistence API, 即Java 持久化API,是SUN公司推出的一套基于ORM的规范,内部是由一系列的接口和抽象类构成。

JPA通过JDK 5.0注解描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中。

2.3 JPA的优势

1. 标准化

JPA 是 JCP 组织发布的 Java EE 标准之一,因此任何声称符合 JPA 标准的框架都遵循同样的架构,提供相同的访问API,这保证了基于JPA开发的企业应用能够经过少量的修改就能够在不同的JPA框架下运行。

2. 容器级特性的支持

JPA框架中支持大数据集、事务、并发等容器级事务,这使得 JPA 超越了简单持久化框架的局限,在企业应用发挥更大的作用。

3. 简单方便

JPA的主要目标之一就是提供更加简单的编程模型:在JPA框架下创建实体和创建Java 类一样简单,没有任何的约束和限制,只需要使用 javax.persistence.Entity进行注释,JPA的框架和接口也都非常简单,没有太多特别的规则和设计模式的要求,开发者可以很容易的掌握。JPA基于非侵入式原则设计,因此可以很容易的和其它框架或者容器集成。

4. 查询能力

JPA的查询语言是面向对象而非面向数据库的,它以面向对象的自然语法构造查询语句,可以看成是Hibernate HQL的等价物。JPA定义了独特的JPQL(Java Persistence Query Language),JPQL是EJBQL的一种扩展,它是针对实体的一种查询语言,操作对象是实体,而不是关系数据库的表,而且能够支持批量更新和修改、JOIN、GROUP
BY、HAVING 等通常只有 SQL 才能够提供的高级查询特性,甚至还能够支持子查询。

5. 高级特性

JPA 中能够支持面向对象的高级特性,如类之间的继承、多态和类之间的复杂关系,这样的支持能够让开发者最大限度的使用面向对象的模型设计企业应用,而不需要自行处理这些特性在关系数据库的持久化。

2.4 JPA与hibernate的关系

JPA规范本质上就是一种ORM规范,注意不是ORM框架——因为JPA并未提供ORM实现,它只是制订了一些规范,提供了一些编程的API接口,但具体实现则由服务厂商来提供实现。
在这里插入图片描述
JPA和Hibernate的关系就像JDBC和JDBC驱动的关系,JPA是规范,Hibernate除了作为ORM框架之外,它也是一种JPA实现。JPA怎么取代Hibernate呢?JDBC规范可以驱动底层数据库吗?答案是否定的,也就是说,如果使用JPA规范进行数据库操作,底层需要hibernate作为其实现类完成数据持久化工作。

3 JPA的入门案例


3.1 需求介绍

保存一个客户到数据库的客户表中。

3.2 开发包介绍

由于JPA是sun公司制定的API规范,所以我们不需要导入额外的JPA相关的jar包,只需要导入JPA的提供商的jar包。我们选择Hibernate作为JPA的提供商,所以需要导入Hibernate的相关jar包。

下载网址:
http://sourceforge.net/projects/hibernate/files/hibernate-orm/5.0.7.Final/

页面显示如下图:

在这里插入图片描述

3.3 搭建开发环境

3.3.1 导入jar包

对于JPA操作,只需要从hibernate提供的资料中找到我们需要的jar导入到工程中即可。

传统工程导入jar包

在这里插入图片描述
maven工程导入坐标:

<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.9</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>

3.3.2 创建客户的数据库表和客户的实体类

创建客户的数据库表

/*创建客户表*/ 
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;

创建客户的实体类:

public class Customer implements Serializable { 
    private Long custId; 
    private String custName; 
    private String custSource; 
    private String custIndustry; 
    private String custLevel; 
    private String custAddress; 
    private String custPhone;
    //getter 和 setter方法
}

3.3.3 编写实体类和数据库表的映射配置

在实体类上使用JPA注解的形式配置映射关系

/**
 * 所有的注解都是使用JPA的规范提供的注解, 
 * 所以在导入注解包的时候,一定要导入javax.persistence下的 
 * */
@Entity //声明实体类 
@Table(name="cst_customer") //建立实体类和表的映射关系
public class Customer {
    @Id//声明当前私有属性为主键 
    @GeneratedValue(strategy=GenerationType.IDENTITY) //配置主键的生成策略 
    @Column(name="cust_id") //指定和表中cust_id字段的映射关系 
    private Long custId;

    @Column(name="cust_name") //指定和表中cust_name字段的映射关系 
    private String custName; 
    @Column(name="cust_source")//指定和表中cust_source字段的映射关系 
    private String custSource; 
    @Column(name="cust_industry")//指定和表中cust_industry字段的映射关系 
    private String custIndustry; 
    @Column(name="cust_level")//指定和表中cust_level字段的映射关系 
    private String custLevel; 
    @Column(name="cust_address")//指定和表中cust_address字段的映射关系 
    private String custAddress; 
    @Column(name="cust_phone")//指定和表中cust_phone字段的映射关系 
    private String custPhone;
    
    //getter 和 setter方法
}

常用注解的说明 :

@Entity
  作用:指定当前类是实体类。

@Table
  作用:指定实体类和表之间的对应关系。
  属性: name:指定数据库表的名称

@Id
  作用:指定当前字段是主键。

@GeneratedValue
  作用:指定主键的生成方式。。
  属性:
    strategy :指定主键生成策略。
    generator:指定引用hibernate中声明的主键策略

@Column
  作用:指定实体类属性和数据库表之间的对应关系
  属性:
     name:指定数据库表的列名称。
     unique:是否唯一
     nullable:是否可以为空
     inserttable:是否可以插入
     updateable:是否可以更新
     columnDefinition: 定义建表时创建此列的DDL
     secondaryTable: 从表名。如果此列不建在主表上(默认建在主表),该属性定义该列所在从表的名字

3.3.4 配置JPA的核心配置文件

在maven工程的resources路径下创建一个名为META-INF的文件夹,在此文件夹下创建一个名为persistence.xml的配置文件。注意:META-INF文件夹名称不能修改。persistence.xml文件名称不能改。

<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">
    <!--持久化单元块  注意:可配置多个 -->
    <persistence-unit name="myJpa" transaction-type="RESOURCE_LOCAL">
        <!--配置jpa实现的提供者-->
        <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider><!--不写也行-->
        <!--配置实体类位置-->
        <class>com.com.xxx.domain.Customer</class><!--不写也行-->
        <!--配置数据库连接的先关信息
         信息去哪找?hibernate提供,在hibernate的源码包下的project/etc/hibernate.properties中
            #hibernate.dialect org.hibernate.dialect.MySQLDialect
            #hibernate.dialect org.hibernate.dialect.MySQLInnoDBDialect
            #hibernate.dialect org.hibernate.dialect.MySQLMyISAMDialect
            #hibernate.connection.driver_class com.mysql.jdbc.Driver
            #hibernate.connection.url jdbc:mysql:///test
            #hibernate.connection.username gavin
            #hibernate.connection.password
        -->
        <properties>
          <!--必须配置-->
            <!--数据库驱动-->
            <property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver"/>
            <!--URL-->
            <property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/test"/>
            <!--用户名-->
            <property name="hibernate.connection.username" value="root"/>
            <!--密码-->
            <property name="hibernate.connection.password" value="admin"/>
            <!--数据库方言:数据提供商对SQL的扩展-->
            <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/>
            <!--可选配置-->
               <!--是否打印SQL-->
               <property name="hibernate.show_sql" value="true"/>
               <!--是否格式化SQL-->
               <property name="hibernate.format_sql" value="true"/>
               <!--DDl语句生成策略
                 update:当醒目运行的时候,程序会根据实体类的对应关系,
                       自动检测与数据库表结构的差异,如果发现不一致,立即更新。
                 使用场景:
                       适合:开发环境
                       不适合:线上环境
               -->
               <property name="hibernate.hbm2ddl.auto" value="update"/>
               <!--配置c3p0连接池提供商-->
               <property name="hibernate.connection.provider_class" value="org.hibernate.connection.C3P0ConnectionProvider"/>
        </properties>
    </persistence-unit>
</persistence>

3.4 实现保存操作

@Test
public void test() { 
    /** 
     * 创建实体管理类工厂,借助Persistence的静态方法获取 
     * 其中传递的参数为持久化单元名称,需要jpa配置文件中指定 
     * */ 
    EntityManagerFactory factory = Persistence.createEntityManagerFactory("myJpa"); 
    //创建实体管理类 
    EntityManager em = factory.createEntityManager(); 
    //获取事务对象 
    EntityTransaction tx = em.getTransaction(); 
    //开启事务 
    tx.begin(); 
    Customer c = new Customer(); 
    c.setCustName("xxx"); 
    //保存操作 
    em.persist(c);
    //提交事务 
    tx.commit(); 
    //释放资源 
    em.close(); 
    factory.close(); 
}

4 JPA的API介绍


4.1 Persistence对象

Persistence对象主要作用是用于获取EntityManagerFactory对象的 。通过调用该类的createEntityManagerFactory静态方法,根据配置文件中持久化单元名称创建EntityManagerFactory。

//1. 创建 EntitymanagerFactory 
@Test 
String unitName = "myJpa"; 
EntityManagerFactory factory= Persistence.createEntityManagerFactory(unitName);

4.2 EntityManagerFactory

EntityManagerFactory 接口主要用来创建 EntityManager 实例

//创建实体管理类 
EntityManager em = factory.createEntityManager(); 

由于EntityManagerFactory 是一个线程安全的对象(即多个线程访问同一个EntityManagerFactory 对象不会有线程安全问题),并且EntityManagerFactory 的创建极其浪费资源,所以在使用JPA编程时,我们可以对EntityManagerFactory 的创建进行优化,只需要做到一个工程只存在一个EntityManagerFactory 即可

4.3 EntityManager

在 JPA 规范中, EntityManager是完成持久化操作的核心对象。实体类作为普通 java对象,只有在调用 EntityManager将其持久化后才会变成持久化对象。EntityManager对象在一组实体类与底层数据源之间进行 O/R 映射的管理。它可以用来管理和更新 Entity Bean, 根椐主键查找 Entity Bean, 还可以通过JPQL语句查询实体。

我们可以通过调用EntityManager的方法完成获取事务,以及持久化数据库的操作.

方法说明:

  getTransaction : 获取事务对象
  persist : 保存操作
  merge : 更新操作
  remove : 删除操作
  find/getReference : 根据id查询

4.4 EntityTransaction

在 JPA 规范中, EntityTransaction是完成事务操作的核心对象,对于EntityTransaction在我们的java代码中承接的功能比较简单.

  • begin:开启事务
  • commit:提交事务
  • rollback:回滚事务

5 抽取JPAUtil工具类


import javax.persistence.EntityManager; 
import javax.persistence.EntityManagerFactory; 
import javax.persistence.Persistence; 
public final class JPAUtil { 
    // JPA的实体管理器工厂:相当于Hibernate的SessionFactory 
    private static EntityManagerFactory em; 
    // 使用静态代码块赋值 
    static { 
        // 注意:该方法参数必须和persistence.xml中persistence-unit标签name属性取值一致 
        em = Persistence.createEntityManagerFactory("myPersistUnit"); 
    }
    /** 
     * 使用管理器工厂生产一个管理器对象 
     * @return 
     * */
    public static EntityManager getEntityManager() { 
        return em.createEntityManager(); 
    } 
} 
        

6 使用JPA完成增删改查操作


6.1 CRUD操作

6.1.1 保存

/**
 * 保存一个实体 
 */ 
@Test 
public void testAdd() {
	// 定义对象 
	Customer c = new Customer(); 
	c.setCustName("xxx"); 
	c.setCustLevel("VIP客户"); 
	c.setCustSource("网络"); 
	c.setCustIndustry("IT"); 
	c.setCustAddress("北京"); 
	c.setCustPhone("10086"); 
	EntityManager em = null; 
	EntityTransaction tx = null;
	try { 
	    // 获取实体管理对象 
	    em = JPAUtil.getEntityManager(); 
	    // 获取事务对象 
	    tx = em.getTransaction(); 
	    // 开启事务 
	    tx.begin(); 
	    // 执行操作 
	    em.persist(c); 
	    // 提交事务 
	    tx.commit(); 
	} catch (Exception e) { 
	    // 回滚事务 
	    tx.rollback(); 
	    e.printStackTrace(); 
	} finally { 
	    // 释放资源 
	    em.close(); 
	}
}

6.1.2 修改

@Test 
public void testMerge(){ 
    //定义对象 
    EntityManager em=null; 
    EntityTransaction tx=null; 
    try{ 
        //获取实体管理对象
        em=JPAUtil.getEntityManager(); 
        //获取事务对象 
        tx=em.getTransaction(); 
        //开启事务 
        tx.begin(); 
        //执行操作 
        Customer c1 = em.find(Customer.class, 6L); 
        c1.setCustName("小白"); 
        em.clear();
        //把c1对象从缓存中清除出去 
        em.merge(c1); 
        //提交事务 
        tx.commit(); 
    }catch(Exception e){ 
        //回滚事务 
        tx.rollback(); 
        e.printStackTrace(); 
    }finally{ 
        //释放资源 
        em.close(); 
    } 
}

6.1.3 删除

/** 
 * 删除 
 * */ 
@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, 6L); 
        em.remove(c1); 
        // 提交事务 
        tx.commit();
    } catch (Exception e) { 
        // 回滚事务 
        tx.rollback(); 
        e.printStackTrace(); 
    } finally { 
        // 释放资源 
        em.close(); 
    } 
}

6.1.4 根据id查询

/** 
 * 查询一个: 使用立即加载的策略 
 * */ 
@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); 
        // 提交事务 
        tx.commit(); 
        System.out.println(c1); 
        // 输出查询对象 
    } catch (Exception e) { 
        // 回滚事务 
        tx.rollback(); 
        e.printStackTrace(); 
    } finally { 
        // 释放资源 
        em.close(); 
    } 
}

6.1.5 查询全部

//查询所有客户 
@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 list = query.getResultList(); 
        // 得到集合返回类型 
        for (Object object : list) { 
            System.out.println(object); 
        } 
        tx.commit(); 
    } catch (Exception e) { 
        // 回滚事务 
        tx.rollback(); 
        e.printStackTrace(); 
    } finally { 
        // 释放资源 
        em.close(); 
    } 
}

6.1.6 查询返回一行一列

@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(); 
    } 
}

6.2 根据id查询的两种方式及区别

/** 
 * <p>Title: JPATest</p> 
 * <p>Description: JPA的查询一个实体的两种方式</p> 
 * find和getReference 
 * 区别: 
 * 第一个:查询的时机不一样。 
 * find是立即加载 ,只要一调用方法,马上发起查询。 
 * getReference是延迟加载,什么时候使用什么时候加载。 
 * 第二个:返回的结果不一样 
 * find返回的是实体类类型 
 * getReference返回的是实体类的代理对象 
 * hibernate中 
 * get和load方法的区别和jpa中的find和getReference是一样的 
 * 其中: 
 * get方法对应find 
 * load方法对应getReference 
 * */ 
 public class JPAFindOneTest { 
     //查询一个 
     //立即加载 
     @Test
     public void testFindOne() { 
         EntityManager em = JPAUtil.createEntityManager(); 
         EntityTransaction tx = em.getTransaction(); 
         tx.begin(); 
         Customer c = em.find(Customer.class, 1); 
         System.out.println(c); 
         tx.commit(); 
         em.close(); 
     } 
     //查询一个 
     //懒加载(延迟加载) 
     @Test public void testFindOne2() { 
         EntityManager em = JPAUtil.createEntityManager(); E
         ntityTransaction tx = em.getTransaction(); 
         tx.begin(); 
         Customer c = em.getReference(Customer.class, 1); 
         System.out.println(c.toString()); 
         tx.commit(); 
         em.close(); 
     } 
 }

6.3 JPA中的其他查询

JPQL全称Java Persistence Query Language

基于首次在EJB2.0中引入的EJB查询语言(EJB QL),Java持久化查询语言(JPQL)是一种可移植的查询语言,旨在以面向对象表达式语言的表达式,将SQL语法和简单查询语义绑定在一起·使用这种语言编写的查询是可移植的,可以被编译成所有主流数据库服务器上的SQL。

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

6.3.1 条件查询

//条件查询 
@Test 
public void findCondition () { 
    EntityManager em = null;
    EntityTransaction tx = null; 
    try { 
        //获取实体管理对象 
        em = JPAUtil.getEntityManager(); 
        //获取事务对象 
        tx = em.getTransaction(); 
        tx.begin(); 
        //创建query对象 
        String jpql = "from Customer where custName like ? "; 
        Query query = em.createQuery(jpql); 
        //对占位符赋值,从1开始 
        query.setParameter(1, "xxx%"); 
        //查询并得到返回结果 
        Object object = query.getSingleResult(); 
        //得到唯一的结果集对象 
        System.out.println(object); 
        tx.commit(); 
    } catch (Exception e) { 
        // 回滚事务 
        tx.rollback(); 
        e.printStackTrace(); 
    } finally { 
        // 释放资源 
        em.close(); 
    } 
}

6.3.2 分页查询

//分页查询客户 
@Test 
public void findPaged () { 
    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); 
        //起始索引 
        query.setFirstResult(0); 
        //每页显示条数 
        query.setMaxResults(2); 
        //查询并得到返回结果 
        List list = query.getResultList(); 
        //得到集合返回类型 
        for (Object object : list) { 
            System.out.println(object); 
        } 
        tx.commit(); 
    } catch (Exception e) { 
        // 回滚事务 
        tx.rollback(); 
        e.printStackTrace(); 
    } finally { 
        // 释放资源 
        em.close(); 
    } 
}

6.3.3 排序查询

//根据客户id倒序查询所有客户 
//查询所有客户 
@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 list = query.getResultList(); 
        // 得到集合返回类型 
        for (Object object : list) { 
            System.out.println(object); 
        } 
        tx.commit(); 
    } catch (Exception e) { 
        // 回滚事务
        tx.rollback(); 
        e.printStackTrace(); 
    } finally { 
        // 释放资源 
        em.close(); 
    } 
}

7 附录:补充说明


7.1 hibernate的使用

7.1.1 hibernate的环境搭建

第一步:创建maven工程并导入坐标,可以直接沿用jpa环境中的pom.xml

<dependencies>
  <dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.6</version>
  </dependency>
  <dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.10</version>
  </dependency>
  <dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-entitymanager</artifactId>
    <version>5.0.7.Final</version>
  </dependency>
  <dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-c3p0</artifactId>
    <version>5.0.7.Final</version>
  </dependency>
  <dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.12</version>
  </dependency>
</dependencies>

第二步:编写hibernate的主配置文件,文件名为hibernate.cfg.xml,放在resource文件夹下即可

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration
  PUBLIC '-//Hibernate/Hibernate Configuration DTD 3.0//EN'
  'http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd'>
<hibernate-configuration>
  <!-- 配置session工厂 -->
  <session-factory>
    <!-- 第一部分:连接数据库的信息 -->
    <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
    <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/ee314</property>
    <property name="hibernate.connection.username">root</property>
    <property name="hibernate.connection.password">1234</property>
    <!-- 第二部分:hibernate的可选配置:例如是否显示SQL,是否格式化SQL等等 -->
    <!-- 数据库方言 -->
    <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
    <!-- 显示sql语句 -->
    <property name="hibernate.show_sql">true</property>
    <!-- 格式化sql语句 -->
    <property name="hibernate.format_sql">true</property>
    <!-- 配置生成DDL的方式 -->
    <property name="hibernate.hbm2ddl.auto">update</property>
    <!-- 配置连接池的提供商 -->
    <property name="hibernate.connection.provider_class">org.hibernate.c3p0.internal.C3P0ConnectionProvider</property>
    <!-- 第三部分:映射配置的位置,xml方式写xml的位置,注解方式写实体类的位置 -->
    <mapping class="com.xxx.domain.Customer"/>
  </session-factory>
</hibernate-configuration>

第三步:在实体类上使用注解建立与数据库表的映射 和jpa中的配置相同,可以直接沿用jpa中的实体类配置

@Entity 
@Table(name="cst_customer") 
public class Customer implements Serializable { 
    @Id
    @Column(name="cust_id") 
    @GeneratedValue(strategy=GenerationType.IDENTITY) 
    private Integer custId; 
    @Column(name="cust_name") 
    private String custName; 
    @Column(name="cust_source") 
    private String custSource; 
    @Column(name="cust_level") 
    private String custLevel; 
    @Column(name="cust_industry") 
    private String custIndustry; 
    @Column(name="cust_address") 
    private String custAddress; 
    @Column(name="cust_phone") 
    private String custPhone;
    
    public Integer getCustId() { return custId; } 
    public void setCustId(Integer 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 getCustLevel() { return custLevel; }
    public void setCustLevel(String custLevel) { this.custLevel = custLevel; } 
    public String getCustIndustry() { return custIndustry; } 
    public void setCustIndustry(String custIndustry) { this.custIndustry = custIndustry; } 
    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 + ", custLevel=" + custLevel + ", custIndustry=" + custIndustry + ", custAddress=" + custAddress + ", custPhone=" + custPhone + "]"; 
    } 
}

第四步:编写hibernate的工具类

public class HibernateUtil { 
    private static SessionFactory factory; 
    static { 
        //读取配置文件 
        Configuration cfg = new Configuration(); 
        cfg.configure(); 
        //根据配置文件构建工厂对象 
        factory = cfg.buildSessionFactory(); 
    } 
    /**
     * 此Session既不是Http中HttpSession,也不是Mybatis的SqlSession 
     * @return 
     * */ 
    public static Session createSession() { return factory.openSession(); } 
}

7.1.2 hibernate的CRUD

public class HibernateTest { 
    //保存 
    @Test 
    public void testPersist() { 
        Customer c = new Customer(); 
        c.setCustName("Hibernate CRUD persist"); 
        Session session = HibernateUtil.createSession(); 
        Transaction tx = session.beginTransaction(); 
        // session.save(c); 
        session.persist(c); 
        tx.commit(); 
        session.close(); 
    } 
    //查询一个 
    @Test 
    public void testFindOne() { 
        Session session = HibernateUtil.createSession(); 
        Transaction tx = session.beginTransaction(); 
        Customer c = session.get(Customer.class, 1); 
        System.out.println(c); 
        tx.commit(); 
        session.close(); 
    } 
    //更新 
    @Test 
    public void testUpdate() { 
        Session session = HibernateUtil.createSession();
        Transaction tx = session.beginTransaction(); 
        Customer c = session.get(Customer.class, 1); 
        c.setCustAddress("北京市"); 
        session.update(c); 
        tx.commit(); 
        session.close(); 
    }
     //删除 
     @Test 
     public void testDelete() { 
         Customer c = new Customer(); 
         c.setCustId(5); 
         Session session = HibernateUtil.createSession(); 
         Transaction tx = session.beginTransaction(); 
         // Customer c = session.get(Customer.class, 1); 
         session.delete(c); 
         tx.commit(); 
         session.close(); 
     } 
     //查询所有 
     @Test 
     public void testFindAll() { 
         Session session = HibernateUtil.createSession(); 
         Transaction tx = session.beginTransaction(); 
         //HQL的写法是把SQL语句中 列名换成属性名称,把表名换成实体类名称 
         //select * from cst_customer 
         Query query = session.createQuery("select c from Customer c ");
         //写的是HQL语句 hibernate query language 
         List<Customer> customers = query.list(); 
         for(Customer c : customers) {  
             System.out.println(c); 
         } 
         tx.commit(); 
         session.close(); 
     }
     //查询使用聚合函数 
     @Test 
     public void testFindTotal() { 
         Session session = HibernateUtil.createSession(); 
         Transaction tx = session.beginTransaction(); 
         Query query = session.createQuery("select count(custId) from Customer "); 
         Object obj = query.uniqueResult(); 
         System.out.println(obj); 
         tx.commit(); 
         session.close(); 
     } 
 }

7.2 hibernate和JPA中的方法对照

在这里插入图片描述

在这里插入图片描述

7.3 JPA中RESOURCE_LOCAL和JTA事务说明

7.3.1 JTA

  JTA事务(Java Transaction API)是J2EE规范中有关事务的标准。它是容器级别的事务,只能运行在J2EE服务器中。它的最大优势是可以支持分布式的事务,如果系统采用的是分布式的数据库,那么只能选择JTA管理EntityManager事务。
  使用JTA管理EntityManager事务时,需要注意以下几个问题。
    1、JTA事务只能运行在J2EE的环境中,即EJB容器中和Web容器中;而在J2SE环境中只能使用RESOURCE_LOCAL管理事务。
    2、容器托管的EntityManager对象只能采用JTA的事务,而不能采用RESOURCE_LOCAL事务。

7.3.2 RESOURCE_LOCAL

   RESOURCE_LOCAL事务数据库本地的事务。它是数据库级别的事务,只能针对一种数据库,不支持分布式的事务。于中小型的应用,可以采用RESOURCE_LOCAL管理EntityManager事务。
  使用RESOURCE_LOCAL管理EntityManager事务时需要注意以下几个问题。
    1、在J2SE环境中,只能使用RESOURCE_LOCAL管理EntityManager事务,并且EntityManager对象是以应用托管方式获得的。
    2、代码中使用RESOURCE_LOCAL管理事务时,要通过调用EntityManager的getTransaction()方法获得本地事务。

发布了35 篇原创文章 · 获赞 4 · 访问量 2万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 深蓝海洋 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览