SpringBoot(三)Spring Data JPA操作数据库

学习内容

实现数据库增删改查操作、分页操作、动态查询操作、控制台打印SQL参数。

构建项目

pom.xml如下所示

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jpa</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>

配置文件

application.properties

spring.datasource.url=jdbc:mysql://localhost:3306/springboot-learning?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8&useSSL=false
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=root

# 使SQL语句打印在控制台
spring.jpa.show-sql=true

# 格式化SQL语句
spring.jpa.properties.hibernate.format_sql=true

#每次运行程序,没有表则会新建表格,表内有数据不会清空,只会更新
spring.jpa.hibernate.ddl-auto=update

# 设置数据表的引擎为InnoDB,默认为MyISAM
spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect

新建实体类

package com.example.springbootchapter3.entity;

import lombok.Data;


import javax.persistence.*;
import java.util.Date;

/**
 * Created by lzc
 * 2019/6/1 11:26
 */

@Data
@Entity
public class Student {

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY) // 设置数据库中id自增
    private Long id;

    // 学生姓名
    private String studentName;

    // 学生姓名
    private String gender;

    // 班级名称
    private String className;

    // 学生年龄
    private Integer age;

    // 学生所在城市
    private String cityName;

    // 创建时间
    private Date createTime;

    // 更新时间
    private Date updateTime;
}

可以看到Student 类中没有get方法和set方法,实体类上有@Data注解,使用该注解后,我们就不需要写get、set方法了。使用该注解还需要安装lombok插件,插件安装方法:Lombok详细教程及idea中lombok插件的安装

实现一个持久层服务

package com.example.springbootchapter3.repository;

import com.example.springbootchapter3.entity.Student;
import org.springframework.data.jpa.repository.JpaRepository;

/**
 * Created by lzc
 * 2019/6/1 14:48
 */
public interface StudentRepository extends JpaRepository<Student, Long> {


}

org.springframework.data.jpa.repository.JpaRepository<T, ID> 接口。其中 T 是数据库实体类,ID 是数据库实体类的主键。

从上面的代码可以看出,StudentRepository 继承了JpaRepository,查看JpaRepository的源码可以发现,JpaRepository为我们提供了很多现成接口供我们使用。

一行代码也不用写。那么针对 StudentRepository 这个实体类,已经拥有下面的功能

这里为了方便就不编写service层了。

使用JpaRepository提供的方法操作数据库,使用测试类进行测试,如下所示

@RunWith(SpringRunner.class)
@SpringBootTest
@Slf4j
public class SpringbootChapter3ApplicationTests {

	@Autowired
	private StudentRepository studentRepository;

	// 增加
	@Test
	public void test1() {
		Student student = new Student();
		student.setStudentName("lisi");
		student.setAge(20);
		student.setCityName("桂林");
		student.setClassName("计科153");
		student.setGender("女");
		studentRepository.save(student);
	}

	// 删除
	@Test
	public void test2() {
		// 通过id删除,如果id不存在,将会抛异常
		// 删除之前可以通过studentRepository.existsById(1L)来判断id是否存在,如果存在,则删除
		studentRepository.deleteById(1L);
	}

	// 修改
	@Test
	public void test3() {
		// 通过id查询
		Student result = studentRepository.findById(4L).orElse(null); // 当查询结果不存在时则返回null
		result.setAge(18);
		studentRepository.save(result);
	}

	// 简单查询:查询所有记录
	@Test
	public void test4() {
		List<Student> studentList = studentRepository.findAll();
		studentList.stream().forEach(s -> log.info(s.toString()));
	}

	// 简单查询:分页查询
	@Test
	public void test5() {
		Page<Student> studentPage = studentRepository.findAll(PageRequest.of(1,2));

		List<Student> studentList = studentPage.getContent();
		studentList.stream().forEach(s -> log.info(s.toString()));

        log.info("【TotalPages】"  + studentPage.getTotalPages());
        log.info("【totalElements】"  + studentPage.getTotalElements());
        log.info("【Number】"  + studentPage.getNumber());
        log.info("【Size】"  + studentPage.getSize());
        log.info("【NumberOfElements】"  + studentPage.getNumberOfElements());
	}

	// 简单查询:分页查询+排序(要么升序,要么降序)
	@Test
	public void test6() {

		Page<Student> studentPage = studentRepository.findAll(PageRequest.of(0,10,Sort.Direction.ASC,"age"));

		List<Student> studentList = studentPage.getContent();
		studentList.stream().forEach(s -> log.info(s.toString()));

		log.info("【TotalPages】"  + studentPage.getTotalPages());
		log.info("【totalElements】"  + studentPage.getTotalElements());
		log.info("【Number】"  + studentPage.getNumber());
		log.info("【Size】"  + studentPage.getSize());
		log.info("【NumberOfElements】"  + studentPage.getNumberOfElements());
	}

	// 简单查询:分页查询+排序(既有升序,又有降序)
	@Test
	public void test7() {

		Sort sort = new Sort(Sort.Direction.DESC,"age"); // 年龄降序
		sort = sort.and(new Sort(Sort.Direction.ASC,"className")); // 班级升序

		Page<Student> studentPage = studentRepository.findAll(PageRequest.of(0,10,sort));

		List<Student> studentList = studentPage.getContent();
		studentList.stream().forEach(s -> log.info(s.toString()));

		log.info("【TotalPages】"  + studentPage.getTotalPages());
		log.info("【totalElements】"  + studentPage.getTotalElements());
		log.info("【Number】"  + studentPage.getNumber());
		log.info("【Size】"  + studentPage.getSize());
		log.info("【NumberOfElements】"  + studentPage.getNumberOfElements());
	}

}

扩展查询

虽然JpaRepository为我们提供了很多操作方法,但是很多我们想要的查询功能还是没有。然而JPA 提供了非常优雅的方式来解决。

根据实体类属性来查询

例如通过实体类的studentName属性进行查询,在StudentRepository接口中声明如下方法即可

Student findByStudentName(String studentName);

还可以进行多个属性进行查询,例如根据实体类的studentName和cityName进行查询,在StudentRepository接口中声明如下方法即可

Student findByStudentNameAndCityName(String studentName, String cityName);

根据实体类的属性进行分页查询

Page<Student> findByClassName(String className, Pageable pageable);

下表描述了JPA支持的关键字以及包含该关键字的方法

KeywordSampleJPQL snippet

And

findByLastnameAndFirstname

… where x.lastname = ?1 and x.firstname = ?2

Or

findByLastnameOrFirstname

… where x.lastname = ?1 or x.firstname = ?2

Is,Equals

findByFirstname,findByFirstnameIs,findByFirstnameEquals

… where x.firstname = ?1

Between

findByStartDateBetween

… where x.startDate between ?1 and ?2

LessThan

findByAgeLessThan

… where x.age < ?1

LessThanEqual

findByAgeLessThanEqual

… where x.age <= ?1

GreaterThan

findByAgeGreaterThan

… where x.age > ?1

GreaterThanEqual

findByAgeGreaterThanEqual

… where x.age >= ?1

After

findByStartDateAfter

… where x.startDate > ?1

Before

findByStartDateBefore

… where x.startDate < ?1

IsNull

findByAgeIsNull

… where x.age is null

IsNotNull,NotNull

findByAge(Is)NotNull

… where x.age not null

Like

findByFirstnameLike

… where x.firstname like ?1

NotLike

findByFirstnameNotLike

… where x.firstname not like ?1

StartingWith

findByFirstnameStartingWith

… where x.firstname like ?1(parameter bound with appended %)

EndingWith

findByFirstnameEndingWith

… where x.firstname like ?1(parameter bound with prepended %)

Containing

findByFirstnameContaining

… where x.firstname like ?1(parameter bound wrapped in %)

OrderBy

findByAgeOrderByLastnameDesc

… where x.age = ?1 order by x.lastname desc

Not

findByLastnameNot

… where x.lastname <> ?1

In

findByAgeIn(Collection<Age> ages)

… where x.age in ?1

NotIn

findByAgeNotIn(Collection<Age> ages)

… where x.age not in ?1

True

findByActiveTrue()

… where x.active = true

False

findByActiveFalse()

… where x.active = false

IgnoreCase

findByFirstnameIgnoreCase

… where UPPER(x.firstame) = UPPER(?1)

自定义查询

通过编写SQL方式的方式进行查询,如下所示。如果是update/delete操作,需要加上 @Transactional和@Modifying注解。

    // 使用Spring Data JPA提供的SQL规则
    @Query("select s from Student s where s.studentName = ?1")
    Student getByStudentName1(String studentName);

    // 使用原生SQL
    @Query(value = "select * from student where student_name = ?1", nativeQuery = true)
    Student getByStudentName2(String studentName);

    // 这里需要加上事物
    @Transactional
    @Modifying
    @Query("update Student s set s.age = ?2 where s.id = ?1")
    Integer updateAgeById(Long id, Integer count);

动态查询

JPA为我们提供了Example类实现动态查询

具体用法看如下测试方法

	// JPA动态查询
	@Test
	public void test11() {
		Student student = new Student();
		student.setCityName("南宁");
		student.setClassName("计科152");

		Example<Student> example = Example.of(student);
		// SQL语句 select * from student where city_name = '南宁' and class_name = '计科152'
		List<Student> studentList = studentRepository.findAll(example);
		studentList.forEach(s -> log.info(s.toString()));
	}
	@Test
	public void test12() {
		Student student = new Student();
		student.setCityName("南宁");
		student.setClassName("计科152");

		Example<Student> example = Example.of(student);
		// SQL语句 select * from student where city_name = '南宁' and class_name = '计科152' order by age desc limit 0,2
		Page<Student> studentPage = studentRepository.findAll(example, PageRequest.of(0,2, Sort.Direction.DESC,"age"));

		List<Student> studentList = studentPage.getContent();
		studentList.stream().forEach(s -> log.info(s.toString()));

		log.info("【TotalPages】"  + studentPage.getTotalPages());
		log.info("【totalElements】"  + studentPage.getTotalElements());
		log.info("【Number】"  + studentPage.getNumber());
		log.info("【Size】"  + studentPage.getSize());
		log.info("【NumberOfElements】"  + studentPage.getNumberOfElements());
	}
	@Test
	public void test13() {
		Student student = new Student();
		student.setCityName("南宁");
		student.setClassName("计科");

		// 设置属性的查询规则,
		// 有ignoreCase(),caseSensitive(),contains(),endsWith(),startsWith(),exact(),storeDefaultMatching(),regex()
		ExampleMatcher matcher = ExampleMatcher.matching()
				.withMatcher("className",startsWith());

		Example<Student> example = Example.of(student, matcher);

		List<Student> studentList = studentRepository.findAll(example);
		studentList.forEach(s -> log.info(s.toString()));
	}

JPA配置实体类创建时间、更新时间自动赋值

在实体类上添加 @EntityListeners(AuditingEntityListener.class)注解,在创建时间字段上添加 @CreatedDate注解,在更新时间字段上添加 @LastModifiedDate,时间类型可以为:DateTime、Date、Long、long、JDK8日期和时间类型

然后还需要在启动类加上@EnableJpaAuditing注解。

打印SQL参数

前面的学习中,执行数据库操作时,控制台只打印出SQL语句而没有SQL参数,为了看到SQL参数,可在application.properties配置文件中作如下配置

logging.level.org.hibernate.type.descriptor.sql.BasicBinder=trace

 

代码地址:https://github.com/923226145/SpringBoot-learning/tree/master/springboot-chapter3

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值