首先來講JPA是一個持久化規範,也就是說當咱們用jpa的時候咱們不須要去選面向hibernate的api編程了,這樣就大大下降了偶和度了html
JPA是一種規範,那麼它的編程有哪些要求呢?
引入下載的jar包導入lib文件夾,而後咱們的在src下面加上一個META-INF目錄在該文件夾下面加上一個persistence.xml文件,這個文件的規範寫法java
<?xml version="1.0"?> <persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd" version="1.0"> <persistence-unit name="jun" transaction-type="RESOURCE_LOCAL"> <provider>org.hibernate.ejb.HibernatePersistence</provider> <properties> <property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5Dialect"/> <property name="hibernate.connection.driver_class" value="org.gjt.mm.mysql.Driver"/> <property name="hibernate.connection.username" value="root"/> <property name="hibernate.connection.password" value="root"/> <property name="hibernate.connection.url" value="jdbc:mysql:///jpa??autoReconnect=true&useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false"/> <property name="hibernate.max_fetch_depth" value="3"/> <property name="hibernate.hbm2ddl.auto" value="update"/> <property name="hibernate.jdbc.fetch_size" value="18"/> <property name="hibernate.jdbc.batch_size" value="10"/> <property name="hibernate.show_sql" value="true"/> <property name="hibernate.format_sql" value="false"/> </properties> </persistence-unit> </persistence>
這個文件中的寫話咱們能夠再hibernate的jpa實現包裏面找到對應的例子,這裏我是使用的是hibernate來實現JPA實現,上面的配置也都和heibernate差不太多值得注意的:mysql
<persistence-unit name="jun" transaction-type="RESOURCE_LOCAL">
Persion.javaspring
@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 // }
Test.javasql
@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(); }
然而EntityManager就至關於Hibernate中的Session。數據庫
jun是在persistence.xml中持久化單元名稱編程
其中EntityManager中的幾種操做數據庫方法有
Persist(),find(),getReference(),merge(),remove()這裏我就列出幾種常見的api
getReference它會查找一個代理對象,當訪問它的屬性的時候它纔會向數據庫操做緩存
new一個實體的時候它所處於的狀態tomcat
這個狀態很是重要,當一個實體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處於的狀態
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 而後遍歷它 */ List<Person> list = 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(); }
@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 Set<OrderItem> items = new HashSet<OrderItem>(); // 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 Set<Teacher> teachers = new HashSet<Teacher>(); public Student() {} public Student(String name) { this.name = name; } }
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 Set<Student> students = new HashSet<Student>(); 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條規則
那麼咱們在主體類裏面用這個主鍵類作爲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(); }
使用步驟相似上面介紹,關鍵是要理解一對1、一對多、多對1、多對多的關聯關係
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency>
# maven打包 clean compile package spring: # 熱重啓 devtools: restart: enabled: true # 數據源 datasource: driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql:///qnzf?autoReconnect=true&useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false username: root password: # JPA配置 jpa: show-sql: true hibernate: naming: physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl ddl-auto: update # tomcat server: port: 8080 tomcat: Uri-encoding: UTF-8
LED.java
@Entity @Table(name = "tbl_led") public class LED { public LED() { super(); } // 指定id @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; // 惟一鍵 @Column(unique = true) private Integer pin; // LED鏈接的針腳位 // 單向一對一 @OneToOne() @JoinColumn(name = "ledtype_id") private LEDType ledType; }
LEDRepository.java
public interface LEDRepository extends JpaRepository<LED, Long> { }
@Autowired private LEDPowerRepository ledPowerRepository;
Spring For All 社區 Spring Data JPA 從入門到進階系列教程
SpringBoot實戰SpringDataJPA
使用 Spring Data JPA 簡化 JPA 開發