一.关于Respository接口
- Repository接口是Spring Data的核心接口,不提供任何方法
- Repository接口是一个空接口(标记接口)-没有包含任何方法声明的接口
- 如果我们定义的接口extends Repository,自动会被Spring管理
- 比如我们上一章讲得EmployeeRepository接口,就是 extends Repository,我们先来打印一下
public class EmployeeRepositoryTest {
private ApplicationContext applicationContext = null;
private EmployeeRepository employeeRepository = null;
@Before
public void init(){
applicationContext = new AnnotationConfigApplicationContext(SpringConfigNew.class);
employeeRepository = applicationContext.getBean(EmployeeRepository.class);
System.out.println("init...");
}
@After
public void destroy(){
applicationContext=null;
System.out.println("destroy...");
}
@Test
public void findByNametest(){
System.out.println(employeeRepository);
Employee employee = employeeRepository.findByName("test1");
System.out.println(employee);
}
}
- 如果我们自己的接口没有extends Repository,运行时会报错,找不到这个Bean。
- 没有继承这个接口,就不会被spring管理
- 可以用RepositoryDefinition注解来实现同样的功能
- 这个接口有两个属性,同样也是类和主键的类型
@RepositoryDefinition(domainClass = Employee.class,idClass = Integer.class)
interface EmployeeRepository /*extends Repository<Employee, Integer>*/ {//类名 + 主键类型
//获取雇员对象通过名称
Employee findByName(String name);
}
- 再打印这个接口同样也没问题的
二.Repository子接口
- 结构
- CrudRepository:继承Repository,实现了CRUD相关的方法
- PagingAndSortingRepository:继承CrudRepository,实现了分页排序相关的方法
- JpaRepository:继承PagingAndSortingRepositor,实现JPA规范相关的方法
三.查询方法定义规则和使用
- 了解Spring Data中查询方法名称的定义规则
- 使用Spring Data完成复杂查询方法名称的命名
- 规则视图如下
@RepositoryDefinition(domainClass = Employee.class,idClass = Integer.class)
interface EmployeeRepository /*extends Repository<Employee, Integer>*/ {//类名 + 主键类型
//获取雇员对象通过名称
Employee findByName(String name);
//where name like ?% and age < ?
List<Employee> findByNameStartingWithAndAgeLessThan(String name,Integer age);
//where name like %? and age < ?
List<Employee> findByNameEndingWithAndAgeLessThan(String name,Integer age);
//where name in () or age < ?
List<Employee> findByNameInOrAgeLessThan(List<String> name,Integer age);
//where name in () and age < ?
List<Employee> findByNameInAndAgeLessThan(List<String> name,Integer age);
}
- 测试类
public class EmployeeRepositoryTest {
private ApplicationContext applicationContext = null;
private EmployeeRepository employeeRepository = null;
@Before
public void init(){
applicationContext = new AnnotationConfigApplicationContext(SpringConfigNew.class);
employeeRepository = applicationContext.getBean(EmployeeRepository.class);
System.out.println("init...");
}
@After
public void destroy(){
applicationContext=null;
System.out.println("destroy...");
}
@Test
public void findByNametest(){
System.out.println(employeeRepository);
Employee employee = employeeRepository.findByName("test1");
System.out.println(employee);
}
@Test
public void findByNameStartingWithAndAgeLessThantest(){
List<Employee> employees = employeeRepository.findByNameStartingWithAndAgeLessThan("test",22);
for(Employee employee:employees){
System.out.println(employee);
}
}
@Test
public void findByNameEndingWithAndAgeLessThantest(){
List<Employee> employees = employeeRepository.findByNameEndingWithAndAgeLessThan("6",23);
for(Employee employee:employees){
System.out.println(employee);
}
}
@Test
public void findByNameInOrAgeLessThantest(){
List<String> name = new ArrayList<>();
name.add("test1");
name.add("test2");
name.add("test3");
List<Employee> employees = employeeRepository.findByNameInOrAgeLessThan(name,23);
for(Employee employee:employees){
System.out.println(employee);
}
}
@Test
public void findByNameInAndOrAgeLessThantest(){
List<String> name = new ArrayList<>();
name.add("test1");
name.add("test2");
name.add("test3");
List<Employee> employees = employeeRepository.findByNameInAndAgeLessThan(name,23);
for(Employee employee:employees){
System.out.println(employee);
}
}
}
- 对于按照方法命名规则来使用的话,有弊端:
- 方法名比较长:约定大于配置
- 对于一些复杂的查询,是很难实现
- 这些问题可以使用@Query注解来解决
四.Query注解使用
-
在Respository方法中使用,不需要遵循查询方法命令规则
-
只需要将@Query定义在Respository中的方法之上即可
-
命名参数及索引参数的使用
-
本地查询
-
EmployeeRepository接口
//Query注解
@Query("select o from Employee o where id = (select max(id) from Employee t1)")//注意这里是根据类来查 不是表
Employee getEmployeeByMaxId();
/*
使用占位符进行参数绑定
*/
@Query("select o from Employee o where o.name = ?1 and o.age = ?2")
List<Employee> listEmployeeByNameAndAge(String name,Integer age);
/*
使用命名参数进行参数绑定
*/
@Query("select o from Employee o where o.name = :name and o.age = :age")
List<Employee> listEmployeeByNameAndAge2(@Param("name")String name,@Param("age")Integer age);
/*
自定义查询SQL,like,占位符进行参数绑定
*/
@Query("select o from Employee o where o.name like %?1%")
List<Employee> listEmployeeByLikeName(String name);
/*
自定义查询SQL,like,占位符进行参数绑定
*/
@Query("select o from Employee o where o.name like %:name%")
List<Employee> listEmployeeByLikeName2(@Param("name") String name);
/*
使用原生态SQL查询
*/
@Query(nativeQuery = true,value="select count(1) from employee")//这才是表查询 默认支持原生态为false 改成true
long getCount();
- 测试类
@Test
public void getEmployeeByMaxIdtest(){
Employee employee = employeeRepository.getEmployeeByMaxId();
System.out.println(employee);
}
@Test
public void listEmployeeByNameAndAgetest(){
List<Employee> employees = employeeRepository.listEmployeeByNameAndAge("test6",22);
for(Employee employee:employees){
System.out.println(employee);
}
}
@Test
public void listEmployeeByNameAndAge2test(){
List<Employee> employees = employeeRepository.listEmployeeByNameAndAge2("test6",22);
for(Employee employee:employees){
System.out.println(employee);
}
}
@Test
public void listEmployeeByLikeNametest(){
List<Employee> employees = employeeRepository.listEmployeeByLikeName("test");
for(Employee employee:employees){
System.out.println(employee);
}
}
@Test
public void listEmployeeByLikeName2test(){
List<Employee> employees = employeeRepository.listEmployeeByLikeName2("6");
for(Employee employee:employees){
System.out.println(employee);
}
}
@Test
public void getCounttest(){
System.out.println(employeeRepository.getCount());
}
五.更新操作整合事务使用
- 更新及删除操作整合事务的使用
@Modifying注解使用
@Modifying结合@Query注解执行更新操作
@Transaction在Spring Data中的使用
- 事务在Spring data中的使用
@Modifying
@Query("update Employee o set o.age=:age where o.id=:id ")
void update(@Param("id")Integer id,@Param("age")Integer age);
- 事务一般是在Service层(因为一个service层 可能存在多个DAO层的调用 必须要保证多个DAO都保存在一个事务里面)
- 实际开发中,需要定义接口
@Service
public class EmployeeService {
@Autowired
private EmployeeRepository employeeRepository;
@Transactional
public void update(Integer id,Integer age){
employeeRepository.update(id,age);
}
}
- 测试类
public class EmployeeServiceTest {
private ApplicationContext ctx = null;
private EmployeeService employeeService = null;
@Before
public void init(){
ctx = new AnnotationConfigApplicationContext(SpringConfigNew.class);
employeeService = ctx.getBean(EmployeeService.class);
System.out.println("init...");
}
@After
public void destroy(){
ctx=null;
System.out.println("destroy...");
}
@Test
public void update(){
employeeService.update(1,50);
}
}