1.1 JpaRepository 排序和分页
1.1.1 排序
Repository
package com.ll.repository;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import com.ll.entity.Student;
public interface StudentRepository extends JpaRepository<Student,Integer> {
//根据科目查询学生信息,按照学生成绩,降序排列
public List<Student> findBySubjectOrderByScoreDesc(String sub);
}
注意:
- 降序------OrderByScoreDesc
- 升序-------OrderByScoreAsc
- 主键类型是int -----JpaRepository<Student,Integer>
- 查询的字段需要对varchar的字段进行排序,因为这个字段是以前就已经生成的,但是所有的值都是数字,排序的结果和预期的数值大小排序不太一样。
- 原因在于对于字符串的排序原理是按位(每个字符)进行比较的,并且是按照每个字符的ascii码值,包括数字(数字的ascii值等于该数字的值)。
- 解决方法:https://www.2cto.com/database/201808/774222.html
Service
@Service
public class StudentService {
@Resource
StudentRepository studentRepository;
//排序
public List<Student> findBySubjectOrderByScoreDesc(String sub){
return studentRepository.findBySubjectOrderByScoreDesc(sub);
}
}
Controller
@RestController
@RequestMapping("student")
public class StudentController {
@Resource
StudentService studentService;
//排序
@RequestMapping("sub/{name}")
public List<Student> showBySub(@PathVariable("name") String sub){
System.out.println("sub+"+sub);
return studentService.findBySubjectOrderByScoreDesc(sub);
}
}
查询测试:http://localhost:9081/b/student/sub/数学
查询结果:
1.1.2 分页排序
Repository
package com.ll.repository;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import com.ll.entity.Student;
public interface StudentRepository extends JpaRepository<Student,Integer> {
//分页排序
public Page<Student> findBySubjectOrderByScoreDesc(String sub,Pageable pageable);
}
Service
//分页排序
public Page<Student> findBySubjectOrderByScoreDesc(String sub,String startpage,String limit){
Pageable pageable=PageRequest.of(Integer.parseInt(startpage), Integer.parseInt(limit));
return studentRepository.findBySubjectOrderByScoreDesc(sub,pageable);
}
Controller
//分页排序
@RequestMapping("page/{name}/{start}/{limit}")
public Page<Student> showPageBySub(@PathVariable("name") String sub,@PathVariable("start") String startpage,@PathVariable("limit") String limit){
System.out.println("sub+"+sub);
return studentService.findBySubjectOrderByScoreDesc(sub,startpage,limit);
}
查询测试:http://localhost:9081/b/student/page/数学/1/3
查询结果:
1.2 @Query查询
1.2.1
Repository
//根据name和team_id查询
@Query("select s from Student s where s.teamId=?1 and s.name=?2")
public Student getStudentssssdfs(int tid,String name);
@Query(value="select * from student where team_id=?1 and name=?2",nativeQuery=true)
public Student getStudentnative(int tid,String name);
- @Query 默认使用JPQL语句,操作的是对象,所以里面的列名字必须和entity的属性名字一样
- nativeQuery=true 表示使用SQL语句,操作的是数据库表,所以里面的列名字必须和数据库里的名字一样
Service
public Student getStudent(int tid,String name) {
return studentRepository.getStudentssssdfs(tid, name);
}
Controller
@RequestMapping("showone/{name}/{tid}")
public Student getStudent(@PathVariable("name") String name,@PathVariable("tid") String tid) {
return studentService.getStudent(Integer.parseInt(tid), name);
}
- Integer.parseInt( ) //String 转int ----- Integer是int类型的包装类
1.2.2 @Query 实现复杂查询 + 批量修改
复杂查询
- 注意: SpringData没有像Beet1SQL那样允许将SQL查询结果映射到一个任意POJO或者Map 对象上,所以,对于非实体类返回结果 ,只能用Object[ ] 数组。数组中每个元素的类型要小心处理,比如count(*),返回的类型是BigInteger,在不同的数据库中返回的可能是BigDecimal
@Query(value="select subject,count(*) from student group by subject",nativeQuery=true)
public List<Object[]> getSubGroup();
批量修改
-
执行update,delete,insert 必须加 @Transactional @Modifying
-
@Modifying 的主要作用是声明执行的SQL语句是更新(增删改)操作
@Modifying注释声明该方法是修改操作,select语句不用该注释,要注意的是:方法的返回值应该是int或者void,如果是Int表示更新语句所影响的行数 -
@Transactional 的主要作用是提供事务支持(提供例如隔离性等事务特性,JPA默认会依赖JDBC默认隔离级别)@Transactional注释声明该方法是事务性操作,如果Query语句执行的时候出现问题,将会回滚到执行前的状态,DELETE和UPDATE方法必须要加@Transactional
-
-
@Modifying和@Transactional为什么配合才能使用的 原因 :
- 默认情况下JPA的每个操作都是事务的,在默认情况下,JPA的事务会设置为只读,具体可以参考SimpleJpaRepository。
- 实质上@Modifying只是声明了这个操作是一个修改操作,但却没有修改这个方法的事务等级,因此这个方法依然不能进行修改操作。只有声明了@Transactional,本质上是声明了@Transactional(readOnly=false),这样覆盖了默认的@Transactional配置便可以执行修改操作了
(原文链接:https://blog.csdn.net/zhenlingcn/article/details/84593013 )
@Transactional
@Modifying
@Query("update Student set subject='语文' where id>?1")
public int updateStu(int id);
- 默认是JPQL,操作对象
1.3 springboot测试service
在pom文件中引入
<!-- 添加测试 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
-
@RunWith 是 JUnit 标准的一个注解,用来告诉JUnit 单元测试框架不要使用内置的方式进行单元测试,而使用 RunWith 指明的类来提供单元测试,所有的 Spring 单元测试总是使用 SpringRunner.class
-
@SpringBootTest 用于Springboot 应用测试
- 该注解是用到类名上,表示自动启动加载类或指定某个或多个加载启动类,默认会加载当前module下的启动类
- 可以指定具体的启动类,且可以多个(3)
- SpringBoot 2.0+版本后,默认生产启动测试类,
可以直接extends TestApplicationTests,这样就不用加@RunWith和@SpringBootTest注解
package com.ll;
import java.util.List;
import javax.annotation.Resource;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import com.ll.entity.Student;
import com.ll.repository.StudentRepository;
@RunWith(SpringRunner.class)
@SpringBootTest
public class StudentTset {
@Resource
StudentRepository studentRepository;
@Test
public void t1() {
Student s=studentRepository.getStudentnative(1, "小红");
System.out.println(s.getScore());
}
@Test
public void t2() {
List<Object[]> s=studentRepository.getSubGroup();
System.out.println(s.get(0)[0]);//英语 相当于list里面的第一个数组中的第一个元素
System.out.println(s.get(0)[1]);//1
System.out.println(s.get(1)[0]);//数学
System.out.println(s.get(1)[1]);//5
}
@Test
public void t3() {
int i=studentRepository.updateStu(6);
}
}
结果