四、SpringData JPA 进阶
Responsitory类的定义
public interface Repository<T,ID extends Serializable>{ }
1)Responsitory是一个空接口,标记接口
没有包含方法的声明接口
2)我们定义的接口
public interface EmployeeRepository extends Repository<Employee, Integer>{ }
表示此接口纳入spring管理,需按一定规则定义方法
或者使用注解方式定义
@RepositoryDefinition(domainClass = Employee.class, idClass = Integer.class)
public interface EmployeeRepository {
}
Repository继承体系
CrudRepository # 实现了CRUD相关方法
- PagingAndSortingRepository # 实现了分页排序方法
- JpaRepository # 实现了Jpa规范相关方法
JpaSpecificationExecutor
Repository查询方法定义规则和使用
package com.mouday.repository; import com.mouday.domain.Employee; import org.springframework.data.repository.RepositoryDefinition; import java.util.List; @RepositoryDefinition(domainClass = Employee.class, idClass = Integer.class) public interface EmployeeRepository { // where name = ? public Employee findByName(String name); // where name like ?% and age > ? List<Employee> findByNameStartingWithAndAgeGreaterThan(String name, Integer age); // where name like %? and age > ? List<Employee> findByNameEndingWithAndAgeGreaterThan(String name, Integer age); }
测试
package com.mouday.repository; import com.mouday.domain.Employee; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import java.util.List; public class EmployeeRepositoryTest { ApplicationContext context = null; EmployeeRepository repository = null; @Before public void setup() { System.out.println("StudentDaoSpringJdbcImplTest.setup"); context = new ClassPathXmlApplicationContext("beans-jpa.xml"); repository = context.getBean(EmployeeRepository.class); } @After public void tearDown() { System.out.println("StudentDaoSpringJdbcImplTest.tearDown"); context = null; } @Test public void testFindByName() { Employee employee = repository.findByName("刘备"); System.out.println(employee); } @Test public void testFindByNameStartingWithAndAgeGreaterThan() { List<Employee> employees = repository.findByNameStartingWithAndAgeGreaterThan("刘", 10); System.out.println(employees); } @Test public void testFindByNameEndingWithAndAgeGreaterThan() { List<Employee> employees = repository.findByNameEndingWithAndAgeGreaterThan("羽", 10); System.out.println(employees); } }
命名规则的弊端
- 方法名比较长
- 复杂查询很难实现
Query查询注解
1、在Respository方法中使用,不需要遵循查询方法命名规则
2、只需要将@Query定义在Respository中的方法之上即可
3、命名参数及索引参数的使用
4、本地查询
package com.mouday.repository; import com.mouday.domain.Employee; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.RepositoryDefinition; import org.springframework.data.repository.query.Param; import java.util.List; @RepositoryDefinition(domainClass = Employee.class, idClass = Integer.class) public interface EmployeeRepository { // where name = ? public Employee findByName(String name); // where name like ?% and age > ? List<Employee> findByNameStartingWithAndAgeGreaterThan(String name, Integer age); // where name like %? and age > ? List<Employee> findByNameEndingWithAndAgeGreaterThan(String name, Integer age); // where name in (?...) and age > ? List<Employee> findByNameInAndAgeGreaterThan(List<String> names, Integer age); @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") Employee getEmployeeByName1(String name, Integer age); @Query("select o from Employee o where o.name = :name and o.age = :age") Employee getEmployeeByName2(@Param("name") String name, @Param("age") Integer age); @Query("select o from Employee o where o.name like %?1%") Employee getEmployeeByNameLike1(String name); @Query("select o from Employee o where o.name like %:name%") Employee getEmployeeByNameLike2(@Param("name") String name); // 开启原生查询 @Query(nativeQuery=true, value = "select count(*) from employee") Integer getEmployeeCount(); }
测试
package com.mouday.repository; import com.mouday.domain.Employee; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import java.util.ArrayList; import java.util.List; public class EmployeeRepositoryTest { ApplicationContext context = null; EmployeeRepository repository = null; @Before public void setup() { System.out.println("StudentDaoSpringJdbcImplTest.setup"); context = new ClassPathXmlApplicationContext("beans-jpa.xml"); repository = context.getBean(EmployeeRepository.class); } @After public void tearDown() { System.out.println("StudentDaoSpringJdbcImplTest.tearDown"); context = null; } @Test public void testFindByName() { Employee employee = repository.findByName("刘备"); System.out.println(employee); } @Test public void testFindByNameStartingWithAndAgeGreaterThan() { List<Employee> employees = repository.findByNameStartingWithAndAgeGreaterThan("刘", 10); System.out.println(employees); } @Test public void testFindByNameEndingWithAndAgeGreaterThan() { List<Employee> employees = repository.findByNameEndingWithAndAgeGreaterThan("羽", 10); System.out.println(employees); } @Test public void testFindByNameInAndAgeGreaterThan() { List<String> names = new ArrayList<>(); names.add("刘备"); names.add("张飞"); List<Employee> employees = repository.findByNameInAndAgeGreaterThan(names, 10); System.out.println(employees); } @Test public void testGetEmployeeByMaxId() { Employee employee = repository.getEmployeeByMaxId(); System.out.println(employee); } @Test public void testGetEmployeeByName1() { Employee employee = repository.getEmployeeByName1("刘备", 40); System.out.println(employee); } @Test public void testGetEmployeeByName2() { Employee employee = repository.getEmployeeByName2("刘备", 40); System.out.println(employee); } @Test public void testGetEmployeeByNameLike1() { Employee employee = repository.getEmployeeByNameLike1("刘"); System.out.println(employee); } @Test public void testGetEmployeeByNameLike2() { Employee employee = repository.getEmployeeByNameLike2("刘"); System.out.println(employee); } @Test public void testGetEmployeeCount() { Integer total = repository.getEmployeeCount(); System.out.println(total); } }
事务在 Spring Data 中的应用:
- 事务一般是在 service 层,保证事务的完整性
2)注解的使用
@Query 查询
@Modifying 修改 更新和删除必用
@Transactional 事务 更新和删除必用
package com.mouday.repository; import com.mouday.domain.Employee; import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.RepositoryDefinition; import org.springframework.data.repository.query.Param; import java.util.List; @RepositoryDefinition(domainClass = Employee.class, idClass = Integer.class) public interface EmployeeRepository { // 修改操作 @Modifying @Query("update Employee o set o.name = :name where id = :id") void updateNameById(@Param("id") Integer id, @Param("name") String name); } package com.mouday.service; import com.mouday.repository.EmployeeRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Service; import javax.transaction.Transactional; @Service public class EmployeeService { @Autowired private EmployeeRepository repository; @Transactional public void update(Integer id, String name){ repository.updateNameById(id, name); } }
测试
package com.mouday.service; import com.mouday.repository.EmployeeRepository; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class EmployeeServiceTest { ApplicationContext context = null; EmployeeService service = null; @Before public void setup() { System.out.println("StudentDaoSpringJdbcImplTest.setup"); context = new ClassPathXmlApplicationContext("beans-jpa.xml"); service = context.getBean(EmployeeService.class); } @After public void tearDown() { System.out.println("StudentDaoSpringJdbcImplTest.tearDown"); context = null; } @Test public void testUpdate(){ service.update(1, "曹操"); } }