详谈hibernate,jpa与spring data jpa三者之间的关系

目录
  • 前提
  • 文字说明
  • CRUD操作

前提

其实很多框架都是对另一个框架的封装,我们在学习类似的框架的时候,难免会进入误区,所以我们就应该对其进行总结归纳,对比。本文就是对hibernate,jpa,spring data jpa三者之间进行文字对比,以及对其三者分别进行CRUD操作。

文字说明

Hibernate

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

JPA

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

JPA与Hibetnate的关系

JPA和Hibernate的关系就像JDBC和JDBC驱动的关系,JPA是规范,Hibernate除了作为ORM框架之外,它也是一种JPA实现。JPA怎么取代Hibernate呢?JDBC规范可以驱动底层数据库吗?答案是否定的,也就是说,如果使用JPA规范进行数据库操作,底层需要hibernate作为其实现类完成数据持久化工作。

Spring Data jpa

Spring Data JPA 让我们解脱了DAO层的操作,基本上所有CRUD都可以依赖于它来实现,在实际的工作工程中,推荐使用Spring Data JPA + ORM(如:hibernate)完成操作,这样在切换不同的ORM框架时提供了极大的方便,同时也使数据库层操作更加简单,方便解耦

Hibernate、JPA与Spring Data JPA之间的关系

JPA是一套规范,内部是有接口和抽象类组成的。hibernate是一套成熟的ORM框架,而且Hibernate实现了JPA规范,所以也可以称hibernate为JPA的一种实现方式,我们使用JPA的API编程,意味着站在更高的角度上看待问题(面向接口编程)Spring Data JPA是Spring提供的一套对JPA操作更加高级的封装,是在JPA规范下的专门用来进行数据持久化的解决方案。以上就是对hibernate、JPA与Spring Data JPA三者之间的关系说明。

总结:

JPA是一种规范,Hibernate实现了JPA规范,即Hibernate为JPA的一种实现;而Spring Data JPA是对JPA进行更高级的封装,让其dao编码变得更简单。

CRUD操作

hibernate的crud操作

首先创建数据库表

创建hibernate核心配置文件hibernate.cfg.xml

<?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-factory>
		<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
		<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
		<property name="hibernate.connection.url">jdbc:mysql:///hibernate</property>
		<property name="hibernate.connection.username">root</property>
		<property name="hibernate.connection.password">root</property>
		<property name="hibernate.connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property>
		<property name="hibernate.show_sql">true</property>
		<property name="hibernate.format_sql">true</property>
		<property name="hibernate.hbm2ddl.auto">update</property>
		<!-- 配置和当前线程绑定的session进行开启配置 -->
		<property name="hibernate.current_session_context_class">thread</property>
		<!-- 引入映射文件 -->
		<mapping resource="cn/itcast/domain/Customer.hbm.xml" />
	</session-factory>
</hibernate-configuratio

创建实体类Customer(和数据库表映射的类)

package cn.itcast.domain;
public class Customer
{
	 private Long cust_id;// '客户编号(主键)',
	 private String cust_name;// '客户名称(公司名称)',
	 private String cust_source;// '客户信息来源',
	 private String cust_industry;//'客户所属行业',
	 private String cust_level;// '客户级别',
	 private String cust_address;// '客户联系地址',
	 private String cust_phone;// '客户联系电话',
	public Long getCust_id() {
		return cust_id;
	}
	public void setCust_id(Long cust_id) {
		this.cust_id = cust_id;
	}
	public String getCust_name() {
		return cust_name;
	}
	public void setCust_name(String cust_name) {
		this.cust_name = cust_name;
	}
	public String getCust_source() {
		return cust_source;
	}
	public void setCust_source(String cust_source) {
		this.cust_source = cust_source;
	}
	public String getCust_industry() {
		return cust_industry;
	}
	public void setCust_industry(String cust_industry) {
		this.cust_industry = cust_industry;
	}
	public String getCust_level() {
		return cust_level;
	}
	public void setCust_level(String cust_level) {
		this.cust_level = cust_level;
	}
	public String getCust_address() {
		return cust_address;
	}
	public void setCust_address(String cust_address) {
		this.cust_address = cust_address;
	}
	public String getCust_phone() {
		return cust_phone;
	}
	public void setCust_phone(String cust_phone) {
		this.cust_phone = cust_phone;
	}
}

创建Hibernate映射文件Customer.hbm.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<!-- 做类(Customer)和表(cst_customer)的映射关系 -->
<hibernate-mapping>
		<!--
			class标签: 作用类和表的映射的
		 		name:类的全限定名(cn.itcast.domain.Customer)
		 		table:表的全名(cst_customer)
		 -->
		<class name="cn.itcast.domain.Customer" table="cst_customer">
			<!--
				id标签:做类中的某个属性 和 表的主键映射关系
				 name:类的某个属性名
				 column:表的主键字段名
			 -->
			<id name="cust_id" column="cust_id">
				<!-- 做主键的增长方式的
					  native: AUTO_INCREMENT 让主键自动增长 -->
				<generator class="native"></generator>
			</id>

			<!--
				property标签:做其它属性和其它字段的映射关系
				   name属性:类的其它属性名
				   column属性:表的其它字段名
				   ps:如果属性名和字段名一致 column可以省略不写
			-->
			<property name="cust_name" column="cust_name" length="20" not-null="true" unique="true"></property>
			<property name="cust_source" column="cust_source"></property>
			<property name="cust_industry" column="cust_industry"></property>
			<property name="cust_level" column="cust_level"></property>
			<property name="cust_address" column="cust_address"></property>
			<property name="cust_phone" column="cust_phone"></property>
		</class>
</hibernate-mapping>

以上我们就完成了dao层的编码工作。现在我们来测试:

创建工具类HibernateUtils

package cn.itcast.utils;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class HibernateUtils
{
		static Configuration configuration =null;
		static SessionFactory sessionFactory = null;
		static
		{
			// 加载一次配置文件
			configuration = new Configuration();
			configuration.configure();

			// 获取一个sessionFactory
			sessionFactory=configuration.buildSessionFactory();

		}

		// 从连接池获取的
		public static Session openSession()
		{
			return sessionFactory.openSession();
		}

		// 从当前线程中获取绑定的session
		// 好处: 在多层之间调用方法获取的都是同一个session
		public static Session getCurrentSession()
		{
			/*特点: 1 默认是关闭的 需要配置开启
				   2 会自动给你关闭连接*/
			Session session = sessionFactory.getCurrentSession();
			return session;
		}
}

通过以上工具类,我们就可以轻松地获取管理hibernate的seesion对象,session对象具备crud的一系列方法。

save():保存操作

@Test
	public void test2()
	{
		Session session = HibernateUtils.openSession();
		Transaction tx = session.beginTransaction();

		Customer customer = new Customer();
		customer.setCust_name("bbbbb");
		session.save(customer);
		tx.commit();
		session.close();
	}

get():查询

// oid查询
	@Test
	public void test1() {
		Session session = HibernateUtils.openSession();
		Transaction tx = session.beginTransaction();
		Customer customser = session.get(Customer.class, "abcdefg");
		System.out.println(customser);
		tx.commit();
		session.close();
		// 只有增删改 一级oid查询 才会自动生成sql语句
	}

通过HQL方式查询:

@Test
	public void test3() {
		Session session = HibernateUtils.openSession();
		Transaction tx = session.beginTransaction();
		// 条件查 类似sql语句的表达式 from 持久化类 where 属性=?
		Query qr = session.createQuery("from Customer where cust_name like ?");
		qr.setParameter(0, "h%");
		List<Customer> list = qr.list();
		for (Customer customer : list) {
			System.out.println(customer);
		}
		tx.commit();
		session.close();
	}

通过sql方式查询:

@Test
	public void test5() {
		Session session = HibernateUtils.openSession();
		Transaction tx = session.beginTransaction();
		// 单列查 返回是Object
		Query qr = session.createQuery("select cust_id from Customer");
		List<Object> list = qr.list();
		for (Object object : list) {
			System.out.println(object);
		}
		tx.commit();
		session.close();
	}

JPA的crud操作

该操作我们用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.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>

在resources目录下创建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/jpa?characterEncoding=utf-8" />
			<!-- 数据库用户名 -->
			<property name="javax.persistence.jdbc.user" value="root" />
			<!-- 数据库密码 -->
			<property name="javax.persistence.jdbc.password" value="root" />
			<!--jpa提供者的可选配置:我们的JPA规范的提供者为hibernate,所以jpa的核心配置中兼容hibernate的 -->
			<!--配置jpa实现方(hibernate)的配置信息
                显示sql           :   false|true
                自动创建数据库表    :  hibernate.hbm2ddl.auto
                        create      : 程序运行时创建数据库表(如果有表,先删除表再创建)
                        update      :程序运行时创建表(如果有表,不会创建表)
                        none        :不会创建表
            -->
			<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>

创建和数据库表映射的实体类

package com.ithubei.entity;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
/**
 * @Entity
        	作用:指定当前类是实体类。
        @Table
        	作用:指定实体类和表之间的对应关系。
        	属性:
        		name:指定数据库表的名称
        @Id
        	作用:指定当前字段是主键。
        @GeneratedValue
        	作用:指定主键的生成方式。。
        	属性:
        		strategy :指定主键生成策略。
        @Column
        	作用:指定实体类属性和数据库表之间的对应关系
        	属性:
        		name:指定数据库表的列名称。
        		unique:是否唯一
        		nullable:是否可以为空
        		inserttable:是否可以插入
        		updateable:是否可以更新
        		columnDefinition: 定义建表时创建此列的DDL
        		secondaryTable: 从表名。如果此列不建在主表上(默认建在主表),该属性定义该列所在从表的名字搭建开发环境[重点]
 * @author DELL
 *
 */
@Entity  //声明该类是和数据库表映射的实体类
@Table(name="cst_customer")  //建立实体类与表的映射关系
public class Customer implements Serializable{
	@Id  //声明当前私有属性为主键
	@GeneratedValue(strategy=GenerationType.IDENTITY)  //配置主键的生成策略,为自增主键
	@Column(name = "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")
	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 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;
	}
}

创建工具类JpaUtils

package com.ithubei.utils;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
/**
 * 解决实体管理器工厂的浪费资源和耗时问题
 *      通过静态代码块的形式,当程序第一次访问此工具类时,创建一个公共的实体管理器工厂对象
 *
 * 第一次访问getEntityManager方法:经过静态代码块创建一个factory对象,再调用方法创建一个EntityManager对象
 * 第二次方法getEntityManager方法:直接通过一个已经创建好的factory对象,创建EntityManager对象
 */
public class JpaUtils {
	private static EntityManagerFactory entityManagerFactory;
	static {
		 //1.加载配置文件,创建entityManagerFactory
		entityManagerFactory = Persistence.createEntityManagerFactory("myJpa");
	}

	public static EntityManager getEntityManager() {
		return entityManagerFactory.createEntityManager();
	}
}

通过以上工具类,我们就可以得到EntityManager实体管理类来进行crud等操作。

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

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

方法说明:

  • getTransaction:获取事务对象
  • persist:保存操作
  • merge:更新操作
  • remove:删除操作
  • find(立即加载)/getReference(延迟加载):根据id查询

现在我们就来通过EntityManager对象来进行crud操作。

测试:

package com.ithubei.test;
import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;
import org.junit.Test;
import com.ithubei.entity.Customer;
import com.ithubei.utils.JpaUtils;
public class JpaTest {
	/**
	 * 保存操作
	 */
	@Test
	public void testSave() {
		//通过工具类来获取EntityManager对象
		EntityManager em = JpaUtils.getEntityManager();
		//获取事务对象
		EntityTransaction tx = em.getTransaction();
		tx.begin();  //开启事务
		//完成增删改查操作,保存一个用户到数据库中
		Customer customer = new Customer();
		customer.setCustName("授课");
		customer.setCustIndustry("教育");
		//保存操作
		em.persist(customer);
		tx.commit();  //提交事务
		em.close();  //释放资源
	}

	/**
	 * 保存一个实体
	 */
	@Test
	public void testAdd() {
		// 定义对象
		Customer c = new Customer();
		c.setCustName("传智学院");
		c.setCustLevel("VIP客户");
		c.setCustSource("网络");
		c.setCustIndustry("IT教育");
		c.setCustAddress("昌平区北七家镇");
		c.setCustPhone("010-84389340");
		EntityManager em = null;
		EntityTransaction tx = null;
		try {
			// 获取实体管理对象
			em = JpaUtils.getEntityManager();
			// 获取事务对象
			tx = em.getTransaction();
			// 开启事务
			tx.begin();
			// 执行操作
			em.persist(c);
			// 提交事务
			tx.commit();
		} catch (Exception e) {
			// 回滚事务
			tx.rollback();
			e.printStackTrace();
		} finally {
			// 释放资源
			em.close();
		}
	}
	/**
	 * 修改操作
	 */
	@Test
    public void testMerge(){
        //定义对象
        EntityManager em=null;
        EntityTransaction tx=null;
        try{
          	//获取实体管理对象
          	em=JpaUtils.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();
        }
    }

	/**
	 * 删除操作
	 */
	@Test
	public void testRemove() {
		// 定义对象
		EntityManager em = null;
		EntityTransaction tx = null;
		try {
			// 获取实体管理对象
			em = JpaUtils.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();
		}
	}

	/**
	 * 查询操作find()
	 */
	@Test
	public void testGetOne() {
		// 定义对象
		EntityManager em = null;
		EntityTransaction tx = null;
		try {
			// 获取实体管理对象
			em = JpaUtils.getEntityManager();
			// 获取事务对象
			tx = em.getTransaction();
			// 开启事务
			tx.begin();
			// 执行操作
			Customer c1 = em.find(Customer.class, 96);
			// 提交事务
			tx.commit();
			System.out.println(c1); // 输出查询对象
		} catch (Exception e) {
			// 回滚事务
			tx.rollback();
			e.printStackTrace();
		} finally {
			// 释放资源
			em.close();
		}
	}
}

虽然我们已经使用EntityManager对象完成了JPA的新增改查操作,但是我们这里还要介绍另外一种查询方式,那就是JPQL(java持久化查询语言),JPQL与hibernate的HQL方式类似。

package com.ithubei.test;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;
import javax.persistence.Query;
import org.junit.Test;
import com.ithubei.utils.JpaUtils;
/**
 * 使用JPQL(java持久化查询语言)来查询数据
 * @author DELL
 *
 */
public class JpqlTest {
	/**
	 * 查询全部的客户
	 */
	@Test
	public void findAll() {
		EntityManager em = null;
		EntityTransaction tx = null;
		try {
			//获取是管理对象
			em = JpaUtils.getEntityManager();
			//获取事务对象
			tx = em.getTransaction();
			//开启事务
			tx.begin();

			String jpql = "from Customer";
			//创建query对象
			Query query = em.createQuery(jpql);
			//使用query对象查询客户信息
			List list = query.getResultList();  //查询所有的客户
			for (Object object : list) {
				System.out.println(object);
			}

			//提交事务
			tx.commit();
		}catch (Exception e) {
			// TODO: handle exception
			//发生异常进行回滚
			tx.rollback();
			e.printStackTrace();
		}finally {
			//释放资源
			em.close();
		}
	}
		//分页查询客户
		@Test
		public void findPaged () {
			EntityManager em = null;
			EntityTransaction tx = null;
			try {
				//获取实体管理对象
				em = JpaUtils.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();
			}
		}

		//条件查询
		@Test
		public void findCondition () {
			EntityManager em = null;
			EntityTransaction tx = null;
			try {
				//获取实体管理对象
				em = JpaUtils.getEntityManager();
				//获取事务对象
				tx = em.getTransaction();
				tx.begin();
				//创建query对象
				String jpql = "from Customer where custName like ? ";
				Query query = em.createQuery(jpql);
				//对占位符赋值,从1开始
				query.setParameter(1, "传智%");
				//查询并得到返回结果
				Object object = query.getSingleResult(); //得到唯一的结果集对象
				System.out.println(object);
				tx.commit();
			} catch (Exception e) {
				// 回滚事务
				tx.rollback();
				e.printStackTrace();
			} finally {
				// 释放资源
				em.close();
			}
		}
		//根据客户id倒序查询所有客户
		//查询所有客户
		@Test
		public void testOrder() {
			EntityManager em = null;
			EntityTransaction tx = null;
			try {
				//获取实体管理对象
				em = JpaUtils.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();
			}
		}
		//统计查询
		@Test
		public void findCount() {
			EntityManager em = null;
			EntityTransaction tx = null;
			try {
				//获取实体管理对象
				em = JpaUtils.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();
			}
		}
}

通过以上等操作,我们就完成了JPA的crud操作。

接下来我们就开始使用spring data jpa来完成crud操作,让我们体会一下什么叫优势。

spring data jpa的crud操作:

首先我们需要引入依赖

<properties>
        <spring.version>4.2.4.RELEASE</spring.version>
        <hibernate.version>5.0.7.Final</hibernate.version>
        <slf4j.version>1.6.6</slf4j.version>
        <log4j.version>1.2.12</log4j.version>
        <c3p0.version>0.9.1.2</c3p0.version>
        <mysql.version>5.1.6</mysql.version>
    </properties>
    <dependencies>
        <!-- junit单元测试 -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.9</version>
            <scope>test</scope>
        </dependency>

        <!-- spring beg -->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.6.8</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-orm</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <!-- spring end -->
        <!-- hibernate beg -->
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-core</artifactId>
            <version>${hibernate.version}</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-entitymanager</artifactId>
            <version>${hibernate.version}</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-validator</artifactId>
            <version>5.2.1.Final</version>
        </dependency>
        <!-- hibernate end -->
        <!-- c3p0 beg -->
        <dependency>
            <groupId>c3p0</groupId>
            <artifactId>c3p0</artifactId>
            <version>${c3p0.version}</version>
        </dependency>
        <!-- c3p0 end -->
        <!-- log end -->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>${log4j.version}</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>${slf4j.version}</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>${slf4j.version}</version>
        </dependency>
        <!-- log end -->

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>${mysql.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-jpa</artifactId>
            <version>1.9.0.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>4.2.4.RELEASE</version>
        </dependency>

        <!-- el beg 使用spring data jpa 必须引入 -->
        <dependency>
            <groupId>javax.el</groupId>
            <artifactId>javax.el-api</artifactId>
            <version>2.2.4</version>
        </dependency>  

        <dependency>
            <groupId>org.glassfish.web</groupId>
            <artifactId>javax.el</artifactId>
            <version>2.2.4</version>
        </dependency>
        <!-- el end -->
    </dependencies>

创建spring配置文件applicationContext.xml,使用spring来管理

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:jpa="http://www.springframework.org/schema/data/jpa" xmlns:task="http://www.springframework.org/schema/task"
	xsi:schemaLocation="
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
		http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
		http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
		http://www.springframework.org/schema/data/jpa
		http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">

	<!-- 1.dataSource 配置数据库连接池-->
	<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
		<property name="driverClass" value="com.mysql.jdbc.Driver" />
		<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/jpa?characterEncoding=utf-8" />
		<property name="user" value="root" />
		<property name="password" value="root" />
	</bean>

	<!-- 2.配置entityManagerFactory -->
	<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
		<property name="dataSource" ref="dataSource" />
		<property name="packagesToScan" value="com.ithubei.entity" />
		<property name="persistenceProvider">
			<bean class="org.hibernate.jpa.HibernatePersistenceProvider" />
		</property>
		<!--JPA的供应商适配器-->
		<property name="jpaVendorAdapter">
			<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
				<property name="generateDdl" value="false" />
				<property name="database" value="MYSQL" />
				<property name="databasePlatform" value="org.hibernate.dialect.MySQLDialect" />
				<property name="showSql" value="true" />
			</bean>
		</property>
		<property name="jpaDialect">
			<bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
		</property>
	</bean>    

	<!-- 3.事务管理器-->
	<!-- JPA事务管理器  -->
	<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
		<property name="entityManagerFactory" ref="entityManagerFactory" />
	</bean>

	<!-- 整合spring data jpa-->
	<jpa:repositories base-package="com.ithubei.dao"
		transaction-manager-ref="transactionManager"
		entity-manager-factory-ref="entityManagerFactory"></jpa:repositories>

	<!-- 4.txAdvice-->
	<tx:advice id="txAdvice" transaction-manager="transactionManager">
		<tx:attributes>
			<tx:method name="save*" propagation="REQUIRED"/>
			<tx:method name="insert*" propagation="REQUIRED"/>
			<tx:method name="update*" propagation="REQUIRED"/>
			<tx:method name="delete*" propagation="REQUIRED"/>
			<tx:method name="get*" read-only="true"/>
			<tx:method name="find*" read-only="true"/>
			<tx:method name="*" propagation="REQUIRED"/>
		</tx:attributes>
	</tx:advice>

	<!-- 5.aop-->
	<aop:config>
		<aop:pointcut id="pointcut" expression="execution(* com.ithubei.service.*.*(..))" />
		<aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut" />
	</aop:config>

	<context:component-scan base-package="com.ithubei"></context:component-scan>
	<!--组装其它 配置文件-->
</beans>

创建和数据库表映射的实体类

package com.ithubei.entity;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
/**
 *
 *      * 所有的注解都是使用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;

    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;
    }
}

创建dao层接口CustomerDao,并继承JpaRepository和JpaSpecificationExecutor接口

/**
 * 定义一个dao层接口,此接口只需要继承JpaRepository和JpaSpecificationExecutor接口即可,该接口就具备了增删改	*   查和分页等功能。
 * JpaRepository<实体类类型,主键类型>:完成基本的CRUD操作
 * JpaSpecificationExecutor<实体类类型>:用于复杂查询(分页等查询操作)
 * @author DELL
 *
 */
public interface CustomerDao extends JpaRepository<Customer, Long>, JpaSpecificationExecutor<Customer>{
}

dao层编码已经写好了,现在我们就可以来测试CustomerDao来实现crud操作。

package com.ithubei.test;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.ithubei.dao.CustomerDao;
import com.ithubei.entity.Customer;
/**
 * 测试:调用CustomerDao接口完成增删改查就等操作
 * @author DELL
 *
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations="classpath:applicationContext.xml")
public class CustomerDaoTest {

	@Autowired
	private CustomerDao customerDao;

	/**
	 * 保存操作:调用save()方法
	 */
	@Test
	public void testSave() {
		Customer customer = new Customer();
		customer.setCustName("黑马程序员");
		//保存
		customerDao.save(customer);
	}
	/**
	 * 修改客户信息:调用save()方法
	 * 	对于save():如果执行此方法时对象中存在id属性,即为更新操作,会根据id查询,再更新
	 * 如果此方法中不存在id属性,则为保存操作
	 */
	@Test
	public void testUpdate() {
		//先根据id查询id为1的客户
		Customer customer = customerDao.findOne(96l);
		//修改客户名称
		customer.setCustName("授课123");
		//更新
		customerDao.save(customer);
	}

	/**
	 * 删除操作
	 */
	@Test
	public void testDelete() {
		customerDao.delete(96l);
	}

	/**
	 * 根据id查询:调用findOne()
	 */
	@Test
	public void testFindById() {
		Customer customer = customerDao.findOne(97l);
		System.out.println(customer);
	}
}

通过以上测试,我们发现CustomerDao接口下并没有写任何的方法,但是它却具备了crud等操作,只是因为它继承了JpaRepository和JpaSpecificationExecutor两个接口,我们就可以使用这两个接口为我们提供的方法来进行crud等操作。

现在我们就来看一下这两个接口下的方法列表:

这两个接口中定义了如此多的方法,方便我们在我们项目中完成基本的操作了。

spring data jpa是一个优势,它减轻了我们的工作量。所以学会它是每个程序员应该做的事情,建议大家都能够去学好它。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • 使用Spring Data JPA的坑点记录总结

    前言 Spring-data-jpa的基本介绍:JPA诞生的缘由是为了整合第三方ORM框架,建立一种标准的方式,百度百科说是JDK为了实现ORM的天下归一,目前也是在按照这个方向发展,但是还没能完全实现.在ORM框架中,Hibernate是一支很大的部队,使用很广泛,也很方便,能力也很强,同时Hibernate也是和JPA整合的比较良好,我们可以认为JPA是标准,事实上也是,JPA几乎都是接口,实现都是Hibernate在做,宏观上面看,在JPA的统一之下Hibernate很良好的运行. 最近在

  • spring data jpa使用详解(推荐)

    使用Spring data JPA开发已经有一段时间了,这期间学习了一些东西,也遇到了一些问题,在这里和大家分享一下. 前言: Spring data简介: Spring Data是一个用于简化数据库访问,并支持云服务的开源框架.其主要目标是使得对数据的访问变得方便快捷,并支持map-reduce框架和云计算数据服务. Spring Data 包含多个子项目: Commons - 提供共享的基础框架,适合各个子项目使用,支持跨数据库持久化 JPA - 简化创建 JPA 数据访问层和跨存储的持久层

  • Spring Data JPA 简单查询--方法定义规则(详解)

    一.常用规则速查 1 And 并且 2 Or   或 3 Is,Equals 等于 4 Between   两者之间 5 LessThan 小于 6 LessThanEqual   小于等于 7 GreaterThan 大于 8 GreaterThanEqual   大于等于 9 After 之后(时间) > 10 Before 之前(时间) < 11 IsNull 等于Null 12 IsNotNull,NotNull 不等于Null 13 Like 模糊查询.查询件中需要自己加 % 14

  • Spring Boot中使用Spring-data-jpa的配置方法详解

    为了解决这些大量枯燥的数据操作语句,我们第一个想到的是使用ORM框架,比如:hibernate.通过整合Hibernate之后,我们以操作Java实体的方式最终将数据改变映射到数据库表中. 为了解决抽象各个Java实体基本的"增删改查"操作,我们通常会以泛型的方式封装一个模板Dao来进行抽象简化,但是这样依然不是很方便,我们需要针对每个实体编写一个继承自泛型模板Dao的接口,再编写该接口的实现.虽然一些基础的数据访问已经可以得到很好的复用,但是在代码结构上针对每个实体都会有一堆Dao的

  • 详谈hibernate,jpa与spring data jpa三者之间的关系

    目录 前提 文字说明 CRUD操作 前提 其实很多框架都是对另一个框架的封装,我们在学习类似的框架的时候,难免会进入误区,所以我们就应该对其进行总结归纳,对比.本文就是对hibernate,jpa,spring data jpa三者之间进行文字对比,以及对其三者分别进行CRUD操作. 文字说明 Hibernate Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,它将POJO与数据库表建立映射关系,是一个全自动的orm框架,hibernate可以自动生

  • SpringBoot集成Spring Data JPA及读写分离

    相关代码: github OSCchina JPA是什么 JPA(Java Persistence API)是Sun官方提出的Java持久化规范,它为Java开发人员提供了一种对象/关联映射工具 来管理Java应用中的关系数据.它包括以下几方面的内容: 1.ORM映射 支持xml和注解方式建立实体与表之间的映射. 2.Java持久化API 定义了一些常用的CRUD接口,我们只需直接调用,而不需要考虑底层JDBC和SQL的细节. 3.JPQL查询语言 这是持久化操作中很重要的一个方面,通过面向对象

  • 记录一个使用Spring Data JPA设置默认值的问题

    目录 Spring Data JPA设置默认值的问题 一开始经过百度,写法是这样的 于是改了第二版 在大佬的指点下,有了第三种写法 Jpa设置默认值约束 1.修改建表时的列定义属性 2.通过Hibernate(org.hibernate.annotations.ColumnDefault) Spring Data JPA设置默认值的问题 我有一个entity实体,其中里面有一个布尔类型的字段: //entity table注解略 public class TableEntity { privat

  • 解决spring data jpa saveAll() 保存过慢问题

    目录 spring data jpa saveAll() 保存过慢 问题发现 解决方案1 此方案在第二天失效了 以上方案有问题,下面附上彻底解决的截图和记录 JPA的saveAll方法执行效率很差 spring data jpa saveAll() 保存过慢 问题发现 今天在生产环境执行保存数据时 影响队列中其他程序的运行 随后加日志排查 发现 执行 4500条 insert操作时 耗时 9分钟 我类个去- 解决方案1 此方案在第二天失效了 废话不多说 直接上配置文件参数 application

  • Spring Data JPA的Audit功能审计数据库的变更

    我最新最全的文章都在南瓜慢说 www.pkslow.com,欢迎大家来喝茶! 1 数据库审计 数据库审计是指当数据库有记录变更时,可以记录数据库的变更时间和变更人等,这样以后出问题回溯问责也比较方便.对于审计表记录的变更可以两种方式,一种是建立一张审计表专门用于记录,另一种是在数据库增加字段.本文所讨论的是第二种方案. 那如何在新增.修改.删除的时候同时增加记录呢?如果每张表都单独记录,代码就会显得很冗余.更好的方式应该是做切面或者事件监听,当数据有变更时统一进行记录. 2 Spring Dat

  • 解析Spring Data JPA的Audit功能之审计数据库变更

    一.数据库审计 数据库审计是指当数据库有记录变更时,可以记录数据库的变更时间和变更人等,这样以后出问题回溯问责也比较方便.对于审计表记录的变更可以两种方式,一种是建立一张审计表专门用于记录,另一种是在数据库增加字段.本文所讨论的是第二种方案. 那如何在新增.修改.删除的时候同时增加记录呢?如果每张表都单独记录,代码就会显得很冗余.更好的方式应该是做切面或者事件监听,当数据有变更时统一进行记录. 二.Spring Data JPA审计 Spring Data JPA为我们提供了方便的Audit功能

  • Spring Data Jpa 中原生查询 REGEXP 的使用详解

    目录 Spring Data Jpa原生查询 REGEXP 的使用 spring data jpa 原生查询(查一个json中的某一字段) Spring Data Jpa原生查询 REGEXP 的使用 REGEXP 与like 有通用之处, 单 regexp 有更好的精确度,更加自由灵活 在jpa 中使用时 :其中 定位符 ^ 在jpa @query 注解中使用时需要加上引用号 e.g @Query(value = "select p.id as id from zt_products AS p

  • Spring Boot深入学习数据访问之Spring Data JPA与Hibernate的应用

    目录 前言 Spring Boot的支持 前言 Hibernate是一个开源的对象关系映射框架,它对JDBC及进行了非常轻量级的对象封装,它将POJO简单的java对象与数据库表建立映射关系,是一个全自动的ORM框架,Hibernate可以自动生成SQL语句自动执行. JPA是官方提出的Java持久化规范,JPA通过注解或XML描述对象一关系表的映射关系,并将内存中的实体对象持久化到数据库 Spring Data JPA通过提供基于JPA的Repository极大的简化了JPA的写法,在几乎不写

  • 详解基于Spring Boot与Spring Data JPA的多数据源配置

    由于项目需要,最近研究了一下基于spring Boot与Spring Data JPA的多数据源配置问题.以下是传统的单数据源配置代码.这里使用的是Spring的Annotation在代码内部直接配置的方式,没有使用任何XML文件. @Configuration @EnableJpaRepositories(basePackages = "org.lyndon.repository") @EnableTransactionManagement @PropertySource("

随机推荐