diff --git a/.gitignore b/.gitignore index 0e13eeb..1d86e31 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ + target/ pom.xml.tag pom.xml.releaseBackup @@ -9,3 +10,14 @@ buildNumber.properties .mvn/timing.properties # https://github.com/takari/maven-wrapper#usage-without-binary-jar .mvn/wrapper/maven-wrapper.jar + +.idea/ + +# Package Files # +*.jar +*.war +*.ear + +*.iml + +jpa-day01/ \ No newline at end of file diff --git a/README.md b/README.md index ec3f93c..c1a62df 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,21 @@ -# Java-Spring -A repository for storing and learning Spring code +# Spring/DataJPA of Java-Spring +JPA learning + + ++ jpa-day3-spec 自定义查询 + + + +## 目录结构 + +```powershell +. +|-- README.md +|-- document +|-- jpa-day1 +|-- jpa-day2 +|-- jpa-day3-manytomany +|-- jpa-day3-onetomany +|-- jpa-day3-spec +``` + diff --git "a/document/day01/01-\345\233\236\351\241\276jdbc\346\223\215\344\275\234\344\273\245\345\217\212\345\274\225\345\205\245orm.png" "b/document/day01/01-\345\233\236\351\241\276jdbc\346\223\215\344\275\234\344\273\245\345\217\212\345\274\225\345\205\245orm.png" new file mode 100644 index 0000000..742ef97 Binary files /dev/null and "b/document/day01/01-\345\233\236\351\241\276jdbc\346\223\215\344\275\234\344\273\245\345\217\212\345\274\225\345\205\245orm.png" differ diff --git a/document/day01/02-jpa.png b/document/day01/02-jpa.png new file mode 100644 index 0000000..2d66145 Binary files /dev/null and b/document/day01/02-jpa.png differ diff --git "a/document/day01/SpringDataJPA\347\254\254\344\270\200\345\244\251\350\256\262\344\271\211.doc" "b/document/day01/SpringDataJPA\347\254\254\344\270\200\345\244\251\350\256\262\344\271\211.doc" new file mode 100644 index 0000000..4302567 Binary files /dev/null and "b/document/day01/SpringDataJPA\347\254\254\344\270\200\345\244\251\350\256\262\344\271\211.doc" differ diff --git a/document/day01/jpa01.txt b/document/day01/jpa01.txt new file mode 100644 index 0000000..d32c902 --- /dev/null +++ b/document/day01/jpa01.txt @@ -0,0 +1,90 @@ +springdatajpa + day1:orm思想和hibernate以及jpa的概述和jpa的基本操作 + day2:springdatajpa的运行原理以及基本操作 + day3:多表操作,复杂查询 + +第一 orm思想 + 主要目的:操作实体类就相当于操作数据库表 + 建立两个映射关系: + 实体类和表的映射关系 + 实体类中属性和表中字段的映射关系 + 不再重点关注:sql语句 + + 实现了ORM思想的框架:mybatis,hibernate + +第二 hibernate框架介绍 + Hibernate是一个开放源代码的对象关系映射框架, + 它对JDBC进行了非常轻量级的对象封装, + 它将POJO与数据库表建立映射关系,是一个全自动的orm框架 + +第三 JPA规范 + jpa规范,实现jpa规范,内部是由接口和抽象类组成 + +第四 jpa的基本操作 + 案例:是客户的相关操作(增删改查) + 客户:就是一家公司 + 客户表: + + jpa操作的操作步骤 + 1.加载配置文件创建实体管理器工厂 + Persisitence:静态方法(根据持久化单元名称创建实体管理器工厂) + createEntityMnagerFactory(持久化单元名称) + 作用:创建实体管理器工厂 + + 2.根据实体管理器工厂,创建实体管理器 + EntityManagerFactory :获取EntityManager对象 + 方法:createEntityManager + * 内部维护的很多的内容 + 内部维护了数据库信息, + 维护了缓存信息 + 维护了所有的实体管理器对象 + 再创建EntityManagerFactory的过程中会根据配置创建数据库表 + * EntityManagerFactory的创建过程比较浪费资源 + 特点:线程安全的对象 + 多个线程访问同一个EntityManagerFactory不会有线程安全问题 + * 如何解决EntityManagerFactory的创建过程浪费资源(耗时)的问题? + 思路:创建一个公共的EntityManagerFactory的对象 + * 静态代码块的形式创建EntityManagerFactory + + 3.创建事务对象,开启事务 + EntityManager对象:实体类管理器 + beginTransaction : 创建事务对象 + presist : 保存 + merge : 更新 + remove : 删除 + find/getRefrence : 根据id查询 + + Transaction 对象 : 事务 + begin:开启事务 + commit:提交事务 + rollback:回滚 + 4.增删改查操作 + 5.提交事务 + 6.释放资源 + + i.搭建环境的过程 + 1.创建maven工程导入坐标 + 2.需要配置jpa的核心配置文件 + *位置:配置到类路径下的一个叫做 META-INF 的文件夹下 + *命名:persistence.xml + 3.编写客户的实体类 + 4.配置实体类和表,类中属性和表中字段的映射关系 + 5.保存客户到数据库中 + ii.完成基本CRUD案例 + persist : 保存 + merge : 更新 + remove : 删除 + find/getRefrence : 根据id查询 + + iii.jpql查询 + sql:查询的是表和表中的字段 + jpql:查询的是实体类和类中的属性 + * jpql和sql语句的语法相似 + + 1.查询全部 + 2.分页查询 + 3.统计查询 + 4.条件查询 + 5.排序 + + \ No newline at end of file diff --git "a/document/day02/01-springDataJpa\357\274\214jpa\357\274\214hibernate\345\205\263\347\263\273.png" "b/document/day02/01-springDataJpa\357\274\214jpa\357\274\214hibernate\345\205\263\347\263\273.png" new file mode 100644 index 0000000..b7ed193 Binary files /dev/null and "b/document/day02/01-springDataJpa\357\274\214jpa\357\274\214hibernate\345\205\263\347\263\273.png" differ diff --git "a/document/day02/02-\345\212\250\346\200\201\345\210\206\346\236\220.png" "b/document/day02/02-\345\212\250\346\200\201\345\210\206\346\236\220.png" new file mode 100644 index 0000000..620ef9b Binary files /dev/null and "b/document/day02/02-\345\212\250\346\200\201\345\210\206\346\236\220.png" differ diff --git "a/document/day02/03-springdatajpa\347\232\204\350\277\220\350\241\214\350\277\207\347\250\213.png" "b/document/day02/03-springdatajpa\347\232\204\350\277\220\350\241\214\350\277\207\347\250\213.png" new file mode 100644 index 0000000..a4cad27 Binary files /dev/null and "b/document/day02/03-springdatajpa\347\232\204\350\277\220\350\241\214\350\277\207\347\250\213.png" differ diff --git "a/document/day02/SpringDataJPA\347\254\254\344\272\214\345\244\251\350\256\262\344\271\211.doc" "b/document/day02/SpringDataJPA\347\254\254\344\272\214\345\244\251\350\256\262\344\271\211.doc" new file mode 100644 index 0000000..cb121e7 Binary files /dev/null and "b/document/day02/SpringDataJPA\347\254\254\344\272\214\345\244\251\350\256\262\344\271\211.doc" differ diff --git a/document/day02/jpa02.txt b/document/day02/jpa02.txt new file mode 100644 index 0000000..146ff87 --- /dev/null +++ b/document/day02/jpa02.txt @@ -0,0 +1,68 @@ +SpringDataJpa第二天 + orm思想,hibernate,JPA的相关操作 + +* SpringDataJpa + +第一 springDataJpa的概述 + +第二 springDataJpa的入门操作 + 案例:客户的基本CRUD + i.搭建环境 + 创建工程导入坐标 + 配置spring的配置文件(配置spring Data jpa的整合) + 编写实体类(Customer),使用jpa注解配置映射关系 + ii.编写一个符合springDataJpa的dao层接口 + * 只需要编写dao层接口,不需要编写dao层接口的实现类 + * dao层接口规范 + 1.需要继承两个接口(JpaRepository,JpaSpecificationExecutor) + 2.需要提供响应的泛型 + + * + findOne(id) :根据id查询 + save(customer):保存或者更新(依据:传递的实体类对象中,是否包含id属性) + delete(id) :根据id删除 + findAll() : 查询全部 + +第三 springDataJpa的运行过程和原理剖析 + 1.通过JdkDynamicAopProxy的invoke方法创建了一个动态代理对象 + 2.SimpleJpaRepository当中封装了JPA的操作(借助JPA的api完成数据库的CRUD) + 3.通过hibernate完成数据库操作(封装了jdbc) + + +第四 复杂查询 + i.借助接口中的定义好的方法完成查询 + findOne(id):根据id查询 + ii.jpql的查询方式 + jpql : jpa query language (jpq查询语言) + 特点:语法或关键字和sql语句类似 + 查询的是类和类中的属性 + + * 需要将JPQL语句配置到接口方法上 + 1.特有的查询:需要在dao接口上配置方法 + 2.在新添加的方法上,使用注解的形式配置jpql查询语句 + 3.注解 : @Query + + iii.sql语句的查询 + 1.特有的查询:需要在dao接口上配置方法 + 2.在新添加的方法上,使用注解的形式配置sql查询语句 + 3.注解 : @Query + value :jpql语句 | sql语句 + nativeQuery :false(使用jpql查询) | true(使用本地查询:sql查询) + 是否使用本地查询 + + iiii.方法名称规则查询 + + + + + + + + + + + + + + + diff --git "a/document/day03/SpringDataJPA\347\254\254\344\270\211\345\244\251\350\256\262\344\271\211.doc" "b/document/day03/SpringDataJPA\347\254\254\344\270\211\345\244\251\350\256\262\344\271\211.doc" new file mode 100644 index 0000000..7876c79 Binary files /dev/null and "b/document/day03/SpringDataJPA\347\254\254\344\270\211\345\244\251\350\256\262\344\271\211.doc" differ diff --git a/document/day03/customer.sql b/document/day03/customer.sql new file mode 100644 index 0000000..7da4f0f --- /dev/null +++ b/document/day03/customer.sql @@ -0,0 +1,27 @@ +/*创建客户表*/ +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=94 DEFAULT CHARSET=utf8; + +/*创建联系人表*/ +CREATE TABLE cst_linkman ( + lkm_id bigint(32) NOT NULL AUTO_INCREMENT COMMENT '联系人编号(主键)', + lkm_name varchar(16) DEFAULT NULL COMMENT '联系人姓名', + lkm_gender char(1) DEFAULT NULL COMMENT '联系人性别', + lkm_phone varchar(16) DEFAULT NULL COMMENT '联系人办公电话', + lkm_mobile varchar(16) DEFAULT NULL COMMENT '联系人手机', + lkm_email varchar(64) DEFAULT NULL COMMENT '联系人邮箱', + lkm_position varchar(16) DEFAULT NULL COMMENT '联系人职位', + lkm_memo varchar(512) DEFAULT NULL COMMENT '联系人备注', + lkm_cust_id bigint(32) NOT NULL COMMENT '客户id(外键)', + PRIMARY KEY (`lkm_id`), + KEY `FK_cst_linkman_lkm_cust_id` (`lkm_cust_id`), + CONSTRAINT `FK_cst_linkman_lkm_cust_id` FOREIGN KEY (`lkm_cust_id`) REFERENCES `cst_customer` (`cust_id`) ON DELETE NO ACTION ON UPDATE NO ACTION +) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8; diff --git a/document/day03/jpa03.txt b/document/day03/jpa03.txt new file mode 100644 index 0000000..097fe25 --- /dev/null +++ b/document/day03/jpa03.txt @@ -0,0 +1,129 @@ +回顾 + i.springDatajpa,jpa规范,hibernate三者之间的关系 + code -- > springDatajpa --> jpa规范的API --> hibernate + ii.符合springDataJpa规范的dao层接口的编写规则 + 1.需要实现两个接口(JpaRepository,JapSpecificationExecutor) + 2.提供响应的泛型 + iii.运行过程 + * 动态代理的方式:动态代理对象 + iiii.查询 + +第一 Specifications动态查询 + + JpaSpecificationExecutor 方法列表 + + T findOne(Specification spec); //查询单个对象 + + List findAll(Specification spec); //查询列表 + + //查询全部,分页 + //pageable:分页参数 + //返回值:分页pageBean(page:是springdatajpa提供的) + Page findAll(Specification spec, Pageable pageable); + + //查询列表 + //Sort:排序参数 + List findAll(Specification spec, Sort sort); + + long count(Specification spec);//统计查询 + + * Specification :查询条件 + 自定义我们自己的Specification实现类 + 实现 + //root:查询的根对象(查询的任何属性都可以从根对象中获取) + //CriteriaQuery:顶层查询对象,自定义查询方式(了解:一般不用) + //CriteriaBuilder:查询的构造器,封装了很多的查询条件 + Predicate toPredicate(Root root, CriteriaQuery query, CriteriaBuilder cb); //封装查询条件 + +第二 多表之间的关系和操作多表的操作步骤 + + 表关系 + 一对一 + 一对多: + 一的一方:主表 + 多的一方:从表 + 外键:需要再从表上新建一列作为外键,他的取值来源于主表的主键 + 多对多: + 中间表:中间表中最少应该由两个字段组成,这两个字段做为外键指向两张表的主键,又组成了联合主键 + + 讲师对学员:一对多关系 + + 实体类中的关系 + 包含关系:可以通过实体类中的包含关系描述表关系 + 继承关系 + + 分析步骤 + 1.明确表关系 + 2.确定表关系(描述 外键|中间表) + 3.编写实体类,再实体类中描述表关系(包含关系) + 4.配置映射关系 + +第三 完成多表操作 + + i.一对多操作 + 案例:客户和联系人的案例(一对多关系) + 客户:一家公司 + 联系人:这家公司的员工 + + 一个客户可以具有多个联系人 + 一个联系人从属于一家公司 + + 分析步骤 + 1.明确表关系 + 一对多关系 + 2.确定表关系(描述 外键|中间表) + 主表:客户表 + 从表:联系人表 + * 再从表上添加外键 + 3.编写实体类,再实体类中描述表关系(包含关系) + 客户:再客户的实体类中包含一个联系人的集合 + 联系人:在联系人的实体类中包含一个客户的对象 + 4.配置映射关系 + * 使用jpa注解配置一对多映射关系 + + 级联: + 操作一个对象的同时操作他的关联对象 + + 级联操作: + 1.需要区分操作主体 + 2.需要在操作主体的实体类上,添加级联属性(需要添加到多表映射关系的注解上) + 3.cascade(配置级联) + + 级联添加, + 案例:当我保存一个客户的同时保存联系人 + 级联删除 + 案例:当我删除一个客户的同时删除此客户的所有联系人 + + ii.多对多操作 + 案例:用户和角色(多对多关系) + 用户: + 角色: + + 分析步骤 + 1.明确表关系 + 多对多关系 + 2.确定表关系(描述 外键|中间表) + 中间间表 + 3.编写实体类,再实体类中描述表关系(包含关系) + 用户:包含角色的集合 + 角色:包含用户的集合 + 4.配置映射关系 + + iii.多表的查询 + 1.对象导航查询 + 查询一个对象的同时,通过此对象查询他的关联对象 + + 案例:客户和联系人 + + 从一方查询多方 + * 默认:使用延迟加载(****) + + 从多方查询一方 + * 默认:使用立即加载 + + + + + + + \ No newline at end of file diff --git a/jpa-day1/pom.xml b/jpa-day1/pom.xml new file mode 100644 index 0000000..2d46030 --- /dev/null +++ b/jpa-day1/pom.xml @@ -0,0 +1,54 @@ + + + 4.0.0 + + cn.itcast + jpa-day1 + 1.0-SNAPSHOT + + + UTF-8 + 5.0.7.Final + + + + + + junit + junit + 4.12 + test + + + + + org.hibernate + hibernate-entitymanager + ${project.hibernate.version} + + + + + org.hibernate + hibernate-c3p0 + ${project.hibernate.version} + + + + + log4j + log4j + 1.2.17 + + + + + mysql + mysql-connector-java + 5.1.6 + + + + \ No newline at end of file diff --git a/jpa-day1/src/main/java/cn/itcast/domain/Customer.java b/jpa-day1/src/main/java/cn/itcast/domain/Customer.java new file mode 100644 index 0000000..ba42dd4 --- /dev/null +++ b/jpa-day1/src/main/java/cn/itcast/domain/Customer.java @@ -0,0 +1,126 @@ +package cn.itcast.domain; + +import javax.persistence.*; + +/** + * 客户的实体类 + * 配置映射关系 + * + * + * 1.实体类和表的映射关系 + * @Entity:声明实体类 + * @Table : 配置实体类和表的映射关系 + * name : 配置数据库表的名称 + * 2.实体类中属性和表中字段的映射关系 + * + * + */ +@Entity +@Table(name = "cst_customer") +public class Customer { + + /** + * @Id:声明主键的配置 + * @GeneratedValue:配置主键的生成策略 + * strategy + * GenerationType.IDENTITY :自增,mysql + * * 底层数据库必须支持自动增长(底层数据库支持的自动增长方式,对id自增) + * GenerationType.SEQUENCE : 序列,oracle + * * 底层数据库必须支持序列 + * GenerationType.TABLE : jpa提供的一种机制,通过一张数据库表的形式帮助我们完成主键自增 + * GenerationType.AUTO : 由程序自动的帮助我们选择主键生成策略 + * @Column:配置属性和字段的映射关系 + * name:数据库表中字段的名称 + */ + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "cust_id") + private Long custId; //客户的主键 + + @Column(name = "cust_name") + private String custName;//客户名称 + + @Column(name="cust_source") + private String custSource;//客户来源 + + @Column(name="cust_level") + private String custLevel;//客户级别 + + @Column(name="cust_industry") + private String custIndustry;//客户所属行业 + + @Column(name="cust_phone") + private String custPhone;//客户的联系方式 + + @Column(name="cust_address") + private String custAddress;//客户地址 + + 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 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 getCustPhone() { + return custPhone; + } + + public void setCustPhone(String custPhone) { + this.custPhone = custPhone; + } + + public String getCustAddress() { + return custAddress; + } + + public void setCustAddress(String custAddress) { + this.custAddress = custAddress; + } + + @Override + public String toString() { + return "Customer{" + + "custId=" + custId + + ", custName='" + custName + '\'' + + ", custSource='" + custSource + '\'' + + ", custLevel='" + custLevel + '\'' + + ", custIndustry='" + custIndustry + '\'' + + ", custPhone='" + custPhone + '\'' + + ", custAddress='" + custAddress + '\'' + + '}'; + } +} diff --git a/jpa-day1/src/main/java/cn/itcast/utils/JpaUtils.java b/jpa-day1/src/main/java/cn/itcast/utils/JpaUtils.java new file mode 100644 index 0000000..a06e0cd --- /dev/null +++ b/jpa-day1/src/main/java/cn/itcast/utils/JpaUtils.java @@ -0,0 +1,29 @@ +package cn.itcast.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 factory; + + static { + //1.加载配置文件,创建entityManagerFactory + factory = Persistence.createEntityManagerFactory("myJpa"); + } + + /** + * 获取EntityManager对象 + */ + public static EntityManager getEntityManager() { + return factory.createEntityManager(); + } +} diff --git a/jpa-day1/src/main/resources/META-INF/persistence.xml b/jpa-day1/src/main/resources/META-INF/persistence.xml new file mode 100644 index 0000000..f2d1331 --- /dev/null +++ b/jpa-day1/src/main/resources/META-INF/persistence.xml @@ -0,0 +1,39 @@ + + + + + + org.hibernate.jpa.HibernatePersistenceProvider + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/jpa-day1/src/test/java/cn/itcast/test/JpaTest.java b/jpa-day1/src/test/java/cn/itcast/test/JpaTest.java new file mode 100644 index 0000000..2e98290 --- /dev/null +++ b/jpa-day1/src/test/java/cn/itcast/test/JpaTest.java @@ -0,0 +1,163 @@ +package cn.itcast.test; + +import cn.itcast.domain.Customer; +import cn.itcast.utils.JpaUtils; +import org.junit.Test; + +import javax.persistence.EntityManager; +import javax.persistence.EntityManagerFactory; +import javax.persistence.EntityTransaction; +import javax.persistence.Persistence; + +public class JpaTest { + + /** + * 测试jpa的保存 + * 案例:保存一个客户到数据库中 + * Jpa的操作步骤 + * 1.加载配置文件创建工厂(实体管理器工厂)对象 + * 2.通过实体管理器工厂获取实体管理器 + * 3.获取事务对象,开启事务 + * 4.完成增删改查操作 + * 5.提交事务(回滚事务) + * 6.释放资源 + */ + @Test + public void testSave() { +// //1.加载配置文件创建工厂(实体管理器工厂)对象 +// EntityManagerFactory factory = Persistence.createEntityManagerFactory("myJpa"); +// //2.通过实体管理器工厂获取实体管理器 +// EntityManager em = factory.createEntityManager(); + EntityManager em = JpaUtils.getEntityManager(); + //3.获取事务对象,开启事务 + EntityTransaction tx = em.getTransaction(); //获取事务对象 + tx.begin();//开启事务 + //4.完成增删改查操作:保存一个客户到数据库中 + Customer customer = new Customer(); + customer.setCustName("传智播客"); + customer.setCustIndustry("教育"); + //保存, + em.persist(customer); //保存操作 + //5.提交事务 + tx.commit(); + //6.释放资源 + em.close(); + // factory.close(); + + } + + /** + * 根据id查询客户 + * 使用find方法查询: + * 1.查询的对象就是当前客户对象本身 + * 2.在调用find方法的时候,就会发送sql语句查询数据库 + * + * 立即加载 + * + * + */ + @Test + public void testFind() { + //1.通过工具类获取entityManager + EntityManager entityManager = JpaUtils.getEntityManager(); + //2.开启事务 + EntityTransaction tx = entityManager.getTransaction(); + tx.begin(); + //3.增删改查 -- 根据id查询客户 + /** + * find : 根据id查询数据 + * class:查询数据的结果需要包装的实体类类型的字节码 + * id:查询的主键的取值 + */ + Customer customer = entityManager.find(Customer.class, 1l); + // System.out.print(customer); + //4.提交事务 + tx.commit(); + //5.释放资源 + entityManager.close(); + } + + /** + * 根据id查询客户 + * getReference方法 + * 1.获取的对象是一个动态代理对象 + * 2.调用getReference方法不会立即发送sql语句查询数据库 + * * 当调用查询结果对象的时候,才会发送查询的sql语句:什么时候用,什么时候发送sql语句查询数据库 + * + * 延迟加载(懒加载) + * * 得到的是一个动态代理对象 + * * 什么时候用,什么使用才会查询 + */ + @Test + public void testReference() { + //1.通过工具类获取entityManager + EntityManager entityManager = JpaUtils.getEntityManager(); + //2.开启事务 + EntityTransaction tx = entityManager.getTransaction(); + tx.begin(); + //3.增删改查 -- 根据id查询客户 + /** + * getReference : 根据id查询数据 + * class:查询数据的结果需要包装的实体类类型的字节码 + * id:查询的主键的取值 + */ + Customer customer = entityManager.getReference(Customer.class, 1l); + System.out.print(customer); + //4.提交事务 + tx.commit(); + //5.释放资源 + entityManager.close(); + } + + + /** + * 删除客户的案例 + * + */ + @Test + public void testRemove() { + //1.通过工具类获取entityManager + EntityManager entityManager = JpaUtils.getEntityManager(); + //2.开启事务 + EntityTransaction tx = entityManager.getTransaction(); + tx.begin(); + //3.增删改查 -- 删除客户 + + //i 根据id查询客户 + Customer customer = entityManager.find(Customer.class,1l); + //ii 调用remove方法完成删除操作 + entityManager.remove(customer); + + //4.提交事务 + tx.commit(); + //5.释放资源 + entityManager.close(); + } + + + /** + * 更新客户的操作 + * merge(Object) + */ + @Test + public void testUpdate() { + //1.通过工具类获取entityManager + EntityManager entityManager = JpaUtils.getEntityManager(); + //2.开启事务 + EntityTransaction tx = entityManager.getTransaction(); + tx.begin(); + //3.增删改查 -- 更新操作 + + //i 查询客户 + Customer customer = entityManager.find(Customer.class,1l); + //ii 更新客户 + customer.setCustIndustry("it教育"); + entityManager.merge(customer); + + //4.提交事务 + tx.commit(); + //5.释放资源 + entityManager.close(); + } + +} diff --git a/jpa-day1/src/test/java/cn/itcast/test/JpqlTest.java b/jpa-day1/src/test/java/cn/itcast/test/JpqlTest.java new file mode 100644 index 0000000..951688e --- /dev/null +++ b/jpa-day1/src/test/java/cn/itcast/test/JpqlTest.java @@ -0,0 +1,196 @@ +package cn.itcast.test; + +import cn.itcast.domain.Customer; +import cn.itcast.utils.JpaUtils; +import org.junit.Test; + +import javax.persistence.EntityManager; +import javax.persistence.EntityTransaction; +import javax.persistence.Query; +import java.util.List; + +/** + * 测试jqpl查询 + */ +public class JpqlTest { + + /** + * 查询全部 + * jqpl:from cn.itcast.domain.Customer + * sql:SELECT * FROM cst_customer + */ + @Test + public void testFindAll() { + //1.获取entityManager对象 + EntityManager em = JpaUtils.getEntityManager(); + //2.开启事务 + EntityTransaction tx = em.getTransaction(); + tx.begin(); + //3.查询全部 + String jpql = "from Customer "; + Query query = em.createQuery(jpql);//创建Query查询对象,query对象才是执行jqpl的对象 + + //发送查询,并封装结果集 + List list = query.getResultList(); + + for (Object obj : list) { + System.out.print(obj); + } + + //4.提交事务 + tx.commit(); + //5.释放资源 + em.close(); + } + + + /** + * 排序查询: 倒序查询全部客户(根据id倒序) + * sql:SELECT * FROM cst_customer ORDER BY cust_id DESC + * jpql:from Customer order by custId desc + * + * 进行jpql查询 + * 1.创建query查询对象 + * 2.对参数进行赋值 + * 3.查询,并得到返回结果 + */ + @Test + public void testOrders() { + //1.获取entityManager对象 + EntityManager em = JpaUtils.getEntityManager(); + //2.开启事务 + EntityTransaction tx = em.getTransaction(); + tx.begin(); + //3.查询全部 + String jpql = "from Customer order by custId desc"; + Query query = em.createQuery(jpql);//创建Query查询对象,query对象才是执行jqpl的对象 + + //发送查询,并封装结果集 + List list = query.getResultList(); + + for (Object obj : list) { + System.out.println(obj); + } + + //4.提交事务 + tx.commit(); + //5.释放资源 + em.close(); + } + + + /** + * 使用jpql查询,统计客户的总数 + * sql:SELECT COUNT(cust_id) FROM cst_customer + * jpql:select count(custId) from Customer + */ + @Test + public void testCount() { + //1.获取entityManager对象 + EntityManager em = JpaUtils.getEntityManager(); + //2.开启事务 + EntityTransaction tx = em.getTransaction(); + tx.begin(); + //3.查询全部 + //i.根据jpql语句创建Query查询对象 + String jpql = "select count(custId) from Customer"; + Query query = em.createQuery(jpql); + //ii.对参数赋值 + //iii.发送查询,并封装结果 + + /** + * getResultList : 直接将查询结果封装为list集合 + * getSingleResult : 得到唯一的结果集 + */ + Object result = query.getSingleResult(); + + System.out.println(result); + + //4.提交事务 + tx.commit(); + //5.释放资源 + em.close(); + } + + + /** + * 分页查询 + * sql:select * from cst_customer limit 0,2 + * jqpl : from Customer + */ + @Test + public void testPaged() { + //1.获取entityManager对象 + EntityManager em = JpaUtils.getEntityManager(); + //2.开启事务 + EntityTransaction tx = em.getTransaction(); + tx.begin(); + //3.查询全部 + //i.根据jpql语句创建Query查询对象 + String jpql = "from Customer"; + Query query = em.createQuery(jpql); + //ii.对参数赋值 -- 分页参数 + //起始索引 + query.setFirstResult(0); + //每页查询的条数 + query.setMaxResults(2); + + //iii.发送查询,并封装结果 + + /** + * getResultList : 直接将查询结果封装为list集合 + * getSingleResult : 得到唯一的结果集 + */ + List list = query.getResultList(); + + for(Object obj : list) { + System.out.println(obj); + } + + //4.提交事务 + tx.commit(); + //5.释放资源 + em.close(); + } + + + /** + * 条件查询 + * 案例:查询客户名称以‘传智播客’开头的客户 + * sql:SELECT * FROM cst_customer WHERE cust_name LIKE ? + * jpql : from Customer where custName like ? + */ + @Test + public void testCondition() { + //1.获取entityManager对象 + EntityManager em = JpaUtils.getEntityManager(); + //2.开启事务 + EntityTransaction tx = em.getTransaction(); + tx.begin(); + //3.查询全部 + //i.根据jpql语句创建Query查询对象 + String jpql = "from Customer where custName like ? "; + Query query = em.createQuery(jpql); + //ii.对参数赋值 -- 占位符参数 + //第一个参数:占位符的索引位置(从1开始),第二个参数:取值 + query.setParameter(1,"传智播客%"); + + //iii.发送查询,并封装结果 + + /** + * getResultList : 直接将查询结果封装为list集合 + * getSingleResult : 得到唯一的结果集 + */ + List list = query.getResultList(); + + for(Object obj : list) { + System.out.println(obj); + } + + //4.提交事务 + tx.commit(); + //5.释放资源 + em.close(); + } + +} diff --git a/jpa-day2/pom.xml b/jpa-day2/pom.xml new file mode 100644 index 0000000..b293300 --- /dev/null +++ b/jpa-day2/pom.xml @@ -0,0 +1,156 @@ + + + 4.0.0 + + cn.itcast + jpa-day2 + 1.0-SNAPSHOT + + + 5.0.2.RELEASE + 5.0.7.Final + 1.6.6 + 1.2.12 + 0.9.1.2 + 8.0.20 + + + + + + junit + junit + 4.12 + test + + + + + org.aspectj + aspectjweaver + 1.6.8 + + + + org.springframework + spring-aop + ${spring.version} + + + + org.springframework + spring-context + ${spring.version} + + + + org.springframework + spring-context-support + ${spring.version} + + + + + org.springframework + spring-orm + ${spring.version} + + + + org.springframework + spring-beans + ${spring.version} + + + + org.springframework + spring-core + ${spring.version} + + + + + + + org.hibernate + hibernate-core + ${hibernate.version} + + + org.hibernate + hibernate-entitymanager + ${hibernate.version} + + + org.hibernate + hibernate-validator + 5.2.1.Final + + + + + + c3p0 + c3p0 + ${c3p0.version} + + + + + + log4j + log4j + ${log4j.version} + + + + org.slf4j + slf4j-api + ${slf4j.version} + + + + org.slf4j + slf4j-log4j12 + ${slf4j.version} + + + + + + mysql + mysql-connector-java + ${mysql.version} + + + + + org.springframework.data + spring-data-jpa + 1.9.0.RELEASE + + + + org.springframework + spring-test + ${spring.version} + + + + + javax.el + javax.el-api + 2.2.4 + + + + org.glassfish.web + javax.el + 2.2.4 + + + + + \ No newline at end of file diff --git a/jpa-day2/src/main/java/cn/itcast/dao/CustomerDao.java b/jpa-day2/src/main/java/cn/itcast/dao/CustomerDao.java new file mode 100644 index 0000000..db93795 --- /dev/null +++ b/jpa-day2/src/main/java/cn/itcast/dao/CustomerDao.java @@ -0,0 +1,106 @@ +package cn.itcast.dao; + +import cn.itcast.domain.Customer; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; + +import java.util.List; + +/** + * 符合SpringDataJpa的dao层接口规范 + * JpaRepository<操作的实体类类型,实体类中主键属性的类型> + * * 封装了基本CRUD操作 + * JpaSpecificationExecutor<操作的实体类类型> + * * 封装了复杂查询(分页) + */ +public interface CustomerDao extends JpaRepository ,JpaSpecificationExecutor { + + /** + * 案例:根据客户名称查询客户 + * 使用jpql的形式查询 + * jpql:from Customer where custName = ? + * + * 配置jpql语句,使用的@Query注解 + */ + @Query(value="from Customer where custName = ?") + public Customer findJpql(String custName); + + + /** + * 案例:根据客户名称和客户id查询客户 + * jpql: from Customer where custName = ? and custId = ? + * + * 对于多个占位符参数 + * 赋值的时候,默认的情况下,占位符的位置需要和方法参数中的位置保持一致 + * + * 可以指定占位符参数的位置 + * ? 索引的方式,指定此占位的取值来源 + */ + @Query(value = "from Customer where custName = ?2 and custId = ?1") + public Customer findCustNameAndId(Long id,String name); + + /** + * 使用jpql完成更新操作 + * 案例 : 根据id更新,客户的名称 + * 更新4号客户的名称,将名称改为“黑马程序员” + * + * sql :update cst_customer set cust_name = ? where cust_id = ? + * jpql : update Customer set custName = ? where custId = ? + * + * @Query : 代表的是进行查询 + * * 声明此方法是用来进行更新操作 + * @Modifying + * * 当前执行的是一个更新操作 + * + */ + @Query(value = " update Customer set custName = ?2 where custId = ?1 ") + @Modifying + public void updateCustomer(long custId,String custName); + + + /** + * 使用sql的形式查询: + * 查询全部的客户 + * sql : select * from cst_customer; + * Query : 配置sql查询 + * value : sql语句 + * nativeQuery : 查询方式 + * true : sql查询 + * false:jpql查询 + * + */ + //@Query(value = " select * from cst_customer" ,nativeQuery = true) + @Query(value="select * from cst_customer where cust_name like ?1",nativeQuery = true) + public List findSql(String name); + + + /** + * 方法名的约定: + * findBy : 查询 + * 对象中的属性名(首字母大写) : 查询的条件 + * CustName + * * 默认情况 : 使用 等于的方式查询 + * 特殊的查询方式 + * + * findByCustName -- 根据客户名称查询 + * + * 再springdataJpa的运行阶段 + * 会根据方法名称进行解析 findBy from xxx(实体类) + * 属性名称 where custName = + * + * 1.findBy + 属性名称 (根据属性名称进行完成匹配的查询=) + * 2.findBy + 属性名称 + “查询方式(Like | isnull)” + * findByCustNameLike + * 3.多条件查询 + * findBy + 属性名 + “查询方式” + “多条件的连接符(and|or)” + 属性名 + “查询方式” + */ + public Customer findByCustName(String custName); + + + public List findByCustNameLike(String custName); + + //使用客户名称模糊匹配和客户所属行业精准匹配的查询 + public Customer findByCustNameLikeAndCustIndustry(String custName,String custIndustry); +} diff --git a/jpa-day2/src/main/java/cn/itcast/domain/Customer.java b/jpa-day2/src/main/java/cn/itcast/domain/Customer.java new file mode 100644 index 0000000..bc96e4b --- /dev/null +++ b/jpa-day2/src/main/java/cn/itcast/domain/Customer.java @@ -0,0 +1,103 @@ +package cn.itcast.domain; + +import javax.persistence.*; + +/** + * 1.实体类和表的映射关系 + * @Eitity + * @Table + * 2.类中属性和表中字段的映射关系 + * @Id + * @GeneratedValue + * @Column + */ +@Entity +@Table(name="cst_customer") +public class Customer { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name="cust_id") + private Long custId; + @Column(name="cust_address") + private String custAddress; + @Column(name="cust_industry") + private String custIndustry; + @Column(name="cust_level") + private String custLevel; + @Column(name="cust_name") + private String custName; + @Column(name="cust_phone") + private String custPhone; + @Column(name="cust_source") + private String custSource; + + public Long getCustId() { + return custId; + } + + public void setCustId(Long custId) { + this.custId = custId; + } + + public String getCustAddress() { + return custAddress; + } + + public void setCustAddress(String custAddress) { + this.custAddress = custAddress; + } + + 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 getCustName() { + return custName; + } + + public void setCustName(String custName) { + this.custName = custName; + } + + public String getCustPhone() { + return custPhone; + } + + public void setCustPhone(String custPhone) { + this.custPhone = custPhone; + } + + public String getCustSource() { + return custSource; + } + + public void setCustSource(String custSource) { + this.custSource = custSource; + } + + @Override + public String toString() { + return "Customer{" + + "custId=" + custId + + ", custAddress='" + custAddress + '\'' + + ", custIndustry='" + custIndustry + '\'' + + ", custLevel='" + custLevel + '\'' + + ", custName='" + custName + '\'' + + ", custPhone='" + custPhone + '\'' + + ", custSource='" + custSource + '\'' + + '}'; + } +} diff --git a/jpa-day2/src/main/resources/applicationContext.xml b/jpa-day2/src/main/resources/applicationContext.xml new file mode 100644 index 0000000..df3592c --- /dev/null +++ b/jpa-day2/src/main/resources/applicationContext.xml @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/jpa-day2/src/test/java/cn/itcast/test/CustomerDaoTest.java b/jpa-day2/src/test/java/cn/itcast/test/CustomerDaoTest.java new file mode 100644 index 0000000..02d3879 --- /dev/null +++ b/jpa-day2/src/test/java/cn/itcast/test/CustomerDaoTest.java @@ -0,0 +1,111 @@ +package cn.itcast.test; + +import cn.itcast.dao.CustomerDao; +import cn.itcast.domain.Customer; +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 org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +@RunWith(SpringJUnit4ClassRunner.class) //声明spring提供的单元测试环境 +@ContextConfiguration(locations = "classpath:applicationContext.xml")//指定spring容器的配置信息 +public class CustomerDaoTest { + @Autowired + private CustomerDao customerDao; + + /** + * 根据id查询 + */ + @Test + public void testFindOne() { + Customer customer = customerDao.findOne(2l); + System.out.println(customer); + } + + /** + * save : 保存或者更新 + * 根据传递的对象是否存在主键id, + * 如果没有id主键属性:保存 + * 存在id主键属性,根据id查询数据,更新数据 + */ + @Test + public void testSave() { + Customer customer = new Customer(); + customer.setCustName("黑马程序员"); + customer.setCustLevel("vip"); + customer.setCustIndustry("it教育"); + customerDao.save(customer); + } + + @Test + public void testUpdate() { + Customer customer = new Customer(); + customer.setCustId(4l); + customer.setCustName("黑马程序员很厉害"); + customerDao.save(customer); + } + + @Test + public void testDelete () { + customerDao.delete(3l); + } + + + /** + * 查询所有 + */ + @Test + public void testFindAll() { + List list = customerDao.findAll(); + for(Customer customer : list) { + System.out.println(customer); + } + } + + /** + * 测试统计查询:查询客户的总数量 + * count:统计总条数 + */ + @Test + public void testCount() { + long count = customerDao.count();//查询全部的客户数量 + System.out.println(count); + } + + /** + * 测试:判断id为4的客户是否存在 + * 1. 可以查询以下id为4的客户 + * 如果值为空,代表不存在,如果不为空,代表存在 + * 2. 判断数据库中id为4的客户的数量 + * 如果数量为0,代表不存在,如果大于0,代表存在 + */ + @Test + public void testExists() { + boolean exists = customerDao.exists(4l); + System.out.println("id为4的客户 是否存在:"+exists); + } + + + /** + * 根据id从数据库查询 + * @Transactional : 保证getOne正常运行 + * + * findOne: + * em.find() :立即加载 + * getOne: + * em.getReference :延迟加载 + * * 返回的是一个客户的动态代理对象 + * * 什么时候用,什么时候查询 + */ + @Test + @Transactional + public void testGetOne() { + Customer customer = customerDao.getOne(4l); + System.out.println(customer); + } + +} diff --git a/jpa-day2/src/test/java/cn/itcast/test/JpqlTest.java b/jpa-day2/src/test/java/cn/itcast/test/JpqlTest.java new file mode 100644 index 0000000..1a4ab47 --- /dev/null +++ b/jpa-day2/src/test/java/cn/itcast/test/JpqlTest.java @@ -0,0 +1,86 @@ +package cn.itcast.test; + +import cn.itcast.dao.CustomerDao; +import cn.itcast.domain.Customer; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.jpa.repository.Query; +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 java.util.Arrays; +import java.util.List; + +@RunWith(SpringJUnit4ClassRunner.class) //声明spring提供的单元测试环境 +@ContextConfiguration(locations = "classpath:applicationContext.xml")//指定spring容器的配置信息 +public class JpqlTest { + @Autowired + private CustomerDao customerDao; + + @Test + public void testFindJPQL() { + Customer customer = customerDao.findJpql("传智播客"); + System.out.println(customer); + } + + + @Test + public void testFindCustNameAndId() { + // Customer customer = customerDao.findCustNameAndId("传智播客",1l); + Customer customer = customerDao.findCustNameAndId(1l,"传智播客"); + System.out.println(customer); + } + + /** + * 测试jpql的更新操作 + * * springDataJpa中使用jpql完成 更新/删除操作 + * * 需要手动添加事务的支持 + * * 默认会执行结束之后,回滚事务 + * @Rollback : 设置是否自动回滚 + * false | true + */ + @Test + @Transactional //添加事务的支持 + @Rollback(value = false) + public void testUpdateCustomer() { + customerDao.updateCustomer(4l,"黑马程序员"); + } + + //测试sql查询 + @Test + public void testFindSql() { + List list = customerDao.findSql("传智播客%"); + for(Object [] obj : list) { + System.out.println(Arrays.toString(obj)); + } + } + + + //测试方法命名规则的查询 + @Test + public void testNaming() { + Customer customer = customerDao.findByCustName("传智播客"); + System.out.println(customer); + } + + + //测试方法命名规则的查询 + @Test + public void testFindByCustNameLike() { + List list = customerDao.findByCustNameLike("传智播客%"); + for (Customer customer : list) { + System.out.println(customer); + } + } + + + //测试方法命名规则的查询 + @Test + public void testFindByCustNameLikeAndCustIndustry() { + Customer customer = customerDao.findByCustNameLikeAndCustIndustry("传智播客1%", "it教育"); + System.out.println(customer); + } +} diff --git a/jpa-day3-manytomany/pom.xml b/jpa-day3-manytomany/pom.xml new file mode 100644 index 0000000..d4b92ab --- /dev/null +++ b/jpa-day3-manytomany/pom.xml @@ -0,0 +1,155 @@ + + + 4.0.0 + + cn.itcast + jpa-day3-manytomany + 1.0-SNAPSHOT + + + 5.0.2.RELEASE + 5.0.7.Final + 1.6.6 + 1.2.12 + 0.9.1.2 + 5.1.6 + + + + + + junit + junit + 4.12 + test + + + + + org.aspectj + aspectjweaver + 1.6.8 + + + + org.springframework + spring-aop + ${spring.version} + + + + org.springframework + spring-context + ${spring.version} + + + + org.springframework + spring-context-support + ${spring.version} + + + + + org.springframework + spring-orm + ${spring.version} + + + + org.springframework + spring-beans + ${spring.version} + + + + org.springframework + spring-core + ${spring.version} + + + + + + + org.hibernate + hibernate-core + ${hibernate.version} + + + org.hibernate + hibernate-entitymanager + ${hibernate.version} + + + org.hibernate + hibernate-validator + 5.2.1.Final + + + + + + c3p0 + c3p0 + ${c3p0.version} + + + + + + log4j + log4j + ${log4j.version} + + + + org.slf4j + slf4j-api + ${slf4j.version} + + + + org.slf4j + slf4j-log4j12 + ${slf4j.version} + + + + + + mysql + mysql-connector-java + ${mysql.version} + + + + + org.springframework.data + spring-data-jpa + 1.9.0.RELEASE + + + + org.springframework + spring-test + ${spring.version} + + + + + javax.el + javax.el-api + 2.2.4 + + + + org.glassfish.web + javax.el + 2.2.4 + + + + \ No newline at end of file diff --git a/jpa-day3-manytomany/src/main/java/cn/itcast/dao/RoleDao.java b/jpa-day3-manytomany/src/main/java/cn/itcast/dao/RoleDao.java new file mode 100644 index 0000000..1901a25 --- /dev/null +++ b/jpa-day3-manytomany/src/main/java/cn/itcast/dao/RoleDao.java @@ -0,0 +1,9 @@ +package cn.itcast.dao; + +import cn.itcast.domain.Role; +import cn.itcast.domain.User; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +public interface RoleDao extends JpaRepository ,JpaSpecificationExecutor { +} diff --git a/jpa-day3-manytomany/src/main/java/cn/itcast/dao/UserDao.java b/jpa-day3-manytomany/src/main/java/cn/itcast/dao/UserDao.java new file mode 100644 index 0000000..93a55b9 --- /dev/null +++ b/jpa-day3-manytomany/src/main/java/cn/itcast/dao/UserDao.java @@ -0,0 +1,8 @@ +package cn.itcast.dao; + +import cn.itcast.domain.User; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +public interface UserDao extends JpaRepository ,JpaSpecificationExecutor { +} diff --git a/jpa-day3-manytomany/src/main/java/cn/itcast/domain/Role.java b/jpa-day3-manytomany/src/main/java/cn/itcast/domain/Role.java new file mode 100644 index 0000000..4efe92d --- /dev/null +++ b/jpa-day3-manytomany/src/main/java/cn/itcast/domain/Role.java @@ -0,0 +1,45 @@ +package cn.itcast.domain; + +import javax.persistence.*; +import java.util.HashSet; +import java.util.Set; + +@Entity +@Table(name = "sys_role") +public class Role { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "role_id") + private Long roleId; + @Column(name = "role_name") + private String roleName; + + //配置多对多 + @ManyToMany(mappedBy = "roles") //配置多表关系 + private Set users = new HashSet<>(); + + 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 Set getUsers() { + return users; + } + + public void setUsers(Set users) { + this.users = users; + } +} diff --git a/jpa-day3-manytomany/src/main/java/cn/itcast/domain/User.java b/jpa-day3-manytomany/src/main/java/cn/itcast/domain/User.java new file mode 100644 index 0000000..7ad0d90 --- /dev/null +++ b/jpa-day3-manytomany/src/main/java/cn/itcast/domain/User.java @@ -0,0 +1,75 @@ +package cn.itcast.domain; + +import javax.persistence.*; +import java.util.HashSet; +import java.util.Set; + +@Entity +@Table(name = "sys_user") +public class User { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name="user_id") + private Long userId; + @Column(name="user_name") + private String userName; + @Column(name="age") + private Integer age; + + /** + * 配置用户到角色的多对多关系 + * 配置多对多的映射关系 + * 1.声明表关系的配置 + * @ManyToMany(targetEntity = Role.class) //多对多 + * targetEntity:代表对方的实体类字节码 + * 2.配置中间表(包含两个外键) + * @JoinTable + * name : 中间表的名称 + * joinColumns:配置当前对象在中间表的外键 + * @JoinColumn的数组 + * name:外键名 + * referencedColumnName:参照的主表的主键名 + * inverseJoinColumns:配置对方对象在中间表的外键 + */ + @ManyToMany(targetEntity = Role.class,cascade = CascadeType.ALL) + @JoinTable(name = "sys_user_role", + //joinColumns,当前对象在中间表中的外键 + joinColumns = {@JoinColumn(name = "sys_user_id",referencedColumnName = "user_id")}, + //inverseJoinColumns,对方对象在中间表的外键 + inverseJoinColumns = {@JoinColumn(name = "sys_role_id",referencedColumnName = "role_id")} + ) + private Set roles = new HashSet<>(); + + public Long getUserId() { + return userId; + } + + public void setUserId(Long userId) { + this.userId = userId; + } + + public String getUserName() { + return userName; + } + + public void setUserName(String userName) { + this.userName = userName; + } + + public Integer getAge() { + return age; + } + + public void setAge(Integer age) { + this.age = age; + } + + public Set getRoles() { + return roles; + } + + public void setRoles(Set roles) { + this.roles = roles; + } +} diff --git a/jpa-day3-manytomany/src/main/resources/applicationContext.xml b/jpa-day3-manytomany/src/main/resources/applicationContext.xml new file mode 100644 index 0000000..127a6f3 --- /dev/null +++ b/jpa-day3-manytomany/src/main/resources/applicationContext.xml @@ -0,0 +1,102 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/jpa-day3-manytomany/src/test/java/cn/itcast/test/ManyToManyTest.java b/jpa-day3-manytomany/src/test/java/cn/itcast/test/ManyToManyTest.java new file mode 100644 index 0000000..3f64b1e --- /dev/null +++ b/jpa-day3-manytomany/src/test/java/cn/itcast/test/ManyToManyTest.java @@ -0,0 +1,83 @@ +package cn.itcast.test; + +import cn.itcast.dao.RoleDao; +import cn.itcast.dao.UserDao; +import cn.itcast.domain.Role; +import cn.itcast.domain.User; +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; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = "classpath:applicationContext.xml") +public class ManyToManyTest { + + @Autowired + private UserDao userDao; + @Autowired + private RoleDao roleDao; + + /** + * 保存一个用户,保存一个角色 + * + * 多对多放弃维护权:被动的一方放弃 + */ + @Test + @Transactional + @Rollback(false) + public void testAdd() { + User user = new User(); + user.setUserName("小李"); + + Role role = new Role(); + role.setRoleName("java程序员"); + + //配置用户到角色关系,可以对中间表中的数据进行维护 1-1 + user.getRoles().add(role); + + //配置角色到用户的关系,可以对中间表的数据进行维护 1-1 + role.getUsers().add(user); + + userDao.save(user); + roleDao.save(role); + } + + + //测试级联添加(保存一个用户的同时保存用户的关联角色) + @Test + @Transactional + @Rollback(false) + public void testCasCadeAdd() { + User user = new User(); + user.setUserName("小李"); + + Role role = new Role(); + role.setRoleName("java程序员"); + + //配置用户到角色关系,可以对中间表中的数据进行维护 1-1 + user.getRoles().add(role); + + //配置角色到用户的关系,可以对中间表的数据进行维护 1-1 + role.getUsers().add(user); + + userDao.save(user); + } + + /** + * 案例:删除id为1的用户,同时删除他的关联对象 + */ + @Test + @Transactional + @Rollback(false) + public void testCasCadeRemove() { + //查询1号用户 + User user = userDao.findOne(1l); + //删除1号用户 + userDao.delete(user); + + } +} diff --git a/jpa-day3-onetomany/pom.xml b/jpa-day3-onetomany/pom.xml new file mode 100644 index 0000000..01ab5c7 --- /dev/null +++ b/jpa-day3-onetomany/pom.xml @@ -0,0 +1,156 @@ + + + 4.0.0 + + cn.itcast + jpa-day3-onetomany + 1.0-SNAPSHOT + + + 5.0.2.RELEASE + 5.0.7.Final + 1.6.6 + 1.2.12 + 0.9.1.2 + 5.1.6 + + + + + + junit + junit + 4.12 + test + + + + + org.aspectj + aspectjweaver + 1.6.8 + + + + org.springframework + spring-aop + ${spring.version} + + + + org.springframework + spring-context + ${spring.version} + + + + org.springframework + spring-context-support + ${spring.version} + + + + + org.springframework + spring-orm + ${spring.version} + + + + org.springframework + spring-beans + ${spring.version} + + + + org.springframework + spring-core + ${spring.version} + + + + + + + org.hibernate + hibernate-core + ${hibernate.version} + + + org.hibernate + hibernate-entitymanager + ${hibernate.version} + + + org.hibernate + hibernate-validator + 5.2.1.Final + + + + + + c3p0 + c3p0 + ${c3p0.version} + + + + + + log4j + log4j + ${log4j.version} + + + + org.slf4j + slf4j-api + ${slf4j.version} + + + + org.slf4j + slf4j-log4j12 + ${slf4j.version} + + + + + + mysql + mysql-connector-java + ${mysql.version} + + + + + org.springframework.data + spring-data-jpa + 1.9.0.RELEASE + + + + org.springframework + spring-test + ${spring.version} + + + + + javax.el + javax.el-api + 2.2.4 + + + + org.glassfish.web + javax.el + 2.2.4 + + + + + \ No newline at end of file diff --git a/jpa-day3-onetomany/src/main/java/cn/itcast/dao/CustomerDao.java b/jpa-day3-onetomany/src/main/java/cn/itcast/dao/CustomerDao.java new file mode 100644 index 0000000..6190984 --- /dev/null +++ b/jpa-day3-onetomany/src/main/java/cn/itcast/dao/CustomerDao.java @@ -0,0 +1,20 @@ +package cn.itcast.dao; + +import cn.itcast.domain.Customer; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; + +import java.util.List; + +/** + * 符合SpringDataJpa的dao层接口规范 + * JpaRepository<操作的实体类类型,实体类中主键属性的类型> + * * 封装了基本CRUD操作 + * JpaSpecificationExecutor<操作的实体类类型> + * * 封装了复杂查询(分页) + */ +public interface CustomerDao extends JpaRepository ,JpaSpecificationExecutor { + +} diff --git a/jpa-day3-onetomany/src/main/java/cn/itcast/dao/LinkManDao.java b/jpa-day3-onetomany/src/main/java/cn/itcast/dao/LinkManDao.java new file mode 100644 index 0000000..7fb2fea --- /dev/null +++ b/jpa-day3-onetomany/src/main/java/cn/itcast/dao/LinkManDao.java @@ -0,0 +1,11 @@ +package cn.itcast.dao; + +import cn.itcast.domain.LinkMan; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +/** + * 联系人的dao接口 + */ +public interface LinkManDao extends JpaRepository, JpaSpecificationExecutor { +} diff --git a/jpa-day3-onetomany/src/main/java/cn/itcast/domain/Customer.java b/jpa-day3-onetomany/src/main/java/cn/itcast/domain/Customer.java new file mode 100644 index 0000000..9568861 --- /dev/null +++ b/jpa-day3-onetomany/src/main/java/cn/itcast/domain/Customer.java @@ -0,0 +1,147 @@ +package cn.itcast.domain; + +import javax.persistence.*; +import java.util.HashSet; +import java.util.Set; + +/** + * 1.实体类和表的映射关系 + * @Eitity + * @Table + * 2.类中属性和表中字段的映射关系 + * @Id + * @GeneratedValue + * @Column + */ +@Entity +@Table(name="cst_customer") +public class Customer { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name="cust_id") + private Long custId; + @Column(name="cust_address") + private String custAddress; + @Column(name="cust_industry") + private String custIndustry; + @Column(name="cust_level") + private String custLevel; + @Column(name="cust_name") + private String custName; + @Column(name="cust_phone") + private String custPhone; + @Column(name="cust_source") + private String custSource; + + //配置客户和联系人之间的关系(一对多关系) + /** + * 使用注解的形式配置多表关系 + * 1.声明关系 + * @OneToMany : 配置一对多关系 + * targetEntity :对方对象的字节码对象 + * 2.配置外键(中间表) + * @JoinColumn : 配置外键 + * name:外键字段名称 + * referencedColumnName:参照的主表的主键字段名称 + * + * * 在客户实体类上(一的一方)添加了外键了配置,所以对于客户而言,也具备了维护外键的作用 + * + */ + +// @OneToMany(targetEntity = LinkMan.class) +// @JoinColumn(name = "lkm_cust_id",referencedColumnName = "cust_id") + /** + * 放弃外键维护权 + * mappedBy:对方配置关系的属性名称\ + * cascade : 配置级联(可以配置到设置多表的映射关系的注解上) + * CascadeType.all : 所有 + * MERGE :更新 + * PERSIST :保存 + * REMOVE :删除 + * + * fetch : 配置关联对象的加载方式 + * EAGER :立即加载 + * LAZY :延迟加载 + + */ + @OneToMany(mappedBy = "customer",cascade = CascadeType.ALL) + private Set linkMans = new HashSet<>(); + + public Long getCustId() { + return custId; + } + + public void setCustId(Long custId) { + this.custId = custId; + } + + public String getCustAddress() { + return custAddress; + } + + public void setCustAddress(String custAddress) { + this.custAddress = custAddress; + } + + 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 getCustName() { + return custName; + } + + public void setCustName(String custName) { + this.custName = custName; + } + + public String getCustPhone() { + return custPhone; + } + + public void setCustPhone(String custPhone) { + this.custPhone = custPhone; + } + + public String getCustSource() { + return custSource; + } + + public void setCustSource(String custSource) { + this.custSource = custSource; + } + + public Set getLinkMans() { + return linkMans; + } + + public void setLinkMans(Set linkMans) { + this.linkMans = linkMans; + } + + @Override + public String toString() { + return "Customer{" + + "custId=" + custId + + ", custAddress='" + custAddress + '\'' + + ", custIndustry='" + custIndustry + '\'' + + ", custLevel='" + custLevel + '\'' + + ", custName='" + custName + '\'' + + ", custPhone='" + custPhone + '\'' + + ", custSource='" + custSource + '\'' + + '}'; + } +} diff --git a/jpa-day3-onetomany/src/main/java/cn/itcast/domain/LinkMan.java b/jpa-day3-onetomany/src/main/java/cn/itcast/domain/LinkMan.java new file mode 100644 index 0000000..34eee4c --- /dev/null +++ b/jpa-day3-onetomany/src/main/java/cn/itcast/domain/LinkMan.java @@ -0,0 +1,128 @@ +package cn.itcast.domain; + +import javax.persistence.*; + +@Entity +@Table(name = "cst_linkman") +public class LinkMan { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "lkm_id") + private Long lkmId; //联系人编号(主键) + @Column(name = "lkm_name") + private String lkmName;//联系人姓名 + @Column(name = "lkm_gender") + private String lkmGender;//联系人性别 + @Column(name = "lkm_phone") + private String lkmPhone;//联系人办公电话 + @Column(name = "lkm_mobile") + private String lkmMobile;//联系人手机 + @Column(name = "lkm_email") + private String lkmEmail;//联系人邮箱 + @Column(name = "lkm_position") + private String lkmPosition;//联系人职位 + @Column(name = "lkm_memo") + private String lkmMemo;//联系人备注 + + /** + * 配置联系人到客户的多对一关系 + * 使用注解的形式配置多对一关系 + * 1.配置表关系 + * @ManyToOne : 配置多对一关系 + * targetEntity:对方的实体类字节码 + * 2.配置外键(中间表) + * + * * 配置外键的过程,配置到了多的一方,就会在多的一方维护外键 + * + */ + @ManyToOne(targetEntity = Customer.class,fetch = FetchType.LAZY) + @JoinColumn(name = "lkm_cust_id",referencedColumnName = "cust_id") + private Customer customer; + + public Long getLkmId() { + return lkmId; + } + + public void setLkmId(Long lkmId) { + this.lkmId = lkmId; + } + + public String getLkmName() { + return lkmName; + } + + public void setLkmName(String lkmName) { + this.lkmName = lkmName; + } + + public String getLkmGender() { + return lkmGender; + } + + public void setLkmGender(String lkmGender) { + this.lkmGender = lkmGender; + } + + public String getLkmPhone() { + return lkmPhone; + } + + public void setLkmPhone(String lkmPhone) { + this.lkmPhone = lkmPhone; + } + + public String getLkmMobile() { + return lkmMobile; + } + + public void setLkmMobile(String lkmMobile) { + this.lkmMobile = lkmMobile; + } + + public String getLkmEmail() { + return lkmEmail; + } + + public void setLkmEmail(String lkmEmail) { + this.lkmEmail = lkmEmail; + } + + public String getLkmPosition() { + return lkmPosition; + } + + public void setLkmPosition(String lkmPosition) { + this.lkmPosition = lkmPosition; + } + + public String getLkmMemo() { + return lkmMemo; + } + + public void setLkmMemo(String lkmMemo) { + this.lkmMemo = lkmMemo; + } + + public Customer getCustomer() { + return customer; + } + + public void setCustomer(Customer customer) { + this.customer = customer; + } + + @Override + public String toString() { + return "LinkMan{" + + "lkmId=" + lkmId + + ", lkmName='" + lkmName + '\'' + + ", lkmGender='" + lkmGender + '\'' + + ", lkmPhone='" + lkmPhone + '\'' + + ", lkmMobile='" + lkmMobile + '\'' + + ", lkmEmail='" + lkmEmail + '\'' + + ", lkmPosition='" + lkmPosition + '\'' + + ", lkmMemo='" + lkmMemo + '\'' + + '}'; + } +} diff --git a/jpa-day3-onetomany/src/main/resources/applicationContext.xml b/jpa-day3-onetomany/src/main/resources/applicationContext.xml new file mode 100644 index 0000000..127a6f3 --- /dev/null +++ b/jpa-day3-onetomany/src/main/resources/applicationContext.xml @@ -0,0 +1,102 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/jpa-day3-onetomany/src/test/java/cn/itcast/test/ObjectQueryTest.java b/jpa-day3-onetomany/src/test/java/cn/itcast/test/ObjectQueryTest.java new file mode 100644 index 0000000..2d9440e --- /dev/null +++ b/jpa-day3-onetomany/src/test/java/cn/itcast/test/ObjectQueryTest.java @@ -0,0 +1,76 @@ +package cn.itcast.test; + +import cn.itcast.dao.CustomerDao; +import cn.itcast.dao.LinkManDao; +import cn.itcast.domain.Customer; +import cn.itcast.domain.LinkMan; +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 org.springframework.transaction.annotation.Transactional; + +import java.util.Set; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = "classpath:applicationContext.xml") +public class ObjectQueryTest { + @Autowired + private CustomerDao customerDao; + + @Autowired + private LinkManDao linkManDao; + + //could not initialize proxy - no Session + //测试对象导航查询(查询一个对象的时候,通过此对象查询所有的关联对象) + @Test + @Transactional // 解决在java代码中的no session问题 + public void testQuery1() { + //查询id为1的客户 + Customer customer = customerDao.getOne(1l); + //对象导航查询,此客户下的所有联系人 + Set linkMans = customer.getLinkMans(); + + for (LinkMan linkMan : linkMans) { + System.out.println(linkMan); + } + } + + /** + * 对象导航查询: + * 默认使用的是延迟加载的形式查询的 + * 调用get方法并不会立即发送查询,而是在使用关联对象的时候才会差和讯 + * 延迟加载! + * 修改配置,将延迟加载改为立即加载 + * fetch,需要配置到多表映射关系的注解上 + * + */ + + @Test + @Transactional // 解决在java代码中的no session问题 + public void testQuery2() { + //查询id为1的客户 + Customer customer = customerDao.findOne(1l); + //对象导航查询,此客户下的所有联系人 + Set linkMans = customer.getLinkMans(); + + System.out.println(linkMans.size()); + } + + /** + * 从联系人对象导航查询他的所属客户 + * * 默认 : 立即加载 + * 延迟加载: + * + */ + @Test + @Transactional // 解决在java代码中的no session问题 + public void testQuery3() { + LinkMan linkMan = linkManDao.findOne(2l); + //对象导航查询所属的客户 + Customer customer = linkMan.getCustomer(); + System.out.println(customer); + } + +} diff --git a/jpa-day3-onetomany/src/test/java/cn/itcast/test/OneToManyTest.java b/jpa-day3-onetomany/src/test/java/cn/itcast/test/OneToManyTest.java new file mode 100644 index 0000000..5d8eab8 --- /dev/null +++ b/jpa-day3-onetomany/src/test/java/cn/itcast/test/OneToManyTest.java @@ -0,0 +1,139 @@ +package cn.itcast.test; + +import cn.itcast.dao.CustomerDao; +import cn.itcast.dao.LinkManDao; +import cn.itcast.domain.Customer; +import cn.itcast.domain.LinkMan; +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; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = "classpath:applicationContext.xml") +public class OneToManyTest { + + @Autowired + private CustomerDao customerDao; + + @Autowired + private LinkManDao linkManDao; + + /** + * 保存一个客户,保存一个联系人 + * 效果:客户和联系人作为独立的数据保存到数据库中 + * 联系人的外键为空 + * 原因? + * 实体类中没有配置关系 + */ + @Test + @Transactional //配置事务 + @Rollback(false) //不自动回滚 + public void testAdd() { + //创建一个客户,创建一个联系人 + Customer customer = new Customer(); + customer.setCustName("百度"); + + LinkMan linkMan = new LinkMan(); + linkMan.setLkmName("小李"); + + /** + * 配置了客户到联系人的关系 + * 从客户的角度上:发送两条insert语句,发送一条更新语句更新数据库(更新外键) + * 由于我们配置了客户到联系人的关系:客户可以对外键进行维护 + */ + customer.getLinkMans().add(linkMan); + + + customerDao.save(customer); + linkManDao.save(linkMan); + } + + + @Test + @Transactional //配置事务 + @Rollback(false) //不自动回滚 + public void testAdd1() { + //创建一个客户,创建一个联系人 + Customer customer = new Customer(); + customer.setCustName("百度"); + + LinkMan linkMan = new LinkMan(); + linkMan.setLkmName("小李"); + + /** + * 配置联系人到客户的关系(多对一) + * 只发送了两条insert语句 + * 由于配置了联系人到客户的映射关系(多对一) + * + * + */ + linkMan.setCustomer(customer); + + customerDao.save(customer); + linkManDao.save(linkMan); + } + + /** + * 会有一条多余的update语句 + * * 由于一的一方可以维护外键:会发送update语句 + * * 解决此问题:只需要在一的一方放弃维护权即可 + * + */ + @Test + @Transactional //配置事务 + @Rollback(false) //不自动回滚 + public void testAdd2() { + //创建一个客户,创建一个联系人 + Customer customer = new Customer(); + customer.setCustName("百度"); + + LinkMan linkMan = new LinkMan(); + linkMan.setLkmName("小李"); + + + linkMan.setCustomer(customer);//由于配置了多的一方到一的一方的关联关系(当保存的时候,就已经对外键赋值) + customer.getLinkMans().add(linkMan);//由于配置了一的一方到多的一方的关联关系(发送一条update语句) + + customerDao.save(customer); + linkManDao.save(linkMan); + } + + /** + * 级联添加:保存一个客户的同时,保存客户的所有联系人 + * 需要在操作主体的实体类上,配置casacde属性 + */ + @Test + @Transactional //配置事务 + @Rollback(false) //不自动回滚 + public void testCascadeAdd() { + Customer customer = new Customer(); + customer.setCustName("百度1"); + + LinkMan linkMan = new LinkMan(); + linkMan.setLkmName("小李1"); + + linkMan.setCustomer(customer); + customer.getLinkMans().add(linkMan); + + customerDao.save(customer); + } + + + /** + * 级联删除: + * 删除1号客户的同时,删除1号客户的所有联系人 + */ + @Test + @Transactional //配置事务 + @Rollback(false) //不自动回滚 + public void testCascadeRemove() { + //1.查询1号客户 + Customer customer = customerDao.findOne(1l); + //2.删除1号客户 + customerDao.delete(customer); + } +} diff --git a/jpa-day3-spec/pom.xml b/jpa-day3-spec/pom.xml new file mode 100644 index 0000000..333e939 --- /dev/null +++ b/jpa-day3-spec/pom.xml @@ -0,0 +1,170 @@ + + + 4.0.0 + + cn.itcast + jpa-day3-spec + 1.0-SNAPSHOT + + + + org.apache.maven.plugins + maven-compiler-plugin + + 6 + 6 + + + + + + + 5.0.2.RELEASE + 5.0.7.Final + 1.6.6 + 1.2.12 + 0.9.1.2 + + 8.0.20 + + + + + + junit + junit + 4.12 + test + + + + + org.aspectj + aspectjweaver + 1.6.8 + + + + org.springframework + spring-aop + ${spring.version} + + + + org.springframework + spring-context + ${spring.version} + + + + org.springframework + spring-context-support + ${spring.version} + + + + + org.springframework + spring-orm + ${spring.version} + + + + org.springframework + spring-beans + ${spring.version} + + + + org.springframework + spring-core + ${spring.version} + + + + + + + org.hibernate + hibernate-core + ${hibernate.version} + + + org.hibernate + hibernate-entitymanager + ${hibernate.version} + + + org.hibernate + hibernate-validator + 5.2.1.Final + + + + + + c3p0 + c3p0 + ${c3p0.version} + + + + + + log4j + log4j + ${log4j.version} + + + + org.slf4j + slf4j-api + ${slf4j.version} + + + + org.slf4j + slf4j-log4j12 + ${slf4j.version} + + + + + + mysql + mysql-connector-java + ${mysql.version} + + + + + org.springframework.data + spring-data-jpa + 1.9.0.RELEASE + + + + org.springframework + spring-test + ${spring.version} + + + + + javax.el + javax.el-api + 2.2.4 + + + + org.glassfish.web + javax.el + 2.2.4 + + + + + + \ No newline at end of file diff --git a/jpa-day3-spec/src/main/java/cn/itcast/dao/CustomerDao.java b/jpa-day3-spec/src/main/java/cn/itcast/dao/CustomerDao.java new file mode 100644 index 0000000..e6e281d --- /dev/null +++ b/jpa-day3-spec/src/main/java/cn/itcast/dao/CustomerDao.java @@ -0,0 +1,106 @@ +package cn.itcast.dao; + +import cn.itcast.domain.Customer; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; + +import java.util.List; + +/** + * 符合SpringDataJpa的dao层接口规范 + * JpaRepository<操作的实体类类型,实体类中主键属性的类型> + * * 封装了基本CRUD操作 + * JpaSpecificationExecutor<操作的实体类类型> + * * 封装了复杂查询(分页) + */ +public interface CustomerDao extends JpaRepository ,JpaSpecificationExecutor { + + /** + * 案例:根据客户名称查询客户 + * 使用jpql的形式查询 + * jpql:from Customer where custName = ? + * + * 配置jpql语句,使用的@Query注解 + */ + @Query(value="from Customer where custName = ?") + public Customer findJpql(String custName); + + + /** + * 案例:根据客户名称和客户id查询客户 + * jpql: from Customer where custName = ? and custId = ? + * + * 对于多个占位符参数 + * 赋值的时候,默认的情况下,占位符的位置需要和方法参数中的位置保持一致 + * + * 可以指定占位符参数的位置 + * ? 索引的方式,指定此占位的取值来源 + */ + @Query(value = "from Customer where custName = ?2 and custId = ?1") + public Customer findCustNameAndId(Long id, String name); + + /** + * 使用jpql完成更新操作 + * 案例 : 根据id更新,客户的名称 + * 更新4号客户的名称,将名称改为“黑马程序员” + * + * sql :update cst_customer set cust_name = ? where cust_id = ? + * jpql : update Customer set custName = ? where custId = ? + * + * @Query : 代表的是进行查询 + * * 声明此方法是用来进行更新操作 + * @Modifying + * * 当前执行的是一个更新操作 + * + */ + @Query(value = " update Customer set custName = ?2 where custId = ?1 ") + @Modifying + public void updateCustomer(long custId, String custName); + + + /** + * 使用sql的形式查询: + * 查询全部的客户 + * sql : select * from cst_customer; + * Query : 配置sql查询 + * value : sql语句 + * nativeQuery : 查询方式 + * true : sql查询 + * false:jpql查询 + * + */ + //@Query(value = " select * from cst_customer" ,nativeQuery = true) + @Query(value="select * from cst_customer where cust_name like ?1",nativeQuery = true) + public List findSql(String name); + + + /** + * 方法名的约定: + * findBy : 查询 + * 对象中的属性名(首字母大写) : 查询的条件 + * CustName + * * 默认情况 : 使用 等于的方式查询 + * 特殊的查询方式 + * + * findByCustName -- 根据客户名称查询 + * + * 再springdataJpa的运行阶段 + * 会根据方法名称进行解析 findBy from xxx(实体类) + * 属性名称 where custName = + * + * 1.findBy + 属性名称 (根据属性名称进行完成匹配的查询=) + * 2.findBy + 属性名称 + “查询方式(Like | isnull)” + * findByCustNameLike + * 3.多条件查询 + * findBy + 属性名 + “查询方式” + “多条件的连接符(and|or)” + 属性名 + “查询方式” + */ + public Customer findByCustName(String custName); + + + public List findByCustNameLike(String custName); + + //使用客户名称模糊匹配和客户所属行业精准匹配的查询 + public Customer findByCustNameLikeAndCustIndustry(String custName, String custIndustry); +} diff --git a/jpa-day3-spec/src/main/java/cn/itcast/domain/Customer.java b/jpa-day3-spec/src/main/java/cn/itcast/domain/Customer.java new file mode 100644 index 0000000..bc96e4b --- /dev/null +++ b/jpa-day3-spec/src/main/java/cn/itcast/domain/Customer.java @@ -0,0 +1,103 @@ +package cn.itcast.domain; + +import javax.persistence.*; + +/** + * 1.实体类和表的映射关系 + * @Eitity + * @Table + * 2.类中属性和表中字段的映射关系 + * @Id + * @GeneratedValue + * @Column + */ +@Entity +@Table(name="cst_customer") +public class Customer { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name="cust_id") + private Long custId; + @Column(name="cust_address") + private String custAddress; + @Column(name="cust_industry") + private String custIndustry; + @Column(name="cust_level") + private String custLevel; + @Column(name="cust_name") + private String custName; + @Column(name="cust_phone") + private String custPhone; + @Column(name="cust_source") + private String custSource; + + public Long getCustId() { + return custId; + } + + public void setCustId(Long custId) { + this.custId = custId; + } + + public String getCustAddress() { + return custAddress; + } + + public void setCustAddress(String custAddress) { + this.custAddress = custAddress; + } + + 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 getCustName() { + return custName; + } + + public void setCustName(String custName) { + this.custName = custName; + } + + public String getCustPhone() { + return custPhone; + } + + public void setCustPhone(String custPhone) { + this.custPhone = custPhone; + } + + public String getCustSource() { + return custSource; + } + + public void setCustSource(String custSource) { + this.custSource = custSource; + } + + @Override + public String toString() { + return "Customer{" + + "custId=" + custId + + ", custAddress='" + custAddress + '\'' + + ", custIndustry='" + custIndustry + '\'' + + ", custLevel='" + custLevel + '\'' + + ", custName='" + custName + '\'' + + ", custPhone='" + custPhone + '\'' + + ", custSource='" + custSource + '\'' + + '}'; + } +} diff --git a/jpa-day3-spec/src/main/resources/applicationContext.xml b/jpa-day3-spec/src/main/resources/applicationContext.xml new file mode 100644 index 0000000..72692ff --- /dev/null +++ b/jpa-day3-spec/src/main/resources/applicationContext.xml @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/jpa-day3-spec/src/test/java/cn/itcast/test/SpecTest.java b/jpa-day3-spec/src/test/java/cn/itcast/test/SpecTest.java new file mode 100644 index 0000000..24219d0 --- /dev/null +++ b/jpa-day3-spec/src/test/java/cn/itcast/test/SpecTest.java @@ -0,0 +1,169 @@ +package cn.itcast.test; + +import cn.itcast.dao.CustomerDao; +import cn.itcast.domain.Customer; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import javax.persistence.criteria.*; +import java.util.List; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = "classpath:applicationContext.xml") +public class SpecTest { + + @Autowired + private CustomerDao customerDao; + + /** + * 根据条件,查询单个对象 + * + */ + @Test + public void testSpec() { + //匿名内部类 + /** + * 自定义查询条件 + * 1.实现Specification接口(提供泛型:查询的对象类型) + * 2.实现toPredicate方法(构造查询条件) + * 3.需要借助方法参数中的两个参数( + * root:获取需要查询的对象属性 + * CriteriaBuilder:构造查询条件的,内部封装了很多的查询条件(模糊匹配,精准匹配) + * ) + * 案例:根据客户名称查询,查询客户名为传智播客的客户 + * 查询条件 + * 1.查询方式 + * cb对象 + * 2.比较的属性名称 + * root对象 + * + */ + Specification spec = new Specification() { + @Override + public Predicate toPredicate(Root root, CriteriaQuery query, CriteriaBuilder cb) { + //1.获取比较的属性 + Path custName = root.get("custName"); + //2.构造查询条件 : select * from cst_customer where cust_name = '传智播客' + /** + * 第一个参数:需要比较的属性(path对象) + * 第二个参数:当前需要比较的取值 + */ + Predicate predicate = cb.equal(custName, "传智播客");//进行精准的匹配 (比较的属性,比较的属性的取值) + return predicate; + } + }; + Customer customer = customerDao.findOne(spec); + System.out.println(customer); + } + + /** + * 多条件查询 + * 案例:根据客户名(传智播客)和客户所属行业查询(it教育) + * + */ + @Test + public void testSpec1() { + /** + * root:获取属性 + * 客户名 + * 所属行业 + * cb:构造查询 + * 1.构造客户名的精准匹配查询 + * 2.构造所属行业的精准匹配查询 + * 3.将以上两个查询联系起来 + */ + Specification spec = new Specification() { + @Override + public Predicate toPredicate(Root root, CriteriaQuery query, CriteriaBuilder cb) { + Path custName = root.get("custName");//客户名 + Path custIndustry = root.get("custIndustry");//所属行业 + + //构造查询 + //1.构造客户名的精准匹配查询 + Predicate p1 = cb.equal(custName, "传智播客");//第一个参数,path(属性),第二个参数,属性的取值 + //2..构造所属行业的精准匹配查询 + Predicate p2 = cb.equal(custIndustry, "it教育"); + //3.将多个查询条件组合到一起:组合(满足条件一并且满足条件二:与关系,满足条件一或满足条件二即可:或关系) + Predicate and = cb.and(p1, p2);//以与的形式拼接多个查询条件 + // cb.or();//以或的形式拼接多个查询条件 + return and; + } + }; + Customer customer = customerDao.findOne(spec); + System.out.println(customer); + } + + + /** + * 案例:完成根据客户名称的模糊匹配,返回客户列表 + * 客户名称以 ’传智播客‘ 开头 + * + * equal :直接的到path对象(属性),然后进行比较即可 + * gt,lt,ge,le,like : 得到path对象,根据path指定比较的参数类型,再去进行比较 + * 指定参数类型:path.as(类型的字节码对象) + */ + @Test + public void testSpec3() { + //构造查询条件 + Specification spec = new Specification() { + @Override + public Predicate toPredicate(Root root, CriteriaQuery query, CriteriaBuilder cb) { + //查询属性:客户名 + Path custName = root.get("custName"); + //查询方式:模糊匹配 + Predicate like = cb.like(custName.as(String.class), "传智播客%"); + return like; + } + }; +// List list = customerDao.findAll(spec); +// for (Customer customer : list) { +// System.out.println(customer); +// } + //添加排序 + //创建排序对象,需要调用构造方法实例化sort对象 + //第一个参数:排序的顺序(倒序,正序) + // Sort.Direction.DESC:倒序 + // Sort.Direction.ASC : 升序 + //第二个参数:排序的属性名称 + Sort sort = new Sort(Sort.Direction.DESC,"custId"); + List list = customerDao.findAll(spec, sort); + for (Customer customer : list) { + System.out.println(customer); + } + } + + /** + * 分页查询 + * Specification: 查询条件 + * Pageable:分页参数 + * 分页参数:查询的页码,每页查询的条数 + * findAll(Specification,Pageable):带有条件的分页 + * findAll(Pageable):没有条件的分页 + * 返回:Page(springDataJpa为我们封装好的pageBean对象,数据列表,共条数) + */ + @Test + public void testSpec4() { + + Specification spec = null; + //PageRequest对象是Pageable接口的实现类 + /** + * 创建PageRequest的过程中,需要调用他的构造方法传入两个参数 + * 第一个参数:当前查询的页数(从0开始) + * 第二个参数:每页查询的数量 + */ + Pageable pageable = new PageRequest(0,2); + //分页查询 + Page page = customerDao.findAll(null, pageable); + System.out.println(page.getContent()); //得到数据集合列表 + System.out.println(page.getTotalElements());//得到总条数 + System.out.println(page.getTotalPages());//得到总页数 + } +}