小白一个,文章中可能说的不严谨或者错的地方,请指出我立马改,我超快的,嘿嘿。
JPA介绍
Spring Date JPA 同样是对数据库进行的操作
与Mybatis不同的是,JPA自定义的接口必须继承 XXRepository,通常选择继承JpaRepository
Repository接口继承结构图:
XXRepository<T,ID>
T:表示要操作的实体类
ID:实体类中主键的类型
- Repository:空接口,表名任何继承它的均为仓库接口类
- CrudRepository:提供了一组CRUD相关的方法
- PagingAndSortingRepository:提供了一组分页、排序相关的方法
- QueryByExample:可以通过Example实例执行复杂条件语句
- JpaRepository:实现一组JPA规范相关的方法
JPA支持方法名关键字查询
可以免去SQL语句的编写
实例编写
前提:
如果是和之前的项目写在一起,记得将 mybatis依赖 及所有与mybatis相关的代码进行注释 ;
如果是新项目,记得加 数据库连接 和 mysql依赖
此项目我们依然使用(四)中的 t_article 数据表
1、加入相应的pom依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
2、编写实体类
package com.zknu.demo.model;
import javax.persistence.*;
@Entity(name = "t_article")
// 标注与之映射的数据表 ,默认为首字母小写的类名,也可用name属性就行指定
public class Discuss {
@Id // 标注主键
@GeneratedValue(strategy = GenerationType.IDENTITY)
// 主键的生成策略 IDENTITY为自动递增
private Integer id;
private String title;
@Column(name = "content")
private String desc;
// 如果字段名与属性名不一致,使用Column 指定表中的字段名所对应的类的属性名
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
@Override
public String toString() {
return "Discuss{" +
"id=" + id +
", title='" + title + '\'' +
", desc='" + desc + '\'' +
'}';
}
}
Column中字段名会报红没关系
3、编写Repository接口
package com.zknu.demo.mapper;
import com.zknu.demo.model.Discuss;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import javax.transaction.Transactional;
import java.awt.print.Pageable;
import java.util.List;
// Discuss为刚刚编写的实体类,Integer是实体类中主键的数据类型
public interface DiscussRepository extends JpaRepository<Discuss,Integer>{
public List<Discuss> findByDescNotNull();
// 使用JPA中的方法名关键字
// 表示:查找表中 desc(即 content)不为空的所有数据
@Query("select c from t_article c where c.id = ?1")
public List<Discuss> getDiscussByPaged(Integer id, Pageable pageable);
// 使用Query注解,可以使用分页查询
// SQL语句语法不变
// ?1 表示传的第一个参数
// 等同于 MyBatis中 #{参数}
@Query(value="select * from t_article where id = ?1",nativeQuery = true)
public List<Discuss> selectDiscuss2(Integer id);
// nativeQuery= true 编写原生的SQL语句
@Transactional // 支持事务管理
@Modifying // 支持数据变更
@Query("update t_article set title = ?2 where id = ?1")
public int updateDiscuss(String title,Integer id);
@Transactional
@Modifying
@Query(value = "insert into t_article(title,content) values (?1,?2)",nativeQuery = true)
public int insertDiscuss(String title,String desc);
@Transactional
@Modifying
@Query("delete from t_article where id = ?1")
public int deleteDiscuss(Integer id);
}
注意:
在进行 增加、修改、删除操作时,必须加上
@Transactional 和 @Modifying 两个注解
insert 语句必须使用value,因为JPA的jpql不支持insert into
insert into 的字段名必须使用数据表中的字段名,不可使用被@Column标注过的字段名
eg. insert into(title,content), 此时的 content 不能用 desc
4、测试类
使用JPA内部方法进行数据操作
@Autowired
private DiscussRepository repository;
@Test
public void selectByJPA(){
System.out.println(repository.findById(1));
}
findById方法并不是我们自定义的方法,而是JPA的内部方法
运行结果
使用自定义方法
插入语句
@Test
public void insertDiscuss(){
repository.insertDiscuss("入门","入门精通");
repository.insertDiscuss("入门","门入");
}
使用Example进行数据查询操作
Example的查询主要是 JpaRepository 继承的 QueryByExampleExecutor 接口的方法
Example包含 probe、matcher 两部分
probe 是实体类,用于查询的参对象
matcher 是查找规则
上面的测试中插入了两条语句,我们用 “入” 这个字来比较一下Example和ExampleMarcher的区别
数据表如下图
Example完整查询
测试类:
@Test
public void selectByExample(){
Discuss discuss = new Discuss();
discuss.setDesc("入门");
Example<Discuss> example = Example.of(discuss);
System.out.println(repository.findAll(example));
}
Example.of 相当于实例化 Example对象
运行结果
结果只有一行数据
所以这个测试类查找的是 desc(即 content)中值为 “入门” 的数据
等价于sql语句:
SELECT * FROM t_article where content = "入门"
ExampleMatcher模糊查询
测试类:
@Test
public void selectByExample2(){
Discuss discuss = new Discuss();
discuss.setDesc("入");
ExampleMatcher matcher = ExampleMatcher.matching().withMatcher("desc",ExampleMatcher.GenericPropertyMatchers.contains());
Example<Discuss> example = Example.of(discuss,matcher);
System.out.println(repository.findAll(example));
}
运行结果
结果有这三条数据
所以,此测试类表示 desc(即 content)中值包含 “入” 的所有数据
等价于sql语句:
SELECT * FROM t_article where content LIKE '%入%'
ExampleMatcher.matching().withMatcher(“desc”,ExampleMatcher.GenericPropertyMatchers.contains()
表示在字段 desc 中查找以包含为条件的数据
除 contains() 外,常用的还有:
- startsWith() 以xxx为开头
- endsWith() 以xxx为结尾