JPA是Java Persistence API的简称,中文名Java持久层API,是JDK 5.0注解或XML描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中。
Sun引入新的JPA ORM规范出于两个原因:其一,简化现有Java EE和Java SE应用开发工作;其二,Sun希望整合ORM技术,实现天下归一。
是一个持久层(作用在dao层)的ORM(对象关系映射)框架,对JDBC的封装,使用jpa可以实现对数据表的增删改查
由于表和其属性(实体)与数据库中的表映射,所以操作表(实体)就能够操作数据库里的表
首先新建一个spingboot工程,选依赖的时候把JPA选上,因为我们需要连接数据库,所以再选一个Mysql的驱动
在application.properties中配置连接数据库和jpa的相关配置
#连接数据库
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/jpa
spring.datasource.username=root
spring.datasource.password=x5
#jpa相关配置
spring.jpa.generate-ddl=true
#如果设置为create 每次运行程序都会删除原来的数据库表,再生成一个新的表
spring.jpa.hibernate.ddl-auto=update
#操作实体对象时会生成sql语句
spring.jpa.show-sql=true
#指定数据库类型
spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect
新建一个实体类
@Data 里面有get,set,toString,equals等方法
@Entity表示是一个实体表,name是要生成的表的名称
@ID 表示是主键
@GeneratedValue(strategy= GenerationType.IDENTITY) ID生成策略,默认是auto,主键自增,但是会多出来一个表,图中这个也是主键自增,不会生成多余的表
@Column 表示是一个普通字段
package com.hanbo.springboot_jpa.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.*;
@Data
@Entity(name = "animal")
public class Animal {
@Id
//主键生成策略,自增,默认的auto会多出来一个表
@GeneratedValue(strategy= GenerationType.IDENTITY)
private int id;
@Column
//普通的列
private String aname;
@Column
private int lifetime;
@Column
private String hobby;
@Column
private String address;
public Animal() {
}
public Animal(int id, String aname, int lifetime, String hobby, String address) {
this.id = id;
this.aname = aname;
this.lifetime = lifetime;
this.hobby = hobby;
this.address = address;
}
}
新建一个Dao,继承一个JpaRepository接口,泛型前面的值是实体类,后面的值是它的主键的类型,这个接口里面有一些方法,比如查询所有,查询一条,增加,删除所有,删除一条,分页查询等
package com.hanbo.springboot_jpa.dao;
import com.hanbo.springboot_jpa.pojo.Animal;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import java.util.List;
public interface AnimalDao extends JpaRepository {
//自定义查询:根据名称查
ListfindByAname(String aname);
//自定义查询:根据地点查
ListfindByaddress(String address);
//自定义查询:根据寿命和爱好查
ListfindByLifetimeAndHobby(int lifetime,String hobby);
//自定义查询:根据id查,id为s-b的animal对象
ListfindByIdBetweenOrderById(int s,int b);
//jpql 查询所有
@Query(value = "from animal")
ListloadList();
//jpql 根据条件查
@Query(value = "select aname,hobby from animal")
List
准备工作完成后,写测试类
先直接启动一下工程,表就应该建出来了,根据类建表的是正向工程,根据表建类的是逆向工程
因为是做练习,所以命名不规范,最好不要这样做
package com.hanbo.springboot_jpa;
import com.hanbo.springboot_jpa.dao.AnimalDao;
import com.hanbo.springboot_jpa.pojo.Animal;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
@SpringBootTest
class SpringbootJpaApplicationTests {
@Autowired
AnimalDao animalDao;
@Test
void contextLoads() {
System.out.println("创建完成...........");
}
@Test
//添加一条
void addAnimal() {
Animal animal=new Animal();
animal.setAname("狮子");
animal.setAddress("非洲");
animal.setHobby("吃肉");
animal.setLifetime(14);
animal.setId(2);
animalDao.save(animal);
}
@Test
//根据id查一条
void queryByid() {
Optional optionalAnimal =animalDao.findById(1);
Animal animal= optionalAnimal.get();
System.out.println(animal.getId()+" "+animal.getAname()+" "+animal.getHobby()+" "+
animal.getLifetime()+" "+animal.getAddress());
}
@Test
//查询所有
void queryAll() {
List all = animalDao.findAll();
System.out.println(all);
}
@Test
//分页
void page(){
Pageable pageable=PageRequest.of(0,2, Sort.Direction.DESC,"id");
Page animals = animalDao.findAll(pageable);
for (Animal animal : animals) {
System.out.println(animal.getId()+" "+animal.getAname()+" "+animal.getHobby()+" "+
animal.getLifetime()+" "+animal.getAddress());
}
}
@Test
//根据id删除一条
void delete(){
animalDao.deleteById(2);
}
@Test
//根据名称查询
void findbyAname(){
List animals = animalDao.findByAname("狮子");
System.out.println(animals);
}
@Test
//根据地点查询
void findbyAddress(){
List address = animalDao.findByaddress("非洲");
System.out.println(address);
}
@Test
//根据寿命和爱好查询
void findbyhl(){
List hl = animalDao.findByLifetimeAndHobby(30, "玩");
System.out.println(hl);
}
@Test
//查询id为1-5的
void findByIdBetweenOrderById(){
List list = animalDao.findByIdBetweenOrderById(1, 5);
System.out.println(list);
}
@Test
//jpql查询所有
void jpql(){
List animals = animalDao.loadList();
System.out.println(animals);
}
@Test
//jpql查询名称和爱好
void jpql2(){
List
当JpaRepository接口里的方法不能满足我们的需求时,我们可以自定义查询
比如我们要根据动物名称查询
ListfindByAname(String aname);
注意事项:方法返回值根据需求定义,方法名称有一定规范,findByxxx,xxx为属性名称
根据两个属性查询
findBy属性1And属性2
其他的方法可以自己尝试一下
基于首次在EJB2.0中引入的EJB查询语言(EJB QL),Java持久化查询语言(JPQL)是一种可移植的查询语言,旨在以面向对象表达式语言的表达式,将SQL语法和简单查询语义绑定在一起·使用这种语言编写的查询是可移植的,可以被编译成所有主流数据库服务器上的SQL。
其特征与原生SQL语句类似,并且完全面向对象,通过类名和属性访问,而不是表名和表的属性。
JPQL与SQL
JPQL 和 SQL 有很多相似之处。归根结底,它们都用于访问和操作数据库数据。而且,二者都使用非过程语句 — 通过特殊解释程序识别的命令。此外,JPQL 在语法上与 SQL 也相似。
JPQL 和 SQL 的主要区别在于,前者处理 JPA 实体,后者直接在数据库空间内对表、列、行等关系数据进行处理。
规则:
1.里面不能出现表名,列名,只能出现java的类名,属性名,区分大小写
2.出现的sql关键字是一样的意思,关键字不区分大小写
3.不能写select * 要写select 别名
例如:
查询所有
@Query表示它是一个JPQL查询语句,因为规则里不能出现select * 所有省略,
@Query(value = " from animal")
ListloadList();
如果查询的字段有多个,就会出现org.springframework.core.convert.ConversionFailedException(类型转换异常),查询的结果没有封装到实体类中,返回的是一个Object数组,解决办法就是把方法里的泛型改成Object数组,但要是非要把它变成一个实体对象也不是没有办法,需要new一个实体,把参数封装到里面,写法如下:
@Query(value = "select new animal (id,aname,lifetime,hobby,address) from animal ")
ListloadList3();
(略)基本与单表的差不多,引依赖,写配置等
首先理清学生和班级的关系,一个班级有多个学生,一个学生属于一个班,所以在班级类中需要一个学生的集合,并在上面加上@OneToMany主键表示一对多关系并加上mappedBy = "clazz",创建一对多映射关系,而学生类里需要有班级的信息,所以在学生类里定义一个班级属性,并在上面加上@JoinColumn(name = "cid"),其中cid表示外键列,也就是班级的主键
package com.hanbo.demo2.domain;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
import javax.persistence.*;
@Getter
@Setter
@Entity(name = "student")
public class Student {
@Id
@GeneratedValue(strategy= GenerationType.IDENTITY)
private int sid;
@Column
private String sname;
@Column
private int age;
@ManyToOne()
@JoinColumn(name = "cid")
private Clazz clazz;
public int getSid() {
return sid;
}
public void setSid(int sid) {
this.sid = sid;
}
public String getSname() {
return sname;
}
public void setSname(String sname) {
this.sname = sname;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Clazz getClazz() {
return clazz;
}
public void setClazz(Clazz clazz) {
this.clazz = clazz;
}
@Override
public String toString() {
return "Student{" +
"sid=" + sid +
", sname='" + sname + '\'' +
", age=" + age +
", clazz=" + clazz +
'}';
}
}
package com.hanbo.demo2.domain;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
import javax.persistence.*;
import java.util.List;
@Getter
@Setter
@Entity(name = "clazz")
public class Clazz {
@Id
@GeneratedValue(strategy= GenerationType.IDENTITY)
private int cid;
@Column
private String cname;
@OneToMany(mappedBy = "clazz",cascade = CascadeType.ALL)
private List list;
public int getCid() {
return cid;
}
public void setCid(int cid) {
this.cid = cid;
}
public String getCname() {
return cname;
}
public void setCname(String cname) {
this.cname = cname;
}
public List getList() {
return list;
}
public void setList(List list) {
this.list = list;
}
@Override
public String toString() {
return "Clazz{" +
"cid=" + cid +
", cname='" + cname + '\'' +
'}';
}
}
Dao层的接口同样继承 JpaRepository接口(略)
由于学生表里有个cid,所以添加方法需要new一个班级,并set一个cid,修改同理,
查询班级有点坑,直接查的话,会报一个懒加载的异常,我们需要在班级类@OneToMany里添加一个fetch = FetchType.EAGER,表示立即加载,还有就是最好不要用@Data,里面的toString方法容易产生问题,会报一个java.lang.StackOverflowError(栈溢出错误),而这两个都去生成toString方法也会报这个错,我的解决办法是把班级类toString里的集合删掉,这样就不会产生栈溢出了,删除学生这里你会发现执行成功了,但是数据库里没删掉,而且控制台打印的是查询语句,不是删除语句,解决方法,把班级类里的立即加载去掉,并加上cascade = CascadeType.ALL级联删除,或者断开两个表之间的联系(学生表里的cid改成null)再删除
package com.hanbo.demo2;
import com.hanbo.demo2.dao.ClazzDao;
import com.hanbo.demo2.dao.StudentDao;
import com.hanbo.demo2.domain.Clazz;
import com.hanbo.demo2.domain.Student;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
@SpringBootTest
class Demo2ApplicationTests {
@Autowired
ClazzDao clazzDao;
@Autowired
StudentDao studentDao;
@Test
void contextLoads() {
System.out.println("建表");
}
@Test
void addClazz() {
Clazz clazz=new Clazz();
clazz.setCname("汪汪队立大功");
clazzDao.save(clazz);
}
@Test
void addStudent() {
Student student=new Student();
student.setSname("斗牛犬");
student.setAge(2);
Clazz clazz=new Clazz();
clazz.setCid(1);
student.setClazz(clazz);
studentDao.save(student);
}
@Test
void updateClass() {
Clazz clazz=new Clazz();
clazz.setCname("幼儿园");
clazz.setCid(1);
clazzDao.save(clazz);
}
@Test
void updateStudent() {
Student student=new Student();
student.setSname("小明");
student.setAge(1);
student.setSid(1);
Clazz clazz=new Clazz();
clazz.setCid(1);
student.setClazz(clazz);
studentDao.save(student);
clazzDao.save(clazz);
}
@Test
void findallClazz() {
List clazzes = clazzDao.findAll();
for (Clazz clazz : clazzes) {
System.out.println(clazz.getCid()+" "+clazz.getCname()+" "+clazz.getList());
List students = clazz.getList();
}
}
@Test
void findallStudent() {
List students = studentDao.findAll();
for (Student student : students) {
System.out.println(student);
}
}
@Test
void deleteClazz() {
clazzDao.deleteById(5);
}
@Test
void deleteStudent() {
studentDao.deleteById(2);
}
@Test
void addClazzStudent() {
Clazz clazz=new Clazz();
clazz.setCname("闪电班");
Student student=new Student();
student.setSname("闪电行者拉娜");
student.setAge(20);
Student student2=new Student();
student2.setSname("闪电行者拉拉");
student2.setAge(45);
List students=new ArrayList<>();
students.add(student);
students.add(student2);
clazz.setList(students);
student.setClazz(clazz);
student2.setClazz(clazz);
clazzDao.save(clazz);
}
}
员工
package com.hanbo.springboot_jpa3.pojo;
import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;
@Entity(name = "emp")
public class Emp {
@Id
@GeneratedValue(strategy= GenerationType.IDENTITY)
private int eid;
@Column
private String ename;
//使emp放弃了外键的维护权力,防止主键重复
@ManyToMany(mappedBy = "emps",fetch = FetchType.EAGER)
private List projects=new ArrayList<>();
public int getEid() {
return eid;
}
public void setEid(int eid) {
this.eid = eid;
}
public String getEname() {
return ename;
}
public void setEname(String ename) {
this.ename = ename;
}
public List getProjects() {
return projects;
}
public void setProjects(List projects) {
this.projects = projects;
}
@Override
public String toString() {
return "Emp{" +
"eid=" + eid +
", ename='" + ename + '\'' +
'}';
}
}
项目
package com.hanbo.springboot_jpa3.pojo;
import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;
@Entity(name = "project")
public class Project {
/*
* @JoinTable 当前实体类与第三张表之间的关联关系
* uniqueConstraints @JoinTable的一个属性,数组类型,数组中的值是注解类型
* @UniqueConstraint 是一个注解,columnNames是属性,对应的值是数组(字符串类型)
* joinColumns 当前对象在中间表的外键,name 外键名
* referencedColumnName 参照主键表的主键名称
* */
@Id
@GeneratedValue(strategy= GenerationType.IDENTITY)
private int pid;
@Column
private String pname;
@ManyToMany(fetch = FetchType.EAGER)
//中间表
@JoinTable(name = "emp_project",uniqueConstraints={@UniqueConstraint(columnNames = {"eid","pid"})},
joinColumns={@JoinColumn(name = "pid",referencedColumnName = "pid")},
inverseJoinColumns = {@JoinColumn(name = "eid",referencedColumnName = "eid")}
)
private List emps=new ArrayList<>();
public int getPid() {
return pid;
}
public void setPid(int pid) {
this.pid = pid;
}
public String getPname() {
return pname;
}
public void setPname(String pname) {
this.pname = pname;
}
public List getEmps() {
return emps;
}
public void setEmps(List emps) {
this.emps = emps;
}
@Override
public String toString() {
return "Project{" +
"pid=" + pid +
", pname='" + pname + '\'' +
", emps=" + emps +
'}';
}
}
package com.hanbo.springboot_jpa3;
import com.hanbo.springboot_jpa3.dao.EmpDao;
import com.hanbo.springboot_jpa3.dao.ProjectDao;
import com.hanbo.springboot_jpa3.pojo.Emp;
import com.hanbo.springboot_jpa3.pojo.Project;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
@SpringBootTest
class SpringbootJpa3ApplicationTests {
@Autowired
EmpDao empDao;
@Autowired
ProjectDao projectDao;
@Test
void contextLoads() {
System.out.println("表创建");
}
@Test
//只能添加员工,没有关联的项目信息,原因,放弃了维护外键
void addEmp() {
//添加员工
//创建员工信息
Emp emp=new Emp();
emp.setEname("马修");
//创建项目信息
Project project=new Project();
project.setPname("学生管理系统");
Project project2=new Project();
project2.setPname("图书管理系统");
//建立关系
emp.getProjects().add(project);
emp.getProjects().add(project2);
//执行方法
empDao.save(emp);
}
/*
* TransientObjectException瞬时对象异常,emp没有被session管理,project中关联了emp,
*
* */
@Test
//方法一
void addProject() {
//添加项目
//创建员工
Emp emp=new Emp();
emp.setEname("道尔夫");
Emp emp2=new Emp();
emp2.setEname("索菲");
//创建项目
Project project=new Project();
project.setPname("学生管理系统");
//关联关系
//emp交给session管理
empDao.save(emp);
empDao.save(emp2);
projectDao.save(project);
}
@Test
void addProject2() {
//方法二
//查询员工id
Emp emp = empDao.getOne(2);
Emp emp2 = empDao.getOne(3);
//创建项目
Project project=new Project();
project.setPname("狂扁小盆友");
//关联关系
project.getEmps().add(emp);
project.getEmps().add(emp2);
projectDao.save(project);
}
@Test
void updateEmp() {
Emp emp=new Emp();
emp.setEname("员工2");
emp.setEid(2);
Emp emp2=new Emp();
emp2.setEname("员工3");
emp2.setEid(3);
Project project = projectDao.getOne(2);
Project project1= projectDao.getOne(3);
emp.getProjects().add(project);
emp.getProjects().add(project1);
empDao.save(emp);
empDao.save(emp2);
}
@Test
void updateProject() {
Emp emp=new Emp();
emp.setEname("员工1号");
emp.setEid(1);
Emp emp2=new Emp();
emp2.setEid(2);
emp2.setEname("员工2号");
Project project=new Project();
project.setPname("我想吃冰激凌");
project.setPid(1);
project.getEmps().add(emp);
project.getEmps().add(emp2);
empDao.save(emp);
empDao.save(emp2);
projectDao.save(project);
}
@Test
//报懒加载的错,有两种解决方法,一种是在 @ManyToMany加上(fetch = FetchType.EAGER),设置立即加载
//还有一种是延长session生命周期
void findProject() {
List projects = projectDao.findAll();
for (Project project : projects) {
System.out.println(project.getPid() + " " + project.getPname() + " " + project.getEmps());
List emps = project.getEmps();
System.out.println(emps);
}
}
@Test
//只能查员工
void findEmp() {
List emps = empDao.findAll();
for (Emp emp: emps) {
System.out.println(emp.getEid()+" "+emp.getEname());
}
}
@Test
//删除项目
void deleteProject() {
Project project = projectDao.getById(3);
projectDao.delete(project);
}
//删除失败,3号员工被引用过,emp没有维护外键
//如果没有被引用就可以删除成功
void deleteEmp() {
Emp emp = empDao.getById(3);
empDao.delete(emp);
}
}
在@JoinColumn里加个属性unique,唯一约束
男孩
package com.hanbo.springboot_jpa4.pojo;
import javax.persistence.*;
@Entity(name = "boy")
public class Boy {
@Id
@GeneratedValue(strategy= GenerationType.IDENTITY)
private int bid;
@Column
private String bname;
@Column
private int age;
@OneToOne(cascade = CascadeType.ALL)
//unique 唯一约束,不加就是一对多
@JoinColumn(name = "gid",unique=true)
private Girl girl;
public int getBid() {
return bid;
}
public void setBid(int bid) {
this.bid = bid;
}
public String getBname() {
return bname;
}
public void setBname(String bname) {
this.bname = bname;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Girl getGirl() {
return girl;
}
public void setGirl(Girl girl) {
this.girl = girl;
}
@Override
public String toString() {
return "Boy{" +
"bid=" + bid +
", bname='" + bname + '\'' +
", age=" + age +
", girl=" + girl +
'}';
}
public Boy() {
}
public Boy(int bid, String bname, int age, Girl girl) {
this.bid = bid;
this.bname = bname;
this.age = age;
this.girl = girl;
}
}
女孩
package com.hanbo.springboot_jpa4.pojo;
import javax.persistence.*;
import java.util.List;
@Entity(name = "girl")
public class Girl {
@Id
@GeneratedValue(strategy= GenerationType.IDENTITY)
private int gid;
@Column
private String gname;
@Column
private int age;
@OneToOne(mappedBy ="girl")
private Boy boy;
public int getGid() {
return gid;
}
public void setGid(int gid) {
this.gid = gid;
}
public String getGname() {
return gname;
}
public void setGname(String gname) {
this.gname = gname;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Boy getBoy() {
return boy;
}
public void setBoy(Boy boy) {
this.boy = boy;
}
@Override
public String toString() {
return "Girl{" +
"gid=" + gid +
", gname='" + gname + '\'' +
", age=" + age +
'}';
}
public Girl() {
}
public Girl(int gid, String gname, int age, Boy boy) {
this.gid = gid;
this.gname = gname;
this.age = age;
this.boy = boy;
}
}
package com.hanbo.springboot_jpa4;
import com.hanbo.springboot_jpa4.dao.BoyDao;
import com.hanbo.springboot_jpa4.dao.GirlDao;
import com.hanbo.springboot_jpa4.pojo.Boy;
import com.hanbo.springboot_jpa4.pojo.Girl;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
import java.util.Optional;
@SpringBootTest
class SpringbootJpa4ApplicationTests {
@Autowired
GirlDao girlDao;
@Autowired
BoyDao boyDao;
@Test
void contextLoads() {
System.out.println("创建成功");
}
@Test
void addgirl() {
Girl girl=new Girl();
girl.setGname("女孩1");
girl.setAge(30);
girlDao.save(girl);
}
@Test
void addboy() {
Boy boy=new Boy();
boy.setBname("男孩1");
boy.setAge(30);
Girl girl = girlDao.getById(1);
boy.setGirl(girl);
boyDao.save(boy);
}
@Test
//级联添加
void addbg() {
Boy boy=new Boy();
boy.setBname("男孩2");
boy.setAge(40);
Girl girl=new Girl();
girl.setGname("女孩2");
girl.setAge(40);
boy.setGirl(girl);
boyDao.save(boy);
girlDao.save(girl);
}
@Test
void updategirl() {
Girl girl=new Girl();
girl.setGid(3);
girl.setGname("女孩3");
girl.setAge(28);
girlDao.save(girl);
}
@Test
void updateboy() {
Boy boy=new Boy();
boy.setBname("男孩3");
boy.setBid(4);
boy.setAge(44);
Girl girl = girlDao.getById(5);
boy.setGirl(girl);
boyDao.save(boy);
}
@Test
//根据id查一条
void findgirl() {
Optional optional = girlDao.findById(3);
Girl girl = optional.get();
System.out.println(girl);
}
@Test
//查所有女孩
void findgirl2() {
List girls = girlDao.findAll();
System.out.println(girls);
}
@Test
//根据id查一条
void findboy() {
Optional optional = boyDao.findById(1);
Boy boy = optional.get();
System.out.println(boy);
}
@Test
//查询所有男孩
void findboy2() {
List boys = boyDao.findAll();
System.out.println(boys);
}
@Test
//只能删除没有boy的女孩
void deletegirl() {
girlDao.deleteById(3);
}
@Test
//删除男孩
void deleteboy() {
boyDao.deleteById(4);
}
}
添加事务的注解
使用过滤器 OpenSessionInViewFilter,springboot已经提供好了