SpringData 学习笔记
一、SpringData概述
1、 springdata:是spring的一个子项目。用于简化数据库访问。支持Nosql 和关系型数据存储。其主要目标是使数据库的访问变得更加方便快捷。
2、springdata所支持的Nosql 数据库:
-MongoDB(文档数据库)
-Neo4j(图形数据库)
-Redis(键值存储)
-Hbase(列族数据库)
3、存储技术:
JDBC JPA
二、搭建JPA环境
1、JPA :java持久化API,是sun公司推出基于ORM的规范,内部是接口和抽象类组成。实现致力于减少Dao 层的操作。声明接口即可
1、创建maven 工程导入坐标
<dependencies>
<!-- junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!-- hibernate对jpa的支持包 -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernateentitymanager</artifactId>
<version>5.4.9.Final</version>
</dependency>
<!-- c3p0 -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-c3p0</artifactId>
<version>5.4.4.Final</version>
</dependency>
<!-- log日志-->
<dependency>
<groupId>apache-log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.14</version>
</dependency>
<!-- Mysql and MariaDB -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
</dependency>
</dependencies>
2、JPA的核心配置文件
1、配置到类路径下的META-INF的文件夹下
persistence.xml
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0">
<!--配置persistence-unit持久化单元:
name :持久化名称
transaction-type:事务管理方式
JTA :分布式事务管理
RESOURCE_LOCAL:本地事务管理
-->
<persistence-unit name="myjpa" transaction-type="RESOURCE_LOCAL">
<!--JPA的实现方式-->
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<properties>
<!--数据库信息-->
<property name="javax.persistence.jdbc.user" value="root"/>
<property name="javax.persistence.jdbc.password" value="root"/>
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://127.0.0.1:3306/mybookshop"/>
<!--可选配置,jpa 实现方(Hibernate)的配置信息
显示sql: hibernate.show_sql : true 显示
自动创建数据库表: hibernate.hbm2ddl.auto :
create : 程序运行时创建数据库表,(如果有表先删除,再创建)
update: 程序运行时创建(如果有表不创建)
none :不创建
-->
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.hbm2ddl.auto" value="update"/>
</properties>
</persistence-unit>
</persistence>
3、映射关系
实体类 ,配置映射关系:
-
1.实体类和表的映射关系
-
@Entity
-
@Table(name =“goods_info”)
-
2.实体类中属性和表字段的映射关系
-
@Column (name =“bname”)
-
-
@GeneratedValue(strategy = GenerationType.IDENTITY) //住建生成策略(自增)mysql
strategy = GenerationType.SEQUENCE :序列(底层数据库必须支持序列)oracle
strategy = GenerationType.TABLE : 通过一张数据库表的形式,完成主键自增
strategy = GenerationType.AUTO : 程序自动选择以上策略
-
package com.tydic.entity;
import javax.persistence.*;
/**
* @author: tydic leiyunlong
* @time: 2019/12/25
* @Version: 1.0
*/
@Entity
@Table(name ="goods_info")
public class Books {
@Id //声明住建ID
@GeneratedValue(strategy = GenerationType.IDENTITY) //生成策略
@Column (name ="id")
private Integer id;
@Column (name ="bname")
private String name;
@Column (name ="bprice")
private Double price;
@Column (name ="bread")
private String read;
@Column (name ="manu")
private String manu;
@Column (name ="db_source")
private String db_source;
public Books() {
}
public Books(String name, Double price, String read, String manu, String db_source) {
this.name = name;
this.price = price;
this.read = read;
this.manu = manu;
this.db_source = db_source;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price = price;
}
public String getRead() {
return read;
}
public void setRead(String read) {
this.read = read;
}
public String getManu() {
return manu;
}
public void setManu(String manu) {
this.manu = manu;
}
public String getDb_source() {
return db_source;
}
public void setDb_source(String db_source) {
this.db_source = db_source;
}
}
4、操作步骤
**// 1. 记载配置文件创建工厂(实体管理器工厂)对象 factory **
EntityManagerFactory factory = Persistence.createEntityManagerFactory(“myjpa”);
createEntityManagerFactory(“myjpa”);持久化单元名称,
Persistence静态方法,根据持久化单元名称创建实体管理器工厂对象factory,
内部维护了数据库信息,维护了缓存信息,维护了实体管理器对象,创建factory 过程中创建了数据库表,线程安全的。
解决EntityManagerFactory 浪费资源问题:
静态代码块的形式创建公共EntityManagerFactory 对象
**// 2. 通过实体管理器工厂获取实体管理器 emf **
EntityManager emf = factory.createEntityManager();
emf.persist(book); //插入
emf.merge ;//更新 需要先根据ID查询,再更新
emf .find; //根据ID查询,查询的对象就是当前本身,调用find方法就会调用sql 语句进行查询
emf.reference ;//获取到的对象是一个动态代理的对象,不会立即发送sql 语句进行查询,当调用查询结果对象时 候才执行 ,也就是延迟加载。
emf . remove ;//删除 需要先根据ID查询,再删除
// 3. 获取事务对象 et,开启事务
EntityTransaction et = emf.getTransaction();
et.begin();开启
et.commit ; 提交
et.rollback;回滚
// 4. 完成CRUD操作
// 5. 提交事务(回滚)
// 6. 释放资源
测试:
package com.tydic.test;
import com.tydic.entity.Books;
import org.junit.Test;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
/**
*
* @author: tydic leiyunlong
* @time: 2019/12/25
* @Version: 1.0
*/
public class BookTest {
@Test
public void BookSave(){
EntityManagerFactory factory = Persistence.createEntityManagerFactory("myjpa");
EntityManager emf = factory.createEntityManager();
EntityTransaction et = emf.getTransaction();
et.begin();
Books book = new Books();
book.setName("啦啦啦");
book.setPrice(18.2);
emf.persist(book); //保存
et.commit();
emf.close();
factory.close();
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-08s47FVv-1578302998473)(C:\Users\lyl\AppData\Roaming\Typora\typora-user-images\1577257430219.png)]
5、创建实体管理器工厂公工具
解决实体管理器工厂的浪费资源和时间消耗问题:
- 第一次访问getEntityManger() 经过静态代码块创建工厂对象 factory ,getEntityManger 方法获取 EntityManager 管理器对象
- 第二次访问 getEntityManger()直接通过一个已经创建好的工厂对象 factory 创建EntityManager对象
package com.tydic.utils;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
/**
*
* @author: tydic leiyunlong
* @time: 2019/12/25
* @Version: 1.0
*/
public class JpaUtils {
private static EntityManagerFactory factory;
static {
// 1. 加载配置文件,创建entityManagerFactory 工厂对象
factory = Persistence.createEntityManagerFactory("myjpa");
}
//2.获取EntityManager 对象
public static EntityManager getEntityManger(){
return factory.createEntityManager();
}
}
测试:
package com.tydic.test;
import com.tydic.entity.Books;
import com.tydic.utils.JpaUtils;
import org.hibernate.dialect.Database;
import org.junit.Test;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
/**
*
* @author: tydic leiyunlong
* @time: 2019/12/25
* @Version: 1.0
*/
public class BookTest {
@Test
public void bookSave(){
/* // 1. 记载配置文件创建工厂(实体管理器工厂)对象
EntityManagerFactory factory = Persistence.createEntityManagerFactory("myjpa");
// 2. 通过实体管理器工厂获取实体管理器
EntityManager emf = factory.createEntityManager();*/
EntityManager emf = JpaUtils.getEntityManger();
// 3. 获取事务对象,开启事务
EntityTransaction et = emf.getTransaction();
et.begin();
// 4. 完成CRUD操作
Books book = new Books("啦啦啦",12.2,"好书","A","0");
emf.persist(book); //保存
// 5. 提交事务(回滚)
et.commit();
// 6. 释放资源
emf.close();
// factory.close(); 公共的静态的就不用关闭了
}
}
6、查询
1.按照ID 查询
/**
* 根据id 查询
*/
@Test
public void findById(){
// 1. 通过工厂获取管理器对象
EntityManager entityManger = JpaUtils.getEntityManger();
// 2. 获取事务,开启事务
EntityTransaction transaction = entityManger.getTransaction();
transaction.begin();
// 3. CRUD
entityManger.find(Books.class,1);
// 4. 提交事务
transaction.commit();
// 5. 释放资源
entityManger.close();
}
2. 查询全部
@Test
public void findAll(){
// 1. 通过工厂获取管理器对象
EntityManager entityManger = JpaUtils.getEntityManger();
// 2. 获取事务,开启事务
EntityTransaction transaction = entityManger.getTransaction();
transaction.begin();
// 3. 查询所有
String jpql = "from com.tydic.entity.Books";
Query query = entityManger.createQuery(jpql); //创建query 查询对象,query对象才是执行jpql 的对象
List resultList = query.getResultList(); // 执行查询,并 封装结果集
for (Object o:resultList) {
System.out.println(o);
}
// 4. 提交事务
transaction.commit();
// 5. 释放资源
entityManger.close();
}
1、 倒序查询
sql : SELECT * FROM goods_info GROUP BY id DESC
jpql : from Books group by id desc
2 、统计总条数
sql: SELECT COUNT(id) FROM goods_info
jpql: select count (id) from Books [count(属性的 id )]
query.getSingleResult(); 唯一的结果集
3.分页查询
sql: SELECT * FROM goods_info limit ?,?
/**
* 分页查询
*/
@Test
public void queryAll(){
// 1. 通过工厂获取管理器对象
EntityManager entityManger = JpaUtils.getEntityManger();
// 2. 获取事务,开启事务
EntityTransaction transaction = entityManger.getTransaction();
transaction.begin();
// 3. 查询所有
String jpql = "from Books";
Query query = entityManger.createQuery(jpql); //创建query 查询对象,query对象才是执行jpql 的对象
query.setFirstResult(0); // 设置起始页
query.setMaxResults(4); // 每页条数
List resultList = query.getResultList(); // 执行查询,并封装结果集
for (Object o:resultList) {
System.out.println(o);
}
// 4. 提交事务
transaction.commit();
// 5. 释放资源
entityManger.close();
}
4.模糊查询
/**
* 模糊查询
*/
@Test
public void queryLike(){
// 1. 通过工厂获取管理器对象
EntityManager entityManger = JpaUtils.getEntityManger();
// 2. 获取事务,开启事务
EntityTransaction transaction = entityManger.getTransaction();
transaction.begin();
// 3. 查询所有
String jpql = "from Books where name like ?1 ";
Query query = entityManger.createQuery(jpql); //创建query 查询对象,query对象才是执行jpql 的对象
query.setParameter(1,"%三%");
query.setFirstResult(0); // 设置起始页
query.setMaxResults(4); // 每页条数
List resultList = query.getResultList(); // 执行查询,并封装结果集
for (Object o:resultList) {
System.out.println(o);
}
// 4. 提交事务
transaction.commit();
// 5. 释放资源
entityManger.close();
}
四、SpringData JPA
1.SpringData JPA 概述
是基于ORM 框架,JPA规范的基础上封装的一套JPA应用框架。解脱了Dao层操作,封装了CRUD,可以使用 springdata JPA +ORM (hibernate)。
2.SpringData JPA特性
使用SpringData JPA 减少了数据库访问层的操作,只需要写接口即可。
3. 几者之间的关系
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FeIrnmsK-1578302998474)(C:\Users\lyl\AppData\Roaming\Typora\typora-user-images\1577323977115.png)]
五、搭建SpringData JPA 环境
1.jar包
** 注意jar 的版本兼容性,后期检查得
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<org.springframework.version>4.2.5.RELEASE</org.springframework.version>
<org.hibernate.version>4.3.8.Final</org.hibernate.version>
<spring-data-jpa.version>1.9.0.RELEASE</spring-data-jpa.version>
<com.fasterxml.jackson.version>2.5.0</com.fasterxml.jackson.version>
<org.slf4j.version>1.6.1</org.slf4j.version>
</properties>
<!-- 版本全部修改 一定要改 -->
<dependencies>
<!--单元测试-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
<scope>test</scope>
</dependency>
<!--============================ spring 包 =====================-->
<!--spring AOP相关包-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.6.8</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.0.8.RELEASE</version>
</dependency>
<!---->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<!--spring对orm 框架的支持包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<!--spring核心包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<!--============================- hibernate包 =====================-->
<!--hibernate核心包-->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.1.0.Final</version>
</dependency>
<!--hibernateJPA实现包-->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>5.1.0.Final</version>
</dependency>
<!--验证包-->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.0.1.Final</version>
</dependency>
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.15</version>
</dependency>
<dependency>
<!--springData JPA的坐标-->
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>2.0.7.RELEASE</version>
</dependency>
<!--springdata JPA 必须引入-->
<dependency>
<groupId>javax.el</groupId>
<artifactId>javax.el-api</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>org.glassfish.web</groupId>
<artifactId>javax.el</artifactId>
<version>2.2.6</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.1.5.RELEASE</version>
<scope>test</scope>
</dependency>
</dependencies>
*** 修改jar
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.tydic</groupId>
<artifactId>SpringData_JPA</artifactId>
<version>1.0-SNAPSHOT</version>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>6</source>
<target>6</target>
</configuration>
</plugin>
</plugins>
</build>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<org.springframework.version>4.2.5.RELEASE</org.springframework.version>
<org.hibernate.version>4.3.8.Final</org.hibernate.version>
<spring-data-jpa.version>1.9.0.RELEASE</spring-data-jpa.version>
<com.fasterxml.jackson.version>2.5.0</com.fasterxml.jackson.version>
<org.slf4j.version>1.6.1</org.slf4j.version>
</properties>
<dependencies>
<!-- Spring的支持包 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${org.springframework.version}</version>
<scope>test</scope>
</dependency>
<!-- 引入web前端的支持 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<!-- SpringMCV上传需要用到io包-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-io</artifactId>
<version>1.3.2</version>
</dependency>
<!-- 文件上传用到的包 -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.2.2</version>
</dependency>
<!-- SpringMVC的json支持包 -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>${com.fasterxml.jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>${com.fasterxml.jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${com.fasterxml.jackson.version}</version>
</dependency>
<!--SpringDataJpa -> Spring封装了JPA (还是要用之前的JPA)-->
<!-- hibernate的支持包 -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>${org.hibernate.version}</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>${org.hibernate.version}</version>
</dependency>
<!-- SpringData的支持包 -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>${spring-data-jpa.version}</version>
</dependency>
<!-- SpringDataJpa的擴展包 -->
<dependency>
<groupId>com.github.wenhao</groupId>
<artifactId>jpa-spec</artifactId>
<version>3.1.1</version>
<!-- 把所有的依賴都去掉 -->
<exclusions>
<exclusion>
<groupId>*</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- c3p0 -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-c3p0</artifactId>
<version>5.4.4.Final</version>
</dependency>
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.2.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
</dependency>
<!--lang包:对Java中的lang包中的东西做扩展-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.5</version>
</dependency>
<!-- 測試包 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<!-- 这个scope 只能作用在编译和测试时,同时没有传递性。表示在运行的时候不添加此jar文件 -->
<scope>provided</scope>
</dependency>
<!-- 日志文件(大家学习MyBatis时候详细讲解) -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${org.slf4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${org.slf4j.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.14</version>
</dependency>
</dependencies>
</project>
2.配置Spring整合JPA
applicationContext
<?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:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/data/jpa
http://www.springframework.org/schema/data/jpa/spring-jpa.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<!--配置service扫包-->
<context:component-scan base-package="com.tydic.service"/>
<!-- 1. 配置dataSource数据源-->
<!--关联外部的db.properties-->
<context:property-placeholder location="classpath:db.properties"/>
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${db.driver}"/>
<property name="jdbcUrl" value="${db.url}"/>
<property name="user" value="${db.username}"/>
<property name="password" value="${db.password}"/>
</bean>
<!-- 2. 配置JPA 的EntityManagerFactory-->
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource"/>
<!--jpa 实现产品的适配器-->
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/>
</property>
<!-- 扫描加了@Entity的包-->
<property name="packagesToScan" value="com.tydic.entity"/>
<!--jpa实现产品的 属性-->
<property name="jpaProperties">
<props>
<!--二级缓存-->
<!--<prop key="factory_class">org.hibernate </prop>
<prop key="net.sf">eh</prop>-->
<!--生成数据表的列的策略-->
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
</bean>
<!-- 3. 配置事务管理器-->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<!-- 4. 配置支持注解的事务-->
<tx:annotation-driven transaction-manager="transactionManager"/>
<!-- 5. 配置springdata-->
<!--扫描Repository Bean 所在的包-->
<!--jpa 的命名空间-->
<jpa:repositories base-package="com.tydic.dao" entity-manager-factory-ref="entityManagerFactory"/>
</beans>
六、Reporstory 接口
-
Reporstory 接口 是一个空接口,即标记接口
-
若我们定义的接口继承了Reporstory ,则该接口会被IOC容器识别为一个Reporstory Bean,纳入到IOC容器中,进而可以在该接口中定义满足一定规范的方法
-
实际上也可以通过@RepositoryDefinition(domainClass = Books.class,idClass = Integer.class) 注解代继承
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2WXKJNtO-1578302998474)(C:\Users\lyl\AppData\Roaming\Typora\typora-user-images\1577346050387.png)]
1、方法规范
-
查询的话,以get 、find、read 方法开头
-
条件查询时,条件的属性用条件的关键字连接
-
条件属性以首字母大写
-
若有级联查询,则属性之间使用 _ 隔开
package com.tydic.dao; import com.tydic.entity.Books; import org.springframework.data.repository.RepositoryDefinition; import java.util.List; /** * * @author: tydic leiyunlong * @time: 2019/12/26 * @Version: 1.0 */ //该注解相当于接口继承了Reporstory @RepositoryDefinition(domainClass = Books.class,idClass = Integer.class) public interface BookDao { List<Books> findAll(); List <Books> getByName (String name); }
```java
package com.tydic.test;
import com.tydic.dao.BookDao;
import com.tydic.entity.Books;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import javax.sql.DataSource;
import java.sql.SQLException;
import java.util.List;
/**
*
* @author: tydic leiyunlong
* @time: 2019/12/26
* @Version: 1.0
*/
public class BookTest {
private ApplicationContext ctx = null;
private BookDao bookDao = null;
{ ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
bookDao = ctx.getBean(BookDao.class);
}
/*测试方法*/
@Test
public void findAll(){
List<Books> list =bookDao.findAll();
for(Object O : list){
System.out.println(O);
}
}
@Test
public void testJPA(){
}
/*测试datasource*/
@Test
public void testDatasource() throws SQLException {
DataSource dataSource = ctx.getBean(DataSource.class);
System.out.println(dataSource.getConnection());
}
}
2、@Query 注解
1.使用@Query注解,可以自定义jpql 语句
@RepositoryDefinition(domainClass = Detail.class,idClass = Integer.class)
public interface DetailDao {
List<Detail> findAll();
/*查询在detail表中ID最大值的Book*/
@Query("SELECT b from Books b where b.id = (SELECT max (d.id) from Detail d)")
Books getMaxIdBook();
}
----------------------------------------------------------------------------------------
/*Query 的子查询*/
@Test
public void queryGetMaxId(){
Books books = detailDao.getMaxIdBook();
System.out.println(books);
}
2.传参
第一种方式,使用占位符,需要标记 1 2
注意:这里的 b.name 是属性 不是列名字 b.bname
/*@Query 传参*/
@Query("select b from Books b where b.name = ?1 and b.read = ?2")
List<Books> testQueryParam1(String name , String read);
-----------------------------------------------------------------------------------------
@Test
public void testParma1(){
List<Books> books = bookDao.testQueryParam1("啦啦啦","好书");
for (Object L :books){
System.out.println(L);
}
}
第二种方式,使用命名参数的方式:
@Query("select b from Books b where b.name = :name and b.read = :read")List<Books> testQueryParam2(@Param("name") String name , @Param("read") String read);
-----------------------------------------------------------------------------------------
@Test
public void testParma2(){
List<Books> books = bookDao.testQueryParam2("啦啦啦","好书");
for (Object L :books){
System.out.println(L);
}
}
like 方式(同样可以使用参数命名 like %:name%)
@Query("select b from Books b where b.name like %?1% or b.read like %?2%")
List<Books> testQueryParam3(String name , String read);
-------------------------------------------------------------------------------------
@Test
public void testParma3(){
List<Books> books = bookDao.testQueryParam3("啦","好");
for (Object L :books){
System.out.println(L);
}
}
使用nativeQuery = true 即可使用原生的sql 查询
@Query(value = "select xxx from xxx" ,nativeQuery = true)
3、@Modifying 注解和事务
/*修改操作* 在query中写jpql 语句,更新和删除必须使用@Modifying 注解,用来通知springdata 这是一个update 操作 或者是delete 操作* 以为springdata 的每个方法都默认是只读事务,所以必须加事务,而事务需要放在service 层,记得配置service自动扫包
**/
@Modifying@Query("update Books b set b.name= ?1 where b.id =?2 ")void updataBooks (String name ,Integer id);
-------------------------------------------------------------------------------------
@Test
public void updateBooks(){
booksService.updataBooks("哈哈哈",9);
七、Reporstory子接口
1、CrudReporstory
只要继承了CrudReporstory 接口,即可使用已经封装好的CRUD方法
1. save 保存方法
package com.tydic.dao;
import com.tydic.entity.Orders;
import org.springframework.data.repository.CrudRepository;
/**
* CrudRepository 中save方法批量保存
*/
public interface OrderDao extends CrudRepository <Orders,Integer> {
}
@Service
public class OrderService {
@Autowired
private OrderDao orderDao;
@Transactional
public void saveOrders (List<Orders> orders){
orderDao.save(orders);
}
@Test
public void saveOrders(){
List <Orders> list = new ArrayList<Orders>();
for (int i = 'a';i<'z';i++){
Orders orders = new Orders();
orders.setName("买家"+(char)i + ""+ (char)i);
orders.setAddress("家住"+(char)i+"地方");
orders.setCreatetime(new Timestamp(System.currentTimeMillis()));
list.add(orders);
orderService.saveOrders(list);
}
}
2.删除
跟保存类似
后续。。。。
2、PagingAndSortingReporstory
分页和排序
1.分页:
public interface OrderDao extends PagingAndSortingRepository<Orders,Integer> {
}
@Test
public void pagingAndSorting(){
int pageNo = 3-1; //起始页
int pageSize = 5; // 每页最大数
// Pageable 接口通常使用的是PageRequest实现类
PageRequest pageable = new PageRequest(pageNo,pageSize);
Page<Orders> page = orderDao.findAll(pageable);
System.out.println("总记录数:" + page.getTotalElements());
System.out.println("总页数:"+page.getTotalPages());
System.out.println("当前第几页:"+ (page.getNumber()+1));
System.out.println("当前页的list:"+page.getContent());
System.out.println("当前页的记录数:"+page.getNumberOfElements());
}
2.排序
@Test
public void pagingAndSorting(){
int pageNo = 3-1; //起始页
int pageSize = 5; // 每页最大数
// Pageable 接口通常使用的是PageRequest实现类
// 排序相关的
Sort.Order order1 = new Sort.Order(Sort.Direction.ASC,"id"); //升序
Sort.Order order2 = new Sort.Order(Sort.Direction.DESC,"id"); //降序
Sort sort = new Sort(order2);
PageRequest pageable = new PageRequest(pageNo,pageSize,sort);
Page<Orders> page = orderDao.findAll(pageable);
System.out.println("总记录数:" + page.getTotalElements());
System.out.println("总页数:"+page.getTotalPages());
System.out.println("当前第几页:"+ (page.getNumber()+1));
System.out.println("当前页的list:"+page.getContent());
System.out.println("当前页的记录数:"+page.getNumberOfElements());
}
3、JpaRepository
JpaRepository extends PagingAndSortingReporstory extends CrudReporstory extends Reporstory
更新数据,类似于JPA 的 emf.merge ;//更新 需要先根据ID查询,再更新
@Test
public void JpaRepostory(){
Orders orders = new Orders();
orders.setName("我是买家A");
orders.setAddress("我是住址A");
orders.setId(67);
orders.setCreatetime(new Timestamp(System.currentTimeMillis()));
orderDao.saveAndFlush(orders);
}
4、JpaSpecificationExecutor
JpaSpecificationExecutor 他不是Repository 家族的 ,是实现一组Criteria查询相关的方法
Specification :封装了Criteria 的查询条件,通常使用匿名内部类的方式来创建接口对象。
public interface OrderDao extends JpaRepository<Orders,Integer>, JpaSpecificationExecutor<Orders> {
}
/**
* 目标:实现带查询条件的分页。
* 调用JpaSpecificationExecutor的Page<T> findAll(Specification<T> var1, Pageable var2);
* Specification :封装了Criteria 的查询条件,通常使用匿名内部类的方式来创建接口对象。
* Pageable 封装了请求分页的信息,如pageNo,pageSize,sort等
*/
@Test
public void JpaSpecificationExecutor (){
int pageNo = 3-1; //起始页
int pageSize = 5; // 每页最大数
PageRequest pageable = new PageRequest(pageNo,pageSize);
Specification<Orders> specification = new Specification<Orders>() {
/**
* 目标:id >16 的对象
* @param root :代表查询的实体类
* @param criteriaQuery :可以从中得到root对象,即告知Criteria 查询哪一个实体类,也 可以添加查询条件,还可以介个EntityManager 对象得到最终查询的TypeQuery 对象
* @param criteriaBuilder :CriteriaBuilder对象,用于创建Criteria相关对象的工厂,可 以从中获取到Predicate 对象
* @return :Predicate 类型,代表一个查询条件
*/
@Override
public Predicate toPredicate(Root<Orders> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
Path path =root.get("id");
Predicate predicate = criteriaBuilder.gt(path,16);
return predicate;
}
};
Page<Orders> page = orderDao.findAll(specification,pageable);
System.out.println("总记录数:" + page.getTotalElements());
System.out.println("总页数:"+page.getTotalPages());
System.out.println("当前第几页:"+ (page.getNumber()+1));
System.out.println("当前页的list:"+page.getContent());
System.out.println("当前页的记录数:"+page.getNumberOfElements());
}
5、自定义Repository 接口方法
步骤:
-
定义一个接口:声明要添加的,并自实现的方法。
-
提供该接口的实现类:类名需要在声明的Repository 后加Impl,并实现方法
-
声明Repository 接口,并继承刚才定义的接口
-
使用
后续。。。
ers>() {
/**
* 目标:id >16 的对象
* @param root :代表查询的实体类
* @param criteriaQuery :可以从中得到root对象,即告知Criteria 查询哪一个实体类,也 可以添加查询条件,还可以介个EntityManager 对象得到最终查询的TypeQuery 对象
* @param criteriaBuilder :CriteriaBuilder对象,用于创建Criteria相关对象的工厂,可 以从中获取到Predicate 对象
* @return :Predicate 类型,代表一个查询条件
*/
@Override
public Predicate toPredicate(Root root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
Path path =root.get("id");
Predicate predicate = criteriaBuilder.gt(path,16);
return predicate;
}
};
Page<Orders> page = orderDao.findAll(specification,pageable);
System.out.println("总记录数:" + page.getTotalElements());
System.out.println("总页数:"+page.getTotalPages());
System.out.println("当前第几页:"+ (page.getNumber()+1));
System.out.println("当前页的list:"+page.getContent());
System.out.println("当前页的记录数:"+page.getNumberOfElements());
}
## 5、自定义Repository 接口方法
步骤:
- 定义一个接口:声明要添加的,并自实现的方法。
- 提供该接口的实现类:类名需要在声明的Repository 后加Impl,并实现方法
- 声明Repository 接口,并继承刚才定义的接口
- 使用
后续。。。