String Data JPA 学习笔记
来源:SegmentFault
时间:2023-02-24 20:54:56 157浏览 收藏
在数据库实战开发的过程中,我们经常会遇到一些这样那样的问题,然后要卡好半天,等问题解决了才发现原来一些细节知识点还是没有掌握好。今天golang学习网就整理分享《String Data JPA 学习笔记》,聊聊MySQL、Java、Oracle、spring,希望可以帮助到正在努力赚钱的你。
说明
首先来说JPA是一个持久化规范,也就是说当我们用jpa的时候我们不需要去选面向hibernate的api编程了,这样就大大降低了偶和度了
引入
JPA是一种规范,那么它的编程有哪些要求呢?
引入下载的jar包导入lib文件夹,然后我们的在src下面加上一个META-INF目录在该文件夹下面加上一个persistence.xml文件,这个文件的规范写法
persistence.xml
org.hibernate.ejb.HibernatePersistence
这个文件中的写话我们可以再hibernate的jpa实现包里面找到对应的例子,这里我是使用的是hibernate来实现JPA实现,上面的配置也都和heibernate差不太多值得注意的:
- Persistence-unit持久性化单元,我们可以随便命名但是在后面回到他的,通过它来找到相关的配置信息
- transaction-type 是指事物的类型,在通常情况下我们是本地的,但是当我们遇到两个数据库保存的时候 我们会到到JTA事物来控制事务,也就是二次提交
实体类来映射数据表
Persion.java
@Entity //就是告诉JPA我是一个实体bean @Table(name="t_person")//作为修改表名,默认情况是类名 public class Person { /** * GenerationType.AUTO它会根据数据库方言来选择正确的生成策略 * 默认情况下就是AUTO */ @Id//映射主键 @GeneratedValue(strategy=GenerationType.AUTO) private Integer id; // 映射一列到数据库中 length是指字段的长度 // nullable是指是否为空,默认情况是空 // 当我们不想让类字段名与数据库名一样的时候用到的 @Column(length=10,nullable=false,name="personname") private String name; // 映射日期类型TemporalType有好几种映射方式 // 我们可以根据自己的需求选择正确的映射方式 @Temporal(TemporalType.DATE) @Column(nullable=false) private Date birthday; // 用枚举类型来映射性别EnumType有好几种映射方式 // 这里使用的是枚举的String类型,我们也一个选择枚举的索引 @Enumerated(EnumType.STRING) @Column(nullable=false,length=5) private Sex sex = Sex.MEN; // 对应大文本和图片就是二进制 @Lob private String info; // 支持延迟加载(减少内存的消耗) @Lob @Basic(fetch=FetchType.LAZY) private Byte[] image; // 不想这个字段与数据库表映射 @Transient private String imagepath; // 版本标识 防止脏读 @Version private Integer version; // get set // }
利用jpa来操作数据库
Test.java
@Test public void testSave() { /** * jun是在persistence.xml中持久化单元名称 */ EntityManagerFactory factory = Persistence.createEntityManagerFactory("jun"); //--->>SessionFactory-->>session-->>begin EntityManager em = factory.createEntityManager(); em.getTransaction().begin();//开启事物 Person person = new Person("刘文军"); person.setBirthday(new Date()); em.persist(person); System.out.println("----->>"+person.getSex().getName()); em.getTransaction().commit(); em.close(); factory.close(); }
- 这里我们EntityManagerFactory就相当于Hibernate中的SessionFactory,
然而EntityManager就相当于Hibernate中的Session。
- 在JPA中我们获得它的方式是Persistence.createEntityManagerFactory("jun");
jun是在persistence.xml中持久化单元名称
- EntityManager em = factory.createEntityManager();
其中EntityManager中的几种操作数据库方法有
Persist(),find(),getReference(),merge(),remove()这里我就列出几种常见的
- 这里说有的getReference()就相当于Hibernate中的Load() 支持Lazy加载,
getReference它会查找一个代理对象,当访问它的属性的时候它才会向数据库操作
- 但是值得注意的这个必须确保Session是打开状态
实体bean的几种状态
一、新建状态
new一个实体的时候它所处于的状态
二、托管状态
这个状态非常重要,当一个实体bean是托管状态的时候我们修改它的属性值得话,即使我们没有用到hibernate中的相关方法操作数据库,她也会同步到数据库里的,托管就是从数据库里面查询到的一个对象,记住,托管状态必须的和事物关联上来
em.getTransaction().begin(); person.setName("小刘"); em.getTransaction().commit(); em.close(); factory.close();
三、游离状态
当我们使用EntityManager中的clear()方法的时候,它会把事物管理器中的所有实体变成游离状态,
处在游离状态的实体bean,我们修改它的属性它不会同步到数据库中的
em.getTransaction().begin(); em.clear(); // 把实体管理器中的所有实体都变成游离状态 person.setName("老刘"); em.merge(person); em.getTransaction().commit(); em.close(); factory.close();
四、关闭状态
就是当我们把Session关闭的时候,实体bean处于的状态
JPA中使用EJQL语句
查询
public void query() { /** * jun是在persistence.xml中持久化单元名称 */ EntityManagerFactory factory=Persistence.createEntityManagerFactory("jun"); //--->>SessionFactory-->>session-->>begin EntityManager em = factory.createEntityManager(); Query query = em.createQuery("select o from Person o where o.id=?1"); query.setParameter(1, 2); // /** * Person person = (Person)query.getSingleResult(); * 这个就相当于Hibernate中的uniqueResult(); * 如果没有查询到数据的话会出错的,所有我们一般不这样做 * 我们先得到List 然后遍历它 */ Listlist = query.getResultList(); for(Person person : list) System.out.println("---------->>" + person.getName()); query = em.createQuery("select count(o) from Person o "); Long count = (Long)query.getSingleResult(); System.out.println("---------->>" + count); em.close(); factory.close(); }
删除查询(记得要开启事物)
public void deletequery() { /** * jun是在persistence.xml中持久化单元名称 */ EntityManagerFactory factory = Persistence.createEntityManagerFactory("jun"); EntityManager em = factory.createEntityManager(); em.getTransaction().begin(); Query query = em.createQuery("delete from Person o where o.id=?1"); query.setParameter(1, 2); query.executeUpdate(); em.getTransaction().commit(); em.close(); factory.close(); }
修改查询(记得要开启事物)
public void updatequery() { /** * jun是在persistence.xml中持久化单元名称 */ EntityManagerFactory factory = Persistence.createEntityManagerFactory("jun"); EntityManager em = factory.createEntityManager(); em.getTransaction().begin(); Query query = em.createQuery("update from Person o set o.name=:name where o.id=:id"); query.setParameter("name", "小刘"); query.setParameter("id", 3); query.executeUpdate(); em.getTransaction().commit(); em.close(); factory.close(); }
刷新方法
public void testgetPerson() { /** * jun是在persistence.xml中持久化单元名称 */ EntityManagerFactory factory = Persistence.createEntityManagerFactory("jun"); //--->>SessionFactory-->>session-->>begin EntityManager em = factory.createEntityManager(); Person person = em.find(Person.class, 1); /** * 1分钟内 * 比方说这里有人直接操作数据库改了数据,我们如何来得到person呢 * 有人说我们可以再执行一下find方法,这个事不可以的,因为你再次 * 执行find方法的时候EntityManager会中一级缓存中取得id是1的 * Person数据,也就是说不能得到最新的数据,那么如果我们想得到最 * 新的数据怎么办呢?JPA帮我们做了一个刷新的方法em.refresh(person); * 通过它我们就可以得到最新的数据了 */ em.refresh(person); System.out.println("----->>"+person.getName()); em.close(); factory.close(); }
JPA中实现表间关联关系
一的多
@Entity @Table(name="t_order") public class Order { @Id @Column(length=200) private String orderid; @Column(nullable=false) private Float amount = 0f; /** * cascade=CascadeType.REFRESH设置级联刷新 * CascadeType.PERSIST设置级联保存 * CascadeType.MERGE设置级联更新 * CascadeType.REMOVE设置级联删除 * CascadeType.ALL设置四种级联 * 这四种级联都是对应的四种方法才能起作用PERSIST(),MERGE(),REMOVE(),REFRESH() * fetch=FetchType.LAZY支持LAzy加载,只有用到该属性的时候才会读集合数据 * 注意这时我们必须保持EntityManager是开着的,默认是延迟加载 * mappedBy="order"指定OrderItem类里面的order这个属性来维护关系 */ @OneToMany(cascade={CascadeType.ALL}, fetch=FetchType.LAZY, mappedBy="order") private Setitems = new HashSet (); // get set // }
为了我们添加Set集合方便我们通常的情况下我们的写一个添加Set的方法
public void addOrderItem(OrderItem orderItem) { orderItem.setOrder(this);//this就是Order items.add(orderItem); }
多的一
@Entity @Table(name="t_orderitem") public class OrderItem { @Id @GeneratedValue private Integer id; @Column(length=40,nullable=false) private String productName; @Column(nullable=false) private Float sellPrice = 0f; /** * optional=false指定该字段不能空 * @JoinColumn(name="order_id")指明关联关系的子段名 * 即定义外键的名称 * * */ @ManyToOne(cascade={CascadeType.MERGE,CascadeType.REFRESH},optional=false) @JoinColumn(name="order_id") private Order order; // get set // }
测试
public void testCreate() { EntityManagerFactory factory = Persistence.createEntityManagerFactory("jun"); EntityManager em = factory.createEntityManager(); em.getTransaction().begin(); Order order = new Order(); order.setAmount(598f); order.setOrderid(UUID.randomUUID().toString()); OrderItem orderItem1 = new OrderItem(); orderItem1.setProductName("篮球"); orderItem1.setSellPrice(256f); order.addOrderItem(orderItem1); OrderItem orderItem2 = new OrderItem(); orderItem2.setProductName("女人"); orderItem2.setSellPrice(800000f); order.addOrderItem(orderItem2); em.persist(order); em.getTransaction().commit(); em.close(); factory.close(); }
这里我们并没有保存orderIterm
但是我们在数据库中依然能看到orderIterm的数据
保存到数据库里面了,这里就是设置级联保存的缘故
CascadeType.PERSIST设置级联保存
一对一
Person.java
@Entity @Table(name="t_person") public class Person { @Id @GeneratedValue private Integer id; @Column(length=10,nullable=false) private String name; @OneToOne(optional=false,cascade={CascadeType.ALL}) @JoinColumn(name="idcard_id") private IDCard idCard; public Person() {} public Person(String name) { this.name = name; } }
IDCard.java
@Entity @Table(name="t_idcard") public class IDCard { @Id @GeneratedValue private Integer id; @Column(length=18,nullable=false) private String cardno ; @OneToOne(mappedBy="idCard", cascade={CascadeType.REFRESH,CascadeType.PERSIST,CascadeType.MERGE}) private Person person; public IDCard() {} public IDCard(String cardno) { this.cardno = cardno; } }
测试
public void testCreateTable() { EntityManagerFactory factory = Persistence.createEntityManagerFactory("jun"); EntityManager em = factory.createEntityManager(); em.getTransaction().begin(); Person person = new Person("小刘"); IDCard idCard = new IDCard("411521198409131915"); idCard.setPerson(person); person.setIdCard(idCard); em.persist(person); em.getTransaction().commit(); em.close(); factory.close(); }
多对多
Student.java
@Entity @Table(name="t_student") public class Student { @Id @GeneratedValue private Integer id; @Column(length=10,nullable=false) private String name; /** * @JoinTable(name="t_stu_tea", joinColumns=@JoinColumn(name="student_id"), inverseJoinColumns=@JoinColumn(name="teacher_id")) 创建中间表来维护两个表的关系 * joinColumns=@JoinColumn(name="student_id")定义维护端在中间表中的关联字段 * inverseJoinColumns=@JoinColumn(name="teacher_id")定义被维护端在中间表中的关联字段 * */ @ManyToMany(cascade=CascadeType.REFRESH) @JoinTable(name="t_stu_tea", joinColumns=@JoinColumn(name="student_id"), inverseJoinColumns=@JoinColumn(name="teacher_id")) private Setteachers = new HashSet (); public Student() {} public Student(String name) { this.name = name; } }
- 我们通常把set集合方法重写
public void addTeacher(Teacher teacher) { this.teachers.add(teacher); } public void removeTeacher(Teacher teacher) { if(this.teachers.contains(teacher)) { this.teachers.remove(teacher); } }
Teacher.java
@Entity @Table(name="t_teacher") public class Teacher { @Id @GeneratedValue private Integer id; @Column(length=12,nullable=false) private String name; @ManyToMany(cascade=CascadeType.REFRESH,mappedBy="teachers") private Setstudents = new HashSet (); public Teacher() {} public Teacher(String name) { this.name = name; } }
测试
@Test public void testCreateTable() { EntityManagerFactory factory = Persistence.createEntityManagerFactory("jun"); EntityManager em = factory.createEntityManager(); em.getTransaction().begin(); Student student = new Student("小刘"); Teacher teacher = new Teacher("肖老师"); em.persist(student); em.persist(teacher); em.getTransaction().commit(); em.close(); factory.close(); } /** * 建立学生跟老师的关系 */ @Test public void buildTS() { EntityManagerFactory factory = Persistence.createEntityManagerFactory("jun"); EntityManager em = factory.createEntityManager(); em.getTransaction().begin(); Student student = em.find(Student.class, 1); student.addTeacher(em.getReference(Teacher.class, 1)); em.getTransaction().commit(); em.close(); factory.close(); } /** * 解除学生跟老师的关系 */ @Test public void deleteTS() { EntityManagerFactory factory = Persistence.createEntityManagerFactory("jun"); EntityManager em = factory.createEntityManager(); em.getTransaction().begin(); Student student = em.find(Student.class, 1); student.removeTeacher(em.getReference(Teacher.class, 1)); em.getTransaction().commit(); em.close(); factory.close(); } /** * 删除老师 */ @Test public void deleteTeacher() { EntityManagerFactory factory = Persistence.createEntityManagerFactory("jun"); EntityManager em = factory.createEntityManager(); em.getTransaction().begin(); /** * 删除老师的时候一定的解除掉老师和学生的关系 */ Student student = em.find(Student.class, 1); student.removeTeacher(em.getReference(Teacher.class, 1)); em.remove(em.getReference(Teacher.class, 1)); em.getTransaction().commit(); em.close(); factory.close(); } /** *删除学生 */ @Test public void deleteStudent() { EntityManagerFactory factory = Persistence.createEntityManagerFactory("jun"); EntityManager em = factory.createEntityManager(); em.getTransaction().begin(); /** * 这个为什么不需要解除关系呢,主要是因为学生这一段是维护端 */ Student student = em.find(Student.class, 1); em.remove(student); em.getTransaction().commit(); em.close(); factory.close(); }
联合主键
我们单独写一个类作为主键,但是这个类的要满足3条规则
- 它必须实现Serializable接口
- 它必须重写字段的hashCode()和equals()方法
- 要在类上表明@Embeddable,这个注解的意思就是让它的属性在AirLine也正常做属性
那么我们在主体类里面用这个主键类做为id,在id上面加上@EmbeddedId表明就是用主键类的属性作为主键,并映射到数据库表中
AirLine.java
@Entity @Table(name="t_airline") public class AirLine { @EmbeddedId private AirLinePK id; @Column(length=10,nullable=false) private String name; }
AirLinePK.java
@Embeddable public class AirLinePK implements Serializable{ // 序列UID private static final long serialVersionUID = -7125628704970675246L; @Column(length=20) private String startLine; @Column(length=20) private String endLine; // 注意这里一定的时间他HashCode()和equals()方法 }
测试
public void testPK() { EntityManagerFactory factory = Persistence.createEntityManagerFactory("jun"); EntityManager em = factory.createEntityManager(); em.getTransaction().begin(); AirLine airLine = new AirLine("PEK","SHG","北京飞往上海"); em.persist(airLine); em.getTransaction().commit(); em.close(); factory.close(); }
使用Spring Boot
配置
使用步骤类似上面介绍,关键是要理解一对一、一对多、多对一、多对多的关联关系
org.springframework.boot Spring For All 社区 Spring Data JPA 从入门到进阶系列教程
SpringBoot实战SpringDataJPA
使用 Spring Data JPA 简化 JPA 开发好了,本文到此结束,带大家了解了《String Data JPA 学习笔记》,希望本文对你有所帮助!关注golang学习网公众号,给大家分享更多数据库知识!
-
499 收藏
-
244 收藏
-
235 收藏
-
157 收藏
-
101 收藏
-
475 收藏
-
266 收藏
-
273 收藏
-
283 收藏
-
210 收藏
-
371 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 542次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 507次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 497次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 484次学习