###1.环境搭建
(项目基于SpringBoot,SpringBoot项目搭建参考其他文章)
###2.引入依赖
<!-- JPA -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- mysql连接的jar包 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- 数据库连接池 可选其他数据连接池 -->
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>${c3p0.version}</version>
</dependency>
###3.创建实体类
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import com.project.base.BaseBean;
/**
* 区域实体
* @Title: Area.java
* @Package com.template.modules.arealinkage
* @Description: TODO 省市联动区域,区域ID 1-2位代表省 3-4位代表市 5-6代表区县
* @author Autumn、
* @date 2018年7月7日
*/
@Entity
@Table(name = "t_template_area")
public class Area implements BaseBean{
//这里使用的是地区表,数据已经提前准备好,ID为String类型
/**
*
*/
private static final long serialVersionUID = 2282511279000179669L;
/**
* 区域ID
*/
@Id
private String id;
/**
* 区域名
*/
@Column
private String areaName;
/**
* 区域拼音
*/
@Column
private String areaCode;
/**
* 区域的父区域
*/
@Column
private String areaParentId;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getAreaName() {
return areaName;
}
public void setAreaName(String areaName) {
this.areaName = areaName;
}
public String getAreaCode() {
return areaCode;
}
public void setAreaCode(String areaCode) {
this.areaCode = areaCode;
}
public String getAreaParentId() {
return areaParentId;
}
public void setAreaParentId(String areaParentId) {
this.areaParentId = areaParentId;
}
public Area(String id, String areaName, String areaCode, String areaParentId) {
super();
this.id = id;
this.areaName = areaName;
this.areaCode = areaCode;
this.areaParentId = areaParentId;
}
public Area() {
super();
}
@Override
public String toString() {
return "Area [id=" + id + ", areaName=" + areaName + ", areaCode="
+ areaCode + ", areaParentId=" + areaParentId + "]";
}
}
###4.创建BaseRepository,方便创建接口时直接继承
import java.io.Serializable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.repository.NoRepositoryBean;
/**
* Spring-Data-JPA基础接口
*
* @Title: BaseRepository.java
* @Package com.template.base
* @Description: TODO Spring-Data-JPA基础接口,用于纵向扩展
* @author Autumn、
* @date 2018年7月30日
*/
@NoRepositoryBean
public interface BaseRepository<T extends BaseBean, ID extends Serializable>
extends JpaRepository<T, ID>, JpaSpecificationExecutor<T> {
/*
* JpaRepository 用于条件查询(主要是针对一张表中的数据进行查询)
* PagingAndSortingRepository 用于分页和排序功能的实现
*/
/*
* 按照Spring Data的规范的规定,查询方法以find | read | get开头(会自动翻译成select语句),涉及查询条件时,
* 条件的属性用条件关键字连接,要注意的是:条件属性以首字母大写。
*
* 自定义方法方法名关键字对照关系
* 逻辑操作 在定义方法时使用的关键词 sql where字句
* AND And and
* OR Or or
* AFTER After , IsAfter > ?
* BEFORE Before , IsBefore < ?
* CONTAINING Containing , IsContaining , Contains like '%?%'
* BETWEEN Between , IsBetween between ? and ?
* ENDING_WITH EndingWith , IsEndingWith , EndsWith like '%?'
* EXISTS Exists
* FALSE False , IsFalse aaa = false
* GREATER_THAN GreaterThan , IsGreaterThan > ?
* GREATER_THAN_EQUALS GreaterThanEqual , IsGreaterThanEqual > = ?
* IN In , IsIn in (?)
* IS Is , Equals , (or no keyword) = ?
* IS_EMPTY IsEmpty , Empty
* IS_NOT_EMPTY IsNotEmpty , NotEmpty
* IS_NOT_NULL NotNull , IsNotNull is not null
* IS_NULL Null , IsNull is null
* LESS_THAN LessThan , IsLessThan < ?
* LESS_THAN_EQUAL LessThanEqual , IsLessThanEqual < = ?
* LIKE Like , IsLike like
* NEAR Near , IsNear
* NOT Not , IsNot <> ?
* NOT_IN NotIn , IsNotIn not in (?)
* NOT_LIKE NotLike , IsNotLike not like ?
* REGEX Regex , MatchesRegex , Matches
* STARTING_WITH StartingWith , IsStartingWith , StartsWith
* TRUE True , IsTrue aaa = true
* WITHIN Within , IsWithin
*
* 如果需要分页功能的话,只需要在方法的最后一个参数加上Pageable就可以了,与findAll方法一样
*/
/*
* 参考文档:
* Spring Data Jpa方法命名规则 - https://blog.csdn.net/sbin456/article/details/53304148
* Spring Data JPA方法定义规范 - https://www.cnblogs.com/jaejaking/p/7994233.html
* Spring Jpa使用教程 - https://blog.csdn.net/KingBoyWorld/article/details/78935843
*/
}
###5.实验所需接口JapCourseRepository.java
import java.util.List;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.transaction.annotation.Transactional;
import com.project.base.BaseRepository;
import com.project.course.domain.Area;
/**
* Spring Data JPA接口
*
* @Title: JapCourseRepository.java
* @Package com.project.course.dao
* @Description: TODO
* @author Autumn、
* @date 2018年8月7日
*/
public interface JpaCourseRepository extends BaseRepository<Area, String> {
/**
* TODO 通过解析方法名创建查询 (根据方法名定义自动生成SQL语句)
* 开发中可参考BaseRepository中的注释根据需要拼接定义方法及其参数
* 参数类型与实体类类型保持一致
*/
/**
* 根据地区名称模糊查询地区并分页
*
* @param areaName 地区名称
* @param pageable 分页
* @return
*/
public Page<Area> findByAreaNameLike(String areaName, Pageable pageable);
/**
* 根据地区名称和区域拼音模糊查询并分页
*
* @param areaName 地区名称
* @param AreaCode 区域拼音
* @return
*/
public List<Area> findByAreaNameLikeAndAreaCodeLike(String areaName, String AreaCode);
/* 最终执行的SQL语句示例
select
area0_.id as id1_0_,
area0_.area_code as area_cod2_0_,
area0_.area_name as area_nam3_0_,
area0_.area_parent_id as area_par4_0_
from
t_template_area area0_
where
(
area0_.area_name like ?
)
and (
area0_.area_code like ?
)
*/
/**
* TODO 使用 @Query 创建查询,自定义SQL语句或者HQL语句
*/
/**
* 使用HQL语句,根据地区名称删除地区
* HQL语句和SQL语句另行参考,如果是修改和删除的方法则必须添加@Modifying注解,否则会报错,
* 由于是修改操作,所以需要添加事务@Transactional,否则无法删除成功
* @param areaName
* @return 受影响的行数
*/
@Modifying
@Transactional
@Query("delete from Area area where area.areaName = :areaName")//:areaName表示名字为areaName的参数
public Integer deleteAreaByAreaName(@Param("areaName") String areaName);
}
###6.JpaRepository使用案例
import java.util.ArrayList;
import java.util.List;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.Example;
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.junit4.SpringRunner;
import org.springframework.transaction.annotation.Transactional;
import com.project.course.dao.JpaCourseRepository;
import com.project.course.domain.Area;
import com.project.utils.GatherPrint;
/**
* SpringBoot环境下的单元测试
*
* @Title: JapCourseServiceTest.java
* @Package com.project.course.service
* @Description: TODO Spring Data Jpa 的一般使用(增删改查)
* @author Autumn、
* @date 2018年8月7日
*/
@RunWith(SpringRunner.class)
@SpringBootTest
public class JapCourseServiceTest {
@Autowired
private JpaCourseRepository jpaCourseRepository;
/**
* TODO Spring Data JPA 查询
*/
/**
* 根据Id查询单条记录
*/
@Test
@Transactional
public void fun1() {
//方法1
System.out.println(jpaCourseRepository.findOne("0003"));
//方法2
System.out.println(jpaCourseRepository.getOne("0004"));
}
/**
* 按例子查询单条记录,会忽略当中为空的值
* 参考文档:
* 使用Example快速实现动态查询 - https://blog.csdn.net/long476964/article/details/79677526
*/
@Test
public void fun2() {
Area area = new Area();
area.setAreaName("北京");
Example<Area> example = Example.of(area);
System.out.println(jpaCourseRepository.findOne(example));
}
/**
* 按规格查询单条记录,可以自定义添加条件
* 参考文档:
* SpringDataJpa的Specification查询 - https://blog.csdn.net/dragonpeng2008/article/details/52252907
*/
@Test
public void fun3() {
Specification<Area> spec = new Specification<Area>() {
@Override
public Predicate toPredicate(Root<Area> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
Predicate predicate = cb.conjunction();
// 添加条件
predicate.getExpressions().add(cb.equal(root.get("areaName"), "北京"));
return predicate;
}
};
System.out.println(jpaCourseRepository.findOne(spec));
}
/**
* 查询多条记录 - 无条件查询所有记录
*/
@Test
public void fun4() {
List<Area> areas = jpaCourseRepository.findAll();
GatherPrint.println(areas);
}
/**
* 根据多个ID查询多条记录
*/
@Test
public void fun5() {
List<String> ids = new ArrayList<String>();
ids.add("110000");
ids.add("110101");
ids.add("110105");
List<Area> areas = jpaCourseRepository.findAll(ids);
GatherPrint.println(areas);
}
/**
* 按例子查询多条记录,会忽略当中为空的值
* 参考文档:
* 使用Example快速实现动态查询 - https://blog.csdn.net/long476964/article/details/79677526
*/
@Test
public void fun6() {
Area area = new Area();
area.setAreaParentId("110100");
Example<Area> example = Example.of(area);
List<Area> areas = jpaCourseRepository.findAll(example);
GatherPrint.println(areas);
}
/**
* 按规格查询多条记录,可以自定义添加条件
* 参考文档:
* SpringDataJpa的Specification查询 - https://blog.csdn.net/dragonpeng2008/article/details/52252907
*/
@Test
public void fun7() {
Specification<Area> spec = new Specification<Area>() {
@Override
public Predicate toPredicate(Root<Area> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
Predicate predicate = cb.conjunction();
// 添加条件(这里使用like模糊查询,%为mysql的占位符,匹配任意个任意字符)
predicate.getExpressions().add(cb.like(root.get("areaName"), "%北京%"));
return predicate;
}
};
List<Area> areas = jpaCourseRepository.findAll(spec);
GatherPrint.println(areas);
}
/**
* 查询多条记录并分页
*/
@Test
public void fun8() {
Pageable pageable = new PageRequest(0, 10);
Page<Area> page = jpaCourseRepository.findAll(pageable);
System.out.println("总记录数:" + page.getTotalElements());
System.out.println("当前第几页:" + page.getNumber());
System.out.println("总页数:" + page.getTotalPages());
System.out.println("当前页面的List:" + page.getContent());
System.out.println("当前页面的记录数:" + page.getNumberOfElements());
}
/**
* 查询多条数据,对查询结果进行降序或者升序排序
*/
@Test
public void fun9() {
// DESC降序
// ASC升序
Sort sort = new Sort(Sort.Direction.ASC, "id");
List<Area> areas = jpaCourseRepository.findAll(sort);
// List<Area> areas = japCourseRepository.findAll(spec, sort);//按规格查询多条记录并排序
// List<Area> areas = japCourseRepository.findAll(example, sort);//按例子查询多条记录并排序
GatherPrint.println(areas);
}
/**
* 按规格分页查询并排序
*/
@Test
public void fun10(){
Specification<Area> spec = new Specification<Area>() {
@Override
public Predicate toPredicate(Root<Area> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
Predicate predicate = cb.conjunction();
// 添加条件(这里使用like模糊查询,%为mysql的占位符,匹配任意个任意字符)
predicate.getExpressions().add(cb.like(root.get("areaName"), "%市%"));
return predicate;
}
};
Sort sort = new Sort(Sort.Direction.ASC, "id");
Pageable pageable = new PageRequest(0, 10, sort);
Page<Area> page = jpaCourseRepository.findAll(spec, pageable);
System.out.println("总记录数:" + page.getTotalElements());
System.out.println("当前第几页:" + page.getNumber());
System.out.println("总页数:" + page.getTotalPages());
System.out.println("当前页面的List:" + page.getContent());
System.out.println("当前页面的记录数:" + page.getNumberOfElements());
}
/**
* 小结:
* Example<Area> 示例,用于简单条件查询,即等于
* Specification<Area> 用于配置规格,即复杂查询条件(除了等于以外的条件)
* Sort 进行排序
* Pageable 用于分页
* 三者可以自由组合搭配使用
*/
/**
* TODO Spring Data JPA 修改和保存
*/
/**
* 新增一条记录
*/
@Test
public void fun11(){
//新增记录,如果ID不是自动增长的需要手动设置好ID
Area area = new Area("0001", "添加测试1", "0002", "0");
jpaCourseRepository.save(area);
}
/**
* 新增一条记录并刷新到数据库中
*/
@Test
public void fun12(){
//新增记录,如果ID不是自动增长的需要手动设置好ID
Area area = new Area("0002", "添加测试2", "0002", "0");
jpaCourseRepository.saveAndFlush(area);
}
/**
* 新增多条记录
*/
@Test
public void fun13(){
List<Area> areas = new ArrayList<Area>();
areas.add(new Area("0003", "添加测试3", "0003", "0"));
areas.add(new Area("0004", "添加测试4", "0004", "0"));
jpaCourseRepository.save(areas);
}
/*第七封情书 - 佰秋离*/
/**
* TODO 修改记录
* 修改记录即为查询与保存的结合,先从数据库查询出来记录,此时得到的记录为持久态记录,如果对持久态的记录实体进行属性的更改
* 则在sqlsession关闭的时候修改会被写入数据库,所以如果不对数据进行更改的情况下不要对持久态的数据做任何修改
*/
/**
* 修改一条记录(修改多条记录与此类似,save方法中传List集合即可)
*/
@Test
public void fun14(){
Area area = jpaCourseRepository.findOne("0003");
area.setAreaName("修改测试");
jpaCourseRepository.save(area);//这里的保存和新增是一样的操作,但是修改的最好是从数据库中查询出来的(如果没有先查询数据库可能会报错)
jpaCourseRepository.flush();//此句为立即刷新,将修改立即写入数据库,可以不写这句,在session关闭的时候会写入数据库
}
/**
* TODO 删除记录
*/
/**
* 根据持久态实体删除单条记录
*/
@Test
public void fun15(){
Area area = jpaCourseRepository.findOne("0003");
jpaCourseRepository.delete(area);
}
/**
* 根据Id删除单条记录
*/
@Test
public void fun16(){
jpaCourseRepository.delete("0003");
}
/**
* 删除多条记录
*/
@Test
public void fun17(){
List<Area> areas = null;//这里是从数据库查询出来的持久态记录的集合,和seve方法类型,这里不做演示
jpaCourseRepository.delete(areas);
//japCourseRepository.deleteInBatch(areas);//此方法为删除一批
}
/**
* 删除所有(慎用)
*/
@Test
public void fun18(){
jpaCourseRepository.deleteAll();
}
/**
* TODO 统计数量
*/
@Test
public void fun19(){
System.out.println("当前表中记录数:" + jpaCourseRepository.count());//统计所有数量
// System.out.println("满足示例的记录数:" + japCourseRepository.count(example));//example与查询的使用方法一致
// System.out.println("满足规格的记录数:" + japCourseRepository.count(spec));//spec与查询是使用方法一致
}
/**
* TODO 判断是否存在
*/
@Test
public void fun20(){
System.out.println(jpaCourseRepository.exists("0002"));//查询Id0003是否存在
// System.out.println(japCourseRepository.exists(example));//查询example示例是否存在
}
/**
* TODO 自定义方法
*/
/**
* 根据地区名称模糊查询地区并分页
*/
@Test
public void fun21(){
Pageable pageable = new PageRequest(0, 100);
Page<Area> page = jpaCourseRepository.findByAreaNameLike("%州%", pageable);
GatherPrint.println(page.getContent());
}
/**
* 根据地区名称和区域拼音模糊查询并分页
*/
@Test
public void fun22(){
List<Area> areas = jpaCourseRepository.findByAreaNameLikeAndAreaCodeLike("%州%", "%");
//%匹配任意个任意字符,_匹配1个任意字符
GatherPrint.println(areas);
}
/**
* 使用HQL语句,根据地区名称删除地区
*/
@Test
public void fun23(){
System.out.println(jpaCourseRepository.deleteAreaByAreaName("添加测试2"));
}
/**
* @return the japCourseRepository
*/
public JpaCourseRepository getJapCourseRepository() {
return jpaCourseRepository;
}
/**
* @param japCourseRepository
* the japCourseRepository to set
*/
public void setJapCourseRepository(JpaCourseRepository japCourseRepository) {
this.jpaCourseRepository = japCourseRepository;
}
}