springdata简介
是Spring 的一个子项目。用于简化数据库访问,支持NoSQL 和 关系数据存储。其主要目标是使数据库的访问变得方便快捷。
相关概述
ORM概述
ORM(Object-Relational Mapping) 表示对象关系映射。在面向对象的软件开发中,通过ORM,就可以把对象映射到关系型数据库中。只要有一套程序能够做到建立对象与数据库的关联,操作对象就可以直接操作数据库数据,就可以说这套程序实现了ORM对象关系映射
简单的说:实现一个应用程序时(不使用O/R Mapping),可能会写特别多数据访问层的代码,从数据库保存数据、修改数据、删除数据,而这些代码都是重复的。而使用ORM则会大大减少重复性代码。ORM就是建立实体类和数据库表之间的关系,从而达到操作实体类就相当于操作数据库表的目的。
hibernate概述
Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,它将POJO与数据库表建立映射关系,是一个全自动的orm框架,hibernate可以自动生成SQL语句,自动执行,使得Java程序员可以随心所欲的使用对象编程思维来操纵数据库。
JPA概述
JPA的全称是Java Persistence API, 即Java 持久化API,是SUN公司推出的一套基于ORM的规范,内部是由一系列的接口和抽象类构成。
JPA通过JDK 5.0注解描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中。
JPA和Hibernate的关系就像JDBC和JDBC驱动的关系,JPA是规范,Hibernate除了作为ORM框架之外,它也是一种JPA实现。JPA怎么取代Hibernate呢?JDBC规范可以驱动底层数据库吗?答案是否定的,也就是说,如果使用JPA规范进行数据库操作,底层需要hibernate作为其实现类完成数据持久化工作。
JPA案例
1、Maven工程pom.xml中导入坐标
<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>
<!-- jdbc驱动jar包 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
</dependency>
</dependencies>
2、配置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/jpa" />
<!-- 数据库用户名 -->
<property name="javax.persistence.jdbc.user" value="root" />
<!-- 数据库密码 -->
<property name="javax.persistence.jdbc.password" value="rootroot" />
<!--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>
3、创建数据库表
CREATE TABLE per_student (
per_id bigint(32) NOT NULL AUTO_INCREMENT COMMENT '学生编号(主键)',
per_name varchar(32) NOT NULL COMMENT '学生姓名',
per_age int DEFAULT NULL COMMENT '学生年龄',
per_sex varchar(2) DEFAULT NULL COMMENT '学生性别',
per_major varchar(32) DEFAULT NULL COMMENT '学生专业',
per_phone varchar(64) DEFAULT NULL COMMENT '学生联系电话',
PRIMARY KEY (`per_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
4、创建实体类
import java.io.Serializable;
import javax.persistence.*
/**
* * 所有的注解都是使用JPA的规范提供的注解,
* * 所以在导入注解包的时候,一定要导入javax.persistence下的
*/
@Entity //声明实体类
@Table(name="per_student") //建立实体类和表的映射关系
public class Student implements Serializable{
@Id//声明当前私有属性为主键
@GeneratedValue(strategy=GenerationType.IDENTITY) //配置主键的生成策略
@Column(name="per_id") //指定和表中per_id字段的映射关系
private Long perId;
@Column(name="per_name") //指定和表中per_name字段的映射关系
private String perName;
@Column(name="per_age")//指定和表中per_age字段的映射关系
private String perAge;
@Column(name="per_sex")//指定和表中per_sex字段的映射关系
private String perSex;
@Column(name="per_major")//指定和表中per_major字段的映射关系
private String perMajor;
@Column(name="per_phone")//指定和表中per_phone字段的映射关系
private String perPhone;
public Long getPerId() {
return perId;
}
public void setPerId(Long perId) {
this.perId = perId;
}
public String getPerName() {
return perName;
}
public void setPerName(String perName) {
this.perName = perName;
}
public int getPerAge() {
return perAge;
}
public void setPerAge(int perAge) {
this.perAge = perAge;
}
public String getPerSex() {
return perSex;
}
public void setPerSex(String perSex) {
this.perSex = perSex;
}
public String getPerMajor() {
return perMajor;
}
public void setPerMajor(String perMajor) {
this.perMajor = perMajor;
}
public String getPerPhone() {
return perPhone;
}
public void setPerPhone(String perPhone) {
this.perPhone = perPhone;
}
}
补充
@Entity
作用:指定当前类是实体类。
@Table
作用:指定实体类和表之间的对应关系。
属性:
name:指定数据库表的名称
@Id
作用:指定当前字段是主键。
@GeneratedValue
作用:指定主键的生成方式。。
属性:
strategy :指定主键生成策略。
@Column
作用:指定实体类属性和数据库表之间的对应关系
属性:
name:指定数据库表的列名称。
unique:是否唯一
nullable:是否可以为空
inserttable:是否可以插入
updateable:是否可以更新
columnDefinition: 定义建表时创建此列的DDL
secondaryTable: 从表名。如果此列不建在主表上(默认建在主表),该属性定义该列所在从表的名字搭建开发环境
5、测试-添加数据
@Test
public void test() {
/**
* 创建实体管理类工厂,借助Persistence的静态方法获取
* 其中传递的参数为持久化单元名称,需要jpa配置文件中指定
*/
EntityManagerFactory factory = Persistence.createEntityManagerFactory("myJpa");
//创建实体管理类
EntityManager em = factory.createEntityManager();
//获取事务对象
EntityTransaction tx = em.getTransaction();
//开启事务
tx.begin();
Student c = new Student();
c.setPerName("张三");
c.setPerAge(18);
c.setPerSex("男");
c.setPerMajor("java开发攻城狮");
c.setPerPhone("17856520896");
//保存操作
em.persist(c);
//提交事务
tx.commit();
//释放资源
em.close();
factory.close();
}
JPA的API介绍
Persistence对象
Persistence对象主要作用是用于获取EntityManagerFactory对象的 。通过调用该类的createEntityManagerFactory静态方法,根据配置文件中持久化单元名称创建EntityManagerFactory。
@Test
String unitName = "myJpa";
EntityManagerFactory factory= Persistence.createEntityManagerFactory(unitName);
EntityManagerFactory
EntityManagerFactory 接口主要用来创建 EntityManager 实例
//创建实体管理类EntityManager em = factory.createEntityManager();
由于EntityManagerFactory 是一个线程安全的对象(即多个线程访问同一个EntityManagerFactory 对象不会有线程安全问题),并且EntityManagerFactory 的创建极其浪费资源,所以在使用JPA编程时,我们可以对EntityManagerFactory 的创建进行优化,只需要做到一个工程只存在一个EntityManagerFactory 即可
EntityManager
在 JPA 规范中, EntityManager是完成持久化操作的核心对象。实体类作为普通 java对象,只有在调用 EntityManager将其持久化后才会变成持久化对象。EntityManager对象在一组实体类与底层数据源之间进行 O/R 映射的管理。它可以用来管理和更新 Entity Bean, 根椐主键查找 Entity Bean, 还可以通过JPQL语句查询实体。
我们可以通过调用EntityManager的方法完成获取事务,以及持久化数据库的操作
方法说明:
getTransaction : 获取事务对象
persist : 保存操作
merge : 更新操作
remove : 删除操作
find/getReference : 根据id查询
EntityTransaction
在 JPA 规范中, EntityTransaction是完成事务操作的核心对象,对于EntityTransaction在我们的java代码中承接的功能比较简单
begin:开启事务
commit:提交事务
rollback:回滚事务
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();
}
}
JPA增删改查
添加
@Test
public void Add() {
// 定义对象
Student c = new Student();
c.setPerName("张三");
c.setPerAge(18);
c.setPerSex("男");
c.setPerMajor("java开发攻城狮");
c.setPerPhone("17856520896");
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();
}
}
修改
@Test
public void Merge(){
//定义对象
EntityManager em=null;
EntityTransaction tx=null;
try{
//获取实体管理对象
em=JPAUtil.getEntityManager();
//获取事务对象
tx=em.getTransaction();
//开启事务
tx.begin();
//执行操作
Student c1 = em.find(Student.class, 1L);
c1.setPerName("李四");
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 = JPAUtil.getEntityManager();
// 获取事务对象
tx = em.getTransaction();
// 开启事务
tx.begin();
// 执行操作
Student c1 = em.find(Student.class,1L);
em.remove(c1);
// 提交事务
tx.commit();
} catch (Exception e) {
// 回滚事务
tx.rollback();
e.printStackTrace();
} finally {
// 释放资源
em.close();
}
}
查询
根据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();
}
}
延迟加载的策略方法:
/**
* 查询一个: 使用延迟加载策略
*/
@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);
} catch (Exception e) {
// 回滚事务
tx.rollback();
e.printStackTrace();
} finally {
// 释放资源
em.close();
}
}
查询全部
//查询所有
@Test
public void findAll() {
EntityManager em = null;
EntityTransaction tx = null;
try {
//获取实体管理对象
em = JPAUtil.getEntityManager();
//获取事务对象
tx = em.getTransaction();
tx.begin();
// 创建query对象
String jpql = "from Student";
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 findPaged () {
EntityManager em = null;
EntityTransaction tx = null;
try {
//获取实体管理对象
em = JPAUtil.getEntityManager();
//获取事务对象
tx = em.getTransaction();
tx.begin();
//创建query对象
String jpql = "from Student";
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 = JPAUtil.getEntityManager();
//获取事务对象
tx = em.getTransaction();
tx.begin();
//创建query对象
String jpql = "from Student where perName 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 = JPAUtil.getEntityManager();
//获取事务对象
tx = em.getTransaction();
tx.begin();
// 创建query对象
String jpql = "from Student order by perId 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 = JPAUtil.getEntityManager();
//获取事务对象
tx = em.getTransaction();
tx.begin();
// 查询全部客户
// 1.创建query对象
String jpql = "select count(perId) from Student";
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();
}
}
Spring Data JPA
概述
Spring Data JPA 是 Spring 基于 ORM 框架、JPA 规范的基础上封装的一套JPA应用框架,可使开发者用极简的代码即可实现对数据库的访问和操作。它提供了包括增删改查等在内的常用功能,且易于扩展!学习并使用 Spring Data JPA 可以极大提高开发效率!
Spring Data JPA 让我们解脱了DAO层的操作,基本上所有CRUD都可以依赖于它来实现,在实际的工作工程中,推荐使用Spring Data JPA + ORM(如:hibernate)完成操作,这样在切换不同的ORM框架时提供了极大的方便,同时也使数据库层操作更加简单,方便解耦
Spring Data JPA 与 JPA和hibernate之间的关系
JPA是一套规范,内部是有接口和抽象类组成的。hibernate是一套成熟的ORM框架,而且Hibernate实现了JPA规范,所以也可以称hibernate为JPA的一种实现方式,我们使用JPA的API编程,意味着站在更高的角度上看待问题(面向接口编程)
Spring Data JPA是Spring提供的一套对JPA操作更加高级的封装,是在JPA规范下的专门用来进行数据持久化的解决方案。
Spring Data JPA案例
引入Spring Data JPA的坐标
<!-- 公共版本号 -->
<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 aspectj -->
<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>
<!-- hibernate -->
<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>
<!-- c3p0 -->
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>${c3p0.version}</version>
</dependency>
<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>
<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>
<!-- 使用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>
</dependencies>
Spring整合Spring Data JPA
<?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" />
<property name="user" value="root" />
<property name="password" value="rootroot" />
</bean>
<!-- 2.配置entityManagerFactory -->
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<!-- 配置扫描实体类所在的包 -->
<property name="packagesToScan" value="com.dzkj.domain" />
<!-- jpa实现厂家 -->
<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>
<!--注入jpa的配置信息
加载jpa的基本配置信息和jpa实现方式(hibernate)的配置信息
hibernate.hbm2ddl.auto : 自动创建数据库表
create : 每次都会重新创建数据库表
update:有表不会重新创建,没有表会重新创建表
-->
<property name="jpaProperties" >
<props>
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</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.dzkj.dao"
transaction-manager-ref="transactionManager"
entity-manager-factory-ref="entityManagerFactory"></jpa:repositories>
<!-- 4.声明式事务-->
<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="mypoint" expression="execution(* com.dzkj.service.*.*(..))" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="mypoint" />
</aop:config>
<context:component-scan base-package="com.dzkj"></context:component-scan>
</beans>
JPA注解配置实体类映射关系
import javax.persistence.*;
/**
* * 所有的注解都是使用JPA的规范提供的注解,
* * 所以在导入注解包的时候,一定要导入javax.persistence下的
*/
@Entity
@Table(name="per_student") //建立实体类和表的映射关系
public class Student implements Serializable{
@Id//声明当前私有属性为主键
@GeneratedValue(strategy=GenerationType.IDENTITY) //配置主键的生成策略
@Column(name="per_id") //指定和表中per_id字段的映射关系
private Long perId;
@Column(name="per_name") //指定和表中per_name字段的映射关系
private String perName;
@Column(name="per_age")//指定和表中per_age字段的映射关系
private int perAge;
@Column(name="per_sex")//指定和表中per_sex字段的映射关系
private String perSex;
@Column(name="per_major")//指定和表中per_major字段的映射关系
private String perMajor;
@Column(name="per_phone")//指定和表中per_phone字段的映射关系
private String perPhone;
public Long getPerId() {
return perId;
}
public void setPerId(Long perId) {
this.perId = perId;
}
public String getPerName() {
return perName;
}
public void setPerName(String perName) {
this.perName = perName;
}
public int getPerAge() {
return perAge;
}
public void setPerAge(int perAge) {
this.perAge = perAge;
}
public String getPerSex() {
return perSex;
}
public void setPerSex(String perSex) {
this.perSex = perSex;
}
public String getPerMajor() {
return perMajor;
}
public void setPerMajor(String perMajor) {
this.perMajor = perMajor;
}
public String getPerPhone() {
return perPhone;
}
public void setPerPhone(String perPhone) {
this.perPhone = perPhone;
}
}
编写Spring Data JPA规范的Dao层接口
1.创建一个Dao层接口,并实现JpaRepository和JpaSpecificationExecutor
2.提供相应的泛型
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import com.dzkj.Student;
/**
* JpaRepository<实体类类型,主键类型>:用来完成基本CRUD操作
* JpaSpecificationExecutor<实体类类型>:用于复杂查询(分页等查询操作)
*/
public interface StudentDao extends JpaRepository<Student, Long>, JpaSpecificationExecutor<Student> {
}
CRUD操作
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations="classpath:applicationContext.xml")
public class StudenDaoTest {
@Autowired
private StudentDao studentDao;
/**
* 添加学生:调用save(obj)方法
*/
@Test
public void testSave() {
Student c = new Student();
c.setperName("李四");
studentDao.save(c);
}
/**
* 修改学生:调用save(obj)方法
* 对于save方法的解释:如果执行此方法是对象中存在id属性,即为更新操作会先根据id查询,再更新
* 如果执行此方法中对象中不存在id属性,即为保存操作
*/
@Test
public void testUpdate() {
//根据id查询id为1的学生
Student student = studentDao.findOne(1l);
//修改学生名称
student.setCustName("张三");
//更新
studentDao.save(student);
}
/**
* 根据id删除:调用delete(id)方法
*/
@Test
public void testDelete() {
studentDao.delete(1l);
}
/**
* 根据id查询:调用findOne(id)方法
*/
@Test
public void testFindById() {
Student student = studentDao.findOne(2l);
System.out.println(student);
}
}
spring内部原理
Spring Data JPA 工作原理 : 自定义JpaRespository接口却不用提供实现
JPQL的方式查询
使用Spring Data JPA提供的查询方法已经可以解决大部分的应用场景,对于某些业务来说,还需要灵活的构造查询条件,这时就可以使用@Query注解,结合JPQL的语句方式完成查询,@Query 只需在方法上面标注该注解,同时提供一个JPQL查询语句,使用时调用该方法就可以了
public interface CustomerDao extends JpaRepository<Customer, Long>,JpaSpecificationExecutor<Customer> {
//@Query 使用jpql的方式查询所有。
@Query(value="from Student")
public List<Student> findAllStudent();
//@Query 使用jpql的方式查询。?1代表参数的占位符,其中1对应方法中的参数索引
@Query(value="from Student where perName = ?1")
public Student findStudent(String perName);
//在使用 @Query 的同时,用 @Modifying 来将该操作标识为修改查询,框架最终会生成一个更新的操作,而非查询
@Query(value="update Student set perName = ?1 where perId = ?2")
@Modifying
public void updateStudent(String perName,Long perId);
}
SQL语句查询
/**
* nativeQuery :false(使用jpql查询) | true(使用本地查询:sql查询)
* 默认jpql查询
*/
@Query(value="select * from per_student",nativeQuery=true)
public void findSql();
方法命名规则查询
需要按照Spring Data JPA提供的方法命名规则定义方法的名称,Spring Data JPA在程序执行的时候会根据方法名称进行解析,并自动生成查询语句进行查询
按照Spring Data JPA 定义的规则,查询方法以findBy开头,涉及条件查询时,条件的属性用条件关键字连接,要注意的是:条件属性首字母需大写。框架在进行方法名解析时,会先把方法名多余的前缀截取掉,然后对剩下部分进行解析。
//方法命名方式查询(根据客户名称查询客户)
public Customer findByPerName(String perName);
具体的关键字,使用方法和生产成SQL如下表所示
: Keyword : | : Sample : | : JPQL : |
---|---|---|
:And: | :findByLastnameAndFirstname: | :… where x.lastname = ?1 and x.firstname = ?2: |
:Or: | :findByLastnameOrFirstname: | :… where x.lastname = ?1 or x.firstname = ?2: |
:Is,Equals : | : findByFirstnameIs,findByFirstnameEquals : | :… where x.firstname = ?1: |
:Between: | :findByStartDateBetween: | :… where x.startDate between ?1 and ?2: |
:LessThan: | :findByAgeLessThan: | :… where x.age < ?1: |
:LessThanEqual: | :findByAgeLessThanEqual: | :… where x.age ⇐ ?1: |
:GreaterThan: | :findByAgeGreaterThan: | :… where x.age > ?1: |
:GreaterThanEqual: | :findByAgeGreaterThanEqual: | :… where x.age >= ?1: |
:After: | :findByStartDateAfter: | :… where x.startDate > ?1: |
:Before: | :findByStartDateBefore: | :… where x.startDate < ?1: |
:IsNull: | :findByAgeIsNull: | :… where x.age is null: |
:IsNotNull,NotNull: | :findByAge(Is)NotNull: | :… where x.age not null: |
:Like: | :findByFirstnameLike: | :… where x.firstname like ?1: |
:NotLike: | :findByFirstnameNotLike: | :… where x.firstname not like ?1: |
:StartingWith: | :findByFirstnameStartingWith: | :… where x.firstname like ?1 (parameter bound with appended %): |
:EndingWith: | :findByFirstnameEndingWith: | :… where x.firstname like ?1 (parameter bound with prepended %): |
:Containing: | :findByFirstnameContaining: | :… where x.firstname like ?1 (parameter bound wrapped in %): |
:OrderBy: | :findByAgeOrderByLastnameDesc: | :… where x.age = ?1 order by x.lastname desc: |
:Not: | :findByLastnameNot: | :… where x.lastname <> ?1: |
:In: | :findByAgeIn(Collection ages): | :… where x.age in ?1: |
:NotIn: | :findByAgeNotIn(Collection age): | :… where x.age not in ?1: |
:TRUE: | :findByActiveTrue(): | :… where x.active = true: |
:FALSE: | :findByActiveFalse(): | :… where x.active = false: |
:IgnoreCase: | :findByFirstnameIgnoreCase: | :… where UPPER(x.firstame) = UPPER(?1): |
Specifications动态查询
当查询某个实体的时候,给定的条件是不固定的,就需要动态构建相应的查询语句,在Spring Data JPA中可以通过JpaSpecificationExecutor接口查询。相比JPQL,其优势是类型安全,更加的面向对象。
Specifications 条件查询
//依赖注入customerDao
@Autowired
private StudentDao studentDao;
@Test
public void testSpecifications() {
//使用匿名内部类的方式,创建一个Specification的实现类,并实现toPredicate方法
/**
* root :Root接口,代表查询的根对象,可以通过root获取实体中的属性
* query :代表一个顶层查询对象,用来自定义查询
* cb :用来构建查询,此对象里有很多条件方法
**/
Specification <Student> spec = new Specification<Student>() {
public Predicate toPredicate(Root<Student> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
//cb:构建查询,添加查询方式 like:模糊匹配
//root:从实体Customer对象中按照custName属性进行查询
return cb.like(root.get("perName").as(String.class), "张三");
}
};
Student student = studentDao.findOne(spec);
System.out.println(student);
}
Specifications 分页查询
@Test
public void testPage() {
//构造查询条件
Specification<Student> spec = new Specification<Student>() {
public Predicate toPredicate(Root<Student> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
return cb.like(root.get("perName").as(String.class), "张三%");
}
};
/**
* 构造分页参数
* Pageable : 接口
* PageRequest实现了Pageable接口,调用构造方法的形式构造
* 第一个参数:页码(从0开始)
* 第二个参数:每页查询条数
*/
Pageable pageable = new PageRequest(0, 5);
/**
* 分页查询,封装为Spring Data Jpa 内部的page bean
* 此重载的findAll方法为分页方法需要两个参数
* 第一个参数:查询条件Specification
* 第二个参数:分页参数
*/
Page<Student> page = studentDao.findAll(spec,pageable);
/**
//获取总页数
page.getTotalPages();
//获取总记录数
page.getTotalElements();
//获取列表数据
page.getContent();
*/
}
映射的注解说明
@OneToMany:
作用:建立一对多的关系映射
属性:
targetEntityClass:指定多的多方的类的字节码
mappedBy:指定从表实体类中引用主表对象的名称。
cascade:指定要使用的级联操作
fetch:指定是否采用延迟加载
orphanRemoval:是否使用孤儿删除@ManyToOne
作用:建立多对一的关系
属性:
targetEntityClass:指定一的一方实体类字节码
cascade:指定要使用的级联操作
fetch:指定是否采用延迟加载
optional:关联是否可选。如果设置为false,则必须始终存在非空关系。@JoinColumn
作用:用于定义主键字段和外键字段的对应关系。
属性:
name:指定外键字段的名称
referencedColumnName:指定引用主表的主键字段名称
unique:是否唯一。默认值不唯一
nullable:是否允许为空。默认值允许。
insertable:是否允许插入。默认值允许。
updatable:是否允许更新。默认值允许。
columnDefinition:列的定义信息。
多表设计
一对多
数据库关系的建立
可以不用创建数据库表 借助springdatajpa的机制自动创建表,在配置文件中添加
<property name="jpaProperties" >
<props>
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
CREATE TABLE per_teacher(
tea_id bigint(32) NOT NULL AUTO_INCREMENT COMMENT '老师编号(主键)',
tea_name varchar(32) NOT NULL COMMENT '老师姓名',
tea_age int DEFAULT NULL COMMENT '老师年龄',
tea_sex varchar(2) DEFAULT NULL COMMENT '老师性别',
tea_major varchar(32) DEFAULT NULL COMMENT '授课专业',
tea_phone varchar(64) DEFAULT NULL COMMENT '老师联系电话',
PRIMARY KEY (`tea_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
CREATE TABLE per_student (
per_id bigint(32) NOT NULL AUTO_INCREMENT COMMENT '学生编号(主键)',
per_name varchar(32) NOT NULL COMMENT '学生姓名',
per_age int DEFAULT NULL COMMENT '学生年龄',
per_sex varchar(2) DEFAULT NULL COMMENT '学生性别',
per_major varchar(32) DEFAULT NULL COMMENT '学生专业',
per_phone varchar(64) DEFAULT NULL COMMENT '学生联系电话',
per_tea_id bigint(32) NOT NULL COMMENT '老师编号(外键)',
PRIMARY KEY (`per_id`),
foreign key(per_tea_id) references per_Teacher(tea_id)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
实体类关系建立
老师实体类
import java.util.HashSet;
import java.util.Set;
import javax.persistence.*;
@Entity//表示当前类是一个实体类
@Table(name="per_teacher")//建立当前实体类和表之间的对应关系
public class Teacher {
@Id//表明当前私有属性是主键
@GeneratedValue(strategy=GenerationType.IDENTITY)//指定主键的生成策略
@Column(name="tea_id")//指定和数据库表中的cust_id列对应
private Long teaId;
@Column(name="tea_name")
private String teaName;
@Column(name="tea_age")
private int teaAge;
@Column(name="tea_sex")
private String teaSex;
@Column(name="tea_major")
private String teaMajor;
@Column(name="tea_phone")
private String teaPhone;
//设置了双向关系后,会发送两条insert语句,一条多余的update语句,解决思路就是一方放弃维护权
@OneToMany(mappedBy="teacher",cascade = CascadeType.ALL)
private Set<Student> students = new HashSet<>();
public Long getTeaId() {
return teaId;
}
public void setTeaId(Long teaId) {
this.teaId = teaId;
}
public String getTeaName() {
return teaName;
}
public void setTeaName(String teaName) {
this.teaName = teaName;
}
public int getTeaAge() {
return teaAge;
}
public void setTeaAge(int teaAge) {
this.teaAge = teaAge;
}
public String getTeaSex() {
return teaSex;
}
public void setTeaSex(String teaSex) {
this.teaSex = teaSex;
}
public String getTeaMajor() {
return teaMajor;
}
public void setTeaMajor(String teaMajor) {
this.teaMajor = teaMajor;
}
public String getTeaPhone() {
return teaPhone;
}
public void setTeaPhone(String teaPhone) {
this.teaPhone = teaPhone;
}
public Set<Student> getStudents() {
return students;
}
public void setStudents(Set<Student> students) {
this.students = students;
}
@Override
public String toString() {
return "Teacher [teaId=" + teaId + ", teaName=" + teaName + ", teaAge=" + teaAge + ", teaSex=" + teaSex
+ ", teaMajor=" + teaMajor + ", teaPhone=" + teaPhone + ", students=" + students + "]";
}
}
学生实体类
import java.io.Serializable;
import javax.persistence.*;
@Entity
@Table(name="per_student") //建立实体类和表的映射关系
public class Student implements Serializable{
@Id//声明当前私有属性为主键
@GeneratedValue(strategy=GenerationType.IDENTITY) //配置主键的生成策略
@Column(name="per_id") //指定和表中per_id字段的映射关系
private Long perId;
@Column(name="per_name") //指定和表中per_name字段的映射关系
private String perName;
@Column(name="per_age")//指定和表中per_age字段的映射关系
private int perAge;
@Column(name="per_sex")//指定和表中per_sex字段的映射关系
private String perSex;
@Column(name="per_major")//指定和表中per_major字段的映射关系
private String perMajor;
@Column(name="per_phone")//指定和表中per_phone字段的映射关系
private String perPhone;
//多对一关系映射:多个学生对应老师
@ManyToOne(targetEntity=Teacher.class)
@JoinColumn(name="per_tea_id",referencedColumnName="tea_id")
private Teacher teacher;
public Long getPerId() {
return perId;
}
public void setPerId(Long perId) {
this.perId = perId;
}
public String getPerName() {
return perName;
}
public void setPerName(String perName) {
this.perName = perName;
}
public int getPerAge() {
return perAge;
}
public void setPerAge(int perAge) {
this.perAge = perAge;
}
public String getPerSex() {
return perSex;
}
public void setPerSex(String perSex) {
this.perSex = perSex;
}
public String getPerMajor() {
return perMajor;
}
public void setPerMajor(String perMajor) {
this.perMajor = perMajor;
}
public String getPerPhone() {
return perPhone;
}
public void setPerPhone(String perPhone) {
this.perPhone = perPhone;
}
public Teacher getTeacher() {
return teacher;
}
public void setTeacher(Teacher teacher) {
this.teacher = teacher;
}
@Override
public String toString() {
return "Student [perId=" + perId + ", perName=" + perName + ", perAge=" + perAge + ", perSex=" + perSex
+ ", perMajor=" + perMajor + ", perPhone=" + perPhone + ", teacher=" + teacher + "]";
}
}
添加
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional;
import com.dzkj.dao.StudentDao;
import com.dzkj.dao.TeacherDao;
import com.dzkj.domain.Student;
import com.dzkj.domain.Teacher;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations="classpath:applicationContext.xml")
public class OneToManyTest {
@Autowired
private TeacherDao teacherDao;
@Autowired
private StudentDao studentDao;
@Test
@Transactional //开启事务
@Rollback(false)//设置为不回滚
public void testAdd() {
Teacher t = new Teacher();
t.setTeaName("王老师");
t.setTeaAge(23);
t.setTeaSex("男");
t.setTeaMajor("java开发");
t.setTeaPhone("17856520899");
Student s = new Student();
s.setPerName("张三");
s.setPerAge(18);
s.setPerSex("男");
s.setPerMajor("java开发攻城狮");
s.setPerPhone("17856520896");
t.getStudents().add(s);
s.setTeacher(t);
teacherDao.save(t);
studentDao.save(s);
}
删除
有从表数据
1、在默认情况下,它会把外键字段置为null,然后删除主表数据。如果在数据库的表结构上,外键字段有非空约束,默认情况就会报错>了。
2、如果配置了放弃维护关联关系的权利,则不能删除(与外键字段是否允许为null, 没有关系)因为在删除时,它根本不会去更>新从表的外键字段了。
3、如果还想删除,使用级联删除引用没有从表数据引用:随便删
@Autowired
private CustomerDao customerDao;
@Test
@Transactional
@Rollback(false)//设置为不回滚
public void testDelete() {
customerDao.delete(1l);
}
级联操作
/**
* cascade:配置级联操作
* CascadeType.MERGE 级联更新
* CascadeType.PERSIST 级联保存:
* CascadeType.REFRESH 级联刷新:
* CascadeType.REMOVE 级联删除:
* CascadeType.ALL 包含所有
*/
@OneToMany(mappedBy="Teacher",cascade=CascadeType.ALL)
多对多
实体类关系配置
用户实体类
/**
* 用户的数据模型
*/
@Entity
@Table(name="sys_user")
public class SysUser implements Serializable {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name="user_id")
private Long userId;
@Column(name="user_code")
private String userCode;
@Column(name="user_name")
private String userName;
@Column(name="user_password")
private String userPassword;
@Column(name="user_state")
private String userState;
//多对多关系映射
@ManyToMany(mappedBy="users")
private Set<SysRole> roles = new HashSet<SysRole>(0);
public Long getUserId() {
return userId;
}
public void setUserId(Long userId) {
this.userId = userId;
}
public String getUserCode() {
return userCode;
}
public void setUserCode(String userCode) {
this.userCode = userCode;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getUserPassword() {
return userPassword;
}
public void setUserPassword(String userPassword) {
this.userPassword = userPassword;
}
public String getUserState() {
return userState;
}
public void setUserState(String userState) {
this.userState = userState;
}
public Set<SysRole> getRoles() {
return roles;
}
public void setRoles(Set<SysRole> roles) {
this.roles = roles;
}
@Override
public String toString() {
return "SysUser [userId=" + userId + ", userCode=" + userCode + ", userName=" + userName + ", userPassword="
+ userPassword + ", userState=" + userState + "]";
}
}
角色实体类
/**
* 角色的数据模型
*/
@Entity
@Table(name="sys_role")
public class SysRole implements Serializable {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name="role_id")
private Long roleId;
@Column(name="role_name")
private String roleName;
@Column(name="role_memo")
private String roleMemo;
//多对多关系映射
@ManyToMany
@JoinTable(name="user_role_rel",//中间表的名称
//中间表user_role_rel字段关联sys_role表的主键字段role_id
joinColumns={@JoinColumn(name="role_id",referencedColumnName="role_id")},
//中间表user_role_rel的字段关联sys_user表的主键user_id
inverseJoinColumns={@JoinColumn(name="user_id",referencedColumnName="user_id")}
)
private Set<SysUser> users = new HashSet<SysUser>(0);
public Long getRoleId() {
return roleId;
}
public void setRoleId(Long roleId) {
this.roleId = roleId;
}
public String getRoleName() {
return roleName;
}
public void setRoleName(String roleName) {
this.roleName = roleName;
}
public String getRoleMemo() {
return roleMemo;
}
public void setRoleMemo(String roleMemo) {
this.roleMemo = roleMemo;
}
public Set<SysUser> getUsers() {
return users;
}
public void setUsers(Set<SysUser> users) {
this.users = users;
}
@Override
public String toString() {
return "SysRole [roleId=" + roleId + ", roleName=" + roleName + ", roleMemo=" + roleMemo + "]";
}
}
添加
@Autowired
private UserDao userDao;
@Autowired
private RoleDao roleDao;
/**
* 需求:
* 保存用户和角色
* 要求:
* 创建2个用户和3个角色
* 让1号用户具有1号和2号角色(双向的)
* 让2号用户具有2号和3号角色(双向的)
* 保存用户和角色
* 问题:
* 在保存时,会出现主键重复的错误,因为都是要往中间表中保存数据造成的。
* 解决办法:
* 让任意一方放弃维护关联关系的权利
*/
@Test
@Transactional //开启事务
@Rollback(false)//设置为不回滚
public void test1(){
//创建对象
SysUser u1 = new SysUser();
u1.setUserName("用户1");
SysRole r1 = new SysRole();
r1.setRoleName("角色1");
//建立关联关系
u1.getRoles().add(r1);
r1.getUsers().add(u1);
//保存
roleDao.save(r1);
userDao.save(u1);
}
删除
@Autowired
private UserDao userDao;
/**
* 删除操作
* 在多对多的删除时,双向级联删除根本不能配置
* 禁用
* 如果配了的话,如果数据之间有相互引用关系,可能会清空所有数据
*/
@Test
@Transactional
@Rollback(false)//设置为不回滚
public void testDelete() {
userDao.delete(1l);
}
对象导航查询
对象图导航检索方式是根据已经加载的对象,导航到他的关联对象。它利用类与类之间的关系来检索对象。例如:我们通过ID查询方式查出一个老师,可以调用Teacher类中的getLinkMans()方法来获取该客户的所有联系人。对象导航查询的使用要求是:两个对象之间必须存在关联关系。
查询一个老师,获取该老师的所有学生
@Autowired
private CustomerDao customerDao;
@Test
//由于是在java代码中测试,为了解决no session问题,将操作配置到同一个事务中
@Transactional
public void testFind() {
Teacher teacher = teacherDao.findOne(5l);
Set<Student> Students = teacher.getStudents();//对象导航查询
for(Student student : Students) {
System.out.println(student);
}
}
查询一个学生,获取该学生的所有老师
@Autowired
private StudentDao studentDao;
@Test
public void testFind() {
Student Student = studentDao.findOne(4l);
Teacher teacher = Student.getTeacher(); //对象导航查询
System.out.println(teacher);
}
查询学生时,肯定会看看该学生的专业老师。如果我们不查的话,在用的时候还要自己写代码,调用方法去查询。如果我们查出来的话,一个对象不会消耗太多的内存。而且多数情况下我们都是要使用的
** 解决: 采用立即加载的思想。通过配置的方式来设定,只要查询从表实体,就把主表实体对象同时查出来 **
/**
* 在联系人对象的@ManyToOne注解中添加fetch属性
* FetchType.EAGER :立即加载
* FetchType.LAZY :延迟加载
*/
@ManyToOne(targetEntity=Teacher.class,fetch=FetchType.EAGER)
@JoinColumn(name="per_tea_id",referencedColumnName="tea_id")
private Teacher teacher;