spring data jpa入门

简述:

Spring Data是Spring的一个子项目, 用于访问数据库

其主要目标是使得数据库的访问变得方便快捷

Spring Data中已经提供了常用的一些接口实现类, 比如分页、排序、DAO一些常用的操作

从而我们可利用spring data快速构建项目

导入spring data的jar包:

中心仓库去下载

<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-jpa -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
    <version>2.0.2.RELEASE</version>
</dependency>

根据不同DB还导一个数据库驱动

<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
    <groupId>mysql</groupId>
	<artifactId>mysql-connector-java</artifactId>
	<version>5.1.14</version>
</dependency>

核心接口:

Repository接口是spring data提供的核心接口, 它是一个空接口(标记接口)

package org.springframework.data.repository;

import java.io.Serializable;

public interface Repository<T, ID extends Serializable> {

}

基础的 Repository 只提供了最基本的数据访问功能,  其子接口扩展了其功能

Repository: 顶级接口, 仅仅是一个标识,表示任何继承它的接口都是仓库接口类

CrudRepository: 继承 Repository,实现了一组 CRUD(增删改查) 相关的方法 

PagingAndSortingRepository: 继承 CrudRepository,实现了一组 分页排序 相关的方法 

JpaRepository: 继承 PagingAndSortingRepository,实现一组  JPA 规范 相关的方法

Repository在commons包中, JpaRepostory在data包r中 , 如下

默认存在的一些方法: 

我们定义一个接口MyRespository, 继承了JpaRespository, 则可以直接使用如下的方法

repository为MyRespository的对象

repository.findAll();
repository.findOne(xxx);
repository.save();
repository.delete(xxx);
repository.count();
repository.exists();
...
    // 查询所有对象
	@RequestMapping("/findAll")
	public void findAll() {
		List<Movie> movies = dao.findAll();
		for (Movie movie : movies) {
			System.out.println(movie.getDesc());
		}
	}
	// 查询某个对象
	@RequestMapping("/findOne/{id}")
	public void findOne(@PathVariable String id) {
		int parseId = Integer.parseInt(id);
		Movie movie = dao.findOne(parseId);
		if (movie == null) {
			return;
		}
		System.out.println(movie.getDesc());
	}
	// 删除对象
	@RequestMapping("/delete/{id}")
	public void delete(@PathVariable String id) {
		int parseId = Integer.parseInt(id);
		boolean flag = false;
		try {
			dao.delete(parseId);
			flag = true;
		} catch (Exception e) {}
		
		if (flag == true) {
			System.out.println("删除成功");
		} else {
			System.out.println("删除失败");
		}
	}
	// count
	@RequestMapping("/count")
	public void count() {
		System.out.println(dao.count());
	}
	// exists
	@RequestMapping("/exists/{id}")
	public void exists(@PathVariable String id) {
		int parseId = Integer.parseInt(id);
		System.out.println(dao.exists(parseId));
	}
	// save    
	@RequestMapping("/save")             //注意数据表不可使用关键字, 否则会提示sql错误
	public void save(String name, String img_url, String year, String artist, String desc) {
		Movie entity = new Movie();
		entity.setName(name);
		entity.setImgUrl(img_url);
		entity.setYear(year);
		entity.setArtist(artist);
		entity.setDesc(desc);
		entity.setId(11);
		try {
			dao.save(entity);
			dao.flush();
			System.out.println("写入成功");
		} catch (Exception e) {
			System.out.println("写入失败");
		}
	}

方法定义规范:

 符合规范的方法,可以不用写实现

设计查询方法以find 或 read 或 get开头

设计 条件查询 时,条件用属性名连接, 例如如下查询

先继承JpaRepository, 再写自己的方法(比如这里的 findById, 也可以改为 getById / readById)

我并没有写 这个MovieDao接口的实现, 但是在Controllrt中就可以使用(因为我遵循了JPA规范, 所以不用写实现)

spring关键字查询

就是表明查询的逻辑, 比如getByNameAndYear  (根据电影名称和年份查询)

这个and就是关键字

添加如下的一个方法

同样没有实现, 在Controller中也可直接使用

接口中我写的JPA规范方法(全部有效)

public interface MovieDao extends JpaRepository<Movie, Integer> {
	// 根据电影的id查询, findById -- 属性名为id
	public Movie getById(Integer id);
	
	// 根据电影名称和电影描述查询
	public Movie getByNameAndYear(String name, String year);
	
	// Or, 这可能查询出多个结果, 所以需要用集合保存结果
	public List<Movie> findByNameOrYear(String name, String year);
	
	// Between, 从第一个参数到第二个参数之间
	public List<Movie> findByYearBetween(String start, String end);
	
	// LessThan, 小于
	public List<Movie> findByYearLessThan(String data);	
	
	// GreaterThan, 大于
	public List<Movie> readByYearGreaterThan(String data);
	
	// After, 字段中大于data的记录(测试时效果与GreaterThan相同, 不知道有什么区别)
	public List<Movie> readByYearAfter(String data);
	
	// Before, 字段中小于data的记录(同上)
	public List<Movie> readByYearBefore(String data);
	
	// IsNull, 说明null表示没有值, 它并不是空值, 空值是: "" (空字符串), 查询时需要注意它们的区别
	public List<Movie> getByYearIsNull();
	
	// IsNotNull
	public List<Movie> getByYearIsNotNull();
	
	// like(模糊查询 like为表达式, 具体由Cotroller中拼接)
	public List<Movie> findByDescLike(String like);
	
	// In, in表示从列表中查询, 参数可以是数组和集合
	public List<Movie> findByYearIn(String[] s);
	
	// 按Desc模糊查询再按Year降序排列                    /*这个是比较综合的查询*/
	public List<Movie> findTop3ByDescLikeOrderByYearDesc(String like);
}

Controller中我对接口的测试 (只看方法名称就知道代表的意思)

@RestController
public class MovieController {	
	@Autowired
	private MovieDao dao;
	@RequestMapping("/getMovieById/{id}")
	public void getMovieById(@PathVariable String id) {
		int parseId = 0;
		try {
			parseId = Integer.parseInt(id);
		} catch (NumberFormatException e) {
			System.err.println("请输入非零正数");
			return;
		}
		/*如果传入的参数正确才查询DB*/
		if (parseId > 0) {
			Movie movie = dao.getById(parseId);
			if (movie != null) {
				System.out.println(movie.getName());
			} else {
				System.out.println("您查询的内容不存在");
			}
			return;
		}
		System.out.println("请输入非零正数");
	}
	@RequestMapping("/findMovieByNameAndYear")
	public String getByNameAndYear(String name, String year) {
		if (year == null || name == null) {
			System.out.println("请输入名称和年份");
			return null;
		}
		Movie movie = dao.getByNameAndYear(name, year);
		
		if (movie != null) {
			System.out.println(movie.getDesc());
		}
		return null;
	}
	@RequestMapping("/findMovieOrNameAndYear")
	public void getByNameOrYear(String name, String year) {
		
		List<Movie> movies = dao.findByNameOrYear(name, year);
		
		for (Movie movie : movies) {
			System.out.println(movie.getDesc());
		}
	}
	@RequestMapping("/findByYearBetween")
	// between
	public void findByYearBetween(String start , String end) {
		if (start == null || end == null) {
			return;
		}
		List<Movie> movies = dao.findByYearBetween(start, end);
		for (Movie movie : movies) {
			System.out.println(movie.getDesc());
		}
	}
	@RequestMapping("/findByYearLessThan")
	public void findByYearLessThan(String data) {
		if (data == null) {
			return;
		}
		List<Movie> movies = dao.findByYearLessThan(data);
		for (Movie movie : movies) {
			System.out.println(movie.getDesc());
		}
	}
	@RequestMapping("/readByYearGreaterThan")
	public void readByYearGreaterThan(String data) {
		if (data == null) {
			return;
		}
		List<Movie> movies = dao.readByYearGreaterThan(data);
		for (Movie movie : movies) {
			System.out.println(movie.getDesc());
		}
	}	
	@RequestMapping("/readByYearAfter")
	// After
	public void readByYearAfter(String data) {
		if (data == null) {
			return;
		}
		List<Movie> movies = dao.readByYearAfter(data);
		for (Movie movie : movies) {
			System.out.println(movie.getDesc());
		}
	}	
	@RequestMapping("/getByYearIsNull")
	public void getByYearIsNull() {
		List<Movie> movies = dao.getByYearIsNull();
		for (Movie movie : movies) {
			System.out.println(movie.getDesc());
		}
	}	
	@RequestMapping("/getByYearIsNotNull")
	public void getByYearIsNotNull() {
		List<Movie> movies = dao.getByYearIsNotNull();
		for (Movie movie : movies) {
			System.out.println(movie.getDesc());
		}
	}	
	@RequestMapping("/findByDescLike")
	public void findByDesc(String data) {
		String like = "%" + data + "%";
		List<Movie> movies = dao.findByDescLike(like);
		System.out.println(movies.size());
	}	
	// 模糊查询排序(JPA规范看: 按Desc查询, 按Year排序)
	@RequestMapping("/findTop3ByDescLikeOrderByYearDesc")
	public void findTop3ByDescLikeOrderByYearDesc(String data) {
		String like = "%" + data + "%";
		List<Movie> movies = dao.findTop3ByDescLikeOrderByYearDesc(like);
		
		for (Movie movie : movies) {
			System.out.println(movie.getYear() + ": " + movie.getName());
		}
	}	
	@RequestMapping("/findByYearIn")
	public void findByYearIn(String a) {
		String[] arr = null;
		if(a != null) {
			arr = a.split(",");
		}		
		if(arr == null) return;
		List<Movie> movies = dao.findByYearIn(arr);
		for (Movie movie : movies) {
			System.out.println(movie.getName());
		}
	}	
	// 查询所有对象
	@RequestMapping("/findAll")
	public void findAll() {
		List<Movie> movies = dao.findAll();
		for (Movie movie : movies) {
			System.out.println(movie.getDesc());
		}
	}	
	// 查询某个对象
	@RequestMapping("/findOne/{id}")
	public void findOne(@PathVariable String id) {
		int parseId = Integer.parseInt(id);
		Movie movie = dao.findOne(parseId);
		if (movie == null) {
			return;
		}
		System.out.println(movie.getDesc());
	}	
	// 删除对象
	@RequestMapping("/delete/{id}")
	public void delete(@PathVariable String id) {
		int parseId = Integer.parseInt(id);
		boolean flag = false;
		try {
			dao.delete(parseId);
			flag = true;
		} catch (Exception e) {}
		
		if (flag == true) {
			System.out.println("删除成功");
		} else {
			System.out.println("删除失败");
		}
	}	
	// count
	@RequestMapping("/count")
	public void count() {
		System.out.println(dao.count());
	}
	// exists
	@RequestMapping("/exists/{id}")
	public void exists(@PathVariable String id) {
		int parseId = Integer.parseInt(id);
		System.out.println(dao.exists(parseId));
	}	
	// save
	@RequestMapping("/save")
	public void save(String name, String img_url, String year, String artist, String desc) {
		Movie entity = new Movie();
		entity.setName(name);
		entity.setImgUrl(img_url);
		entity.setYear(year);
		entity.setArtist(artist);
		entity.setDesc(desc);		
		try {
			dao.save(entity);
			System.out.println("写入成功");
		} catch (Exception e) {
			System.out.println("写入失败");
			e.printStackTrace();
		}		
	}
}

Example查询

count(), findAll(),exists()的参数都可以使用Example对象(来实现模糊查询)

1.先创建Example

2.再创建ExampleMatcher对象

3.使用count, findAll. exists方法

@RequestMapping("/exampleSelect")
public void exampleCount(String name, String year) {
	// 创建对象
	Movie movie = new Movie();
	movie.setName(name);
	movie.setYear(year);
		
	//创建匹配器
	ExampleMatcher matcher = ExampleMatcher.matching()
	// name, year代表数据表中的字段名(但以实体类中的字段名为准)
	.withMatcher("name", GenericPropertyMatchers.contains())	// 包含
	.withMatcher("year", GenericPropertyMatchers.endsWith())	// 以结尾
	//.withMatcher("实体字段名", 匹配条件);		// 还可以继续加匹配
        // 要忽略id(不清楚原因)
	.withIgnorePaths("id");
        
    //创建实例, 用这个实例movie去匹配数据表中的每条记录 (这个实例对象就相当于一条数据表记录)
    Example<Movie> ex = Example.of(movie, matcher); 
    long mo = dao.count(ex);
    System.out.println(mo);
}

JPQL查询

类似HQL语法在方法上使用@Query注解

@Query(value="select * from movie where id = ?1", nativeQuery = true) 
public Movie findDefinedId(int id);

 上面在Query注解中加上了nativeQuery = true, 则这就是原生sql查询

如下的字段名id, movie_name只能是原数据表中的字段名, 不能改为实体类中的属性名

查询单个字段, 返回简单类型

@Query(value="select id, movie_name from movie where id = ?1", nativeQuery = true) 
public String findDefinedId(int id); 

查询多个字段, 返回数组类型 

//原生sql查询
@Query(value="select movie_name, id, artist from movie where id = ?1", nativeQuery = true) 
public String[] findDefinedId(int id);

查询全部字段可以返回对象 

HQL查询也是使用Query注解, 但是不加nativeQuery=true

// HQL查询, 如果查询的是单个字段, 就返回简单类型
// HQL查询, 如果查询的是多个字体, 则返回的是数组
@Query(value="select id, name from Movie where id = ?1") 
public String[] findDefinedHqlId(Long id); 	
	
// HQL查询, 查询多个字段, 但是想要返回对象, 则应该这样写, 但是要保证实体中有引构造器
@Query(value="select new Movie(id, name) from Movie where id = ?1") 
public List<Movie>  findDefinedHqlIdToObject(Long id); 

使用HQL查询, 要当作类来使用, 比如这里的Movie必是类, 而不是表名(所以大写)

这里的id, name也是属性名, 而不是表中的字段名

还有这里的参数Long id, 不可使用int型, 因为我的id在实体类中就是定义的long型, 而不是int型

这些千万要注意区别, 否则会出现类型不能转换的异常

 

多表关联查询, 对于业务复杂的HQL性能很差, 而使用原生sql查询, 效率更佳

但是解析查询的结果比较麻烦一点

接口: 

// 多表原生联查,  返回的必须是List<Object>类型
@Query(nativeQuery=true, value="select S.stitle, S.description, M.movie_name, M.year from movie M join section S on S.sid = M.id where M.year > 1997 order by M.year")
public List<Object> unionTable();

控制层: 

@RequestMapping("/unionTable")
public void unionTable() {
	// 这个集合中的Object对象 本质是对象数组
	List<Object> objs = dao.unionTable();
	for (Object obj : objs) {
		// 因为拿到的对象本质是对象数组, 所以可强制转换为对象数组类型
		Object[] str = (Object[])obj;
		
		// 通过数组的下标, 将数组中的数据放入vo对象中
		MovieSection ms = new MovieSection();
		ms.setTitle((String)str[0]);
		ms.setDescription((String)str[1]);
		ms.setMovie_name((String)str[2]);
		ms.setYear((String)str[3]);
		// 还可以将这些对象放入List中, 再用@ResponseBody返回
	}
}

List<Object>的真实结构如下: (外层一个集合, 中间三个对象数组, 最里面就是单个的String对象)

[  ['a', 'b','c'],  ['1', '2', '3'],  ['盗梦空间', '排行9', '2001年' ]  ]

另外还有参数点位符等, spring data 的大致内容就是这些

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值