什麼是JDBC知道吧?數據庫有Mysql,SQL Server,Oracle,Java爲了統一的去操做創建鏈接,JDBC出現了,有了JDBC,加載註冊不一樣的數據庫驅動就完事了。mysql
可是,JDBC好繁瑣的啊,每次都要寫一堆,煩人,因此一些框架出現了,例如Hibernate,TopLink,可是這些框架也是各類各樣的,我每次使用都要按照各自的框架來寫,這不行,爲了省事,JPA出現了spring
JPA是規範 JPA不是框架,沒有實現的方法,就是規範,提供了一些API接口,大家這些hibernate,TopLink框架啥的,遵循個人JPA規範就成sql
順便一提,JPA是Hibernate做者搞出來的,因此JPA和Hibernate同樣,不須要你寫SQL,有時候必須本身寫SQL可使用JPQL數據庫
PS:EJB有三種,分別是會話Bean(Session Bean),實體Bean(Entity Bean)和消息驅動Bean(MessageDriven Bean)。在EJB3.0推出之後,實體Bean被單獨分了出來,造成了新的規範JPA。性能優化
想要使用JPA,就要引入一些配置,個人項目是SpringBoot,其餘的框架也行,引入了三個,JPA,Hibernate,MySQL服務器
<!--JPA,我用的是SpringBoot的--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> <version>2.1.3.RELEASE</version> </dependency> <!--Hibernate,說了JPA只是一個規範,咱們使用Hibernate做爲實現--> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <version>5.4.1.Final</version> </dependency> <!--數據庫不能少--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency>
引入的配置完了,接下來是對JPA的一些配置,不能不寫,不寫不成功session
### Java Persistence Api -- Spring jpa 的配置信息 #其實這個hibernate.hbm2ddl.auto參數的做用主要用於:自動建立|更新|驗證數據庫表結構,有四個值 #create: 每次加載hibernate時都會刪除上一次的生成的表,而後根據你的model類再從新來生成新表,哪怕兩次沒有任何改變也要這樣執行,這就是致使數據庫表數據丟失的一個重要緣由。 #create-drop :每次加載hibernate時根據model類生成表,可是sessionFactory一關閉,表就自動刪除。 #update:最經常使用的屬性,第一次加載hibernate時根據model類會自動創建起表的結構(前提是先創建好數據庫),之後加載hibernate時根據 model類自動更新表結構,即便表結構改變了但表中的行仍然存在不會刪除之前的行。要注意的是當部署到服務器後,表結構是不會被立刻創建起來的,是要等 應用第一次運行起來後纔會。 #validate :每次加載hibernate時,驗證建立數據庫表結構,只會和數據庫中的表進行比較,不會建立新表,可是會插入新值。 #dialect 主要是指定生成表名的存儲引擎爲InneoDB #show-sql 是否打印出自動生產的SQL,方便調試的時候查看 spring.jpa.properties.hibernate.hbm2ddl.auto=update spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect spring.jpa.show-sql= true
這個是application.properties裏面關於JPA的配置,數據庫配置就不貼了,JPA配置的講解見註釋app
package com.cache.entity; import javax.persistence.*; @Entity @Table(name="product") public class Product { @Id @GeneratedValue @Column(name="id") private Integer id; private String name; private Double price; private String type; public Product() { } public Product(Integer id, String name, Double price, String type) { this.id = id; this.name = name; this.price = price; this.type = type; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Double getPrice() { return price; } public void setPrice(Double price) { this.price = price; } public String getType() { return type; } public void setType(String type) { this.type = type; } @Override public String toString() { return "product{" + "id=" + id + ", name='" + name + '\'' + ", price=" + price + ", type='" + type + '\'' + '}'; } }
這個爲啥叫Entity Bean類呢?我講一下,普通的Java Bean類加上@Entity註解以後就變成了Entity Bean類,這個Entity Bean的意思就是這個類能夠映射到數據庫框架
講解一下上面Entity Bean裏面的註解是什麼意思
@Entity : 這個註解表明這個Userinfo是一個實體類,也就是說,當你建立實體類時,須要加上@Entity 標誌着此類是實體類;
@Table(name=」userinfos」) :這個註解表明對應表的名稱,userinfos就是利用jpa要生成的表名稱;
@id :代表此屬性是主鍵;
@GeneratedValue :表示的是 主鍵生成策略,默認主鍵是自增加的,固然你也可使用 uuid
@Column :代表此屬性在數據庫中對應的字段,若是實體中的屬性與數據庫中的字段同樣,能夠省略不寫。還有兩個註解我沒使用,能夠了解一下:
@Transient:Entity Bean的屬性或字段加上這個註解,該字段便不會映射到數據庫表
@Temporal:也是在Entity Bean的屬性或字段上加的,這個是對Date時間類型的精度的一個選擇,例如生日我就想精確到年月日就好了,下單時間我卻想精確到時分秒,這個時候就可使用這個,有Date,TIMESTAMP,TIME這三種精度
怎麼樣?爽不爽?沒有JDBC的繁瑣,我僅僅是寫了一個Entity Bean實體類,我就和數據庫進行映射關係了,內存中的實體類對象映射到數據庫了,這也叫持久化。
持久化是位於 JDBC 之上的一個更高層抽象。持久層將對象映射到數據庫,以便在查詢、 裝載、 更新, 或刪除對象的時候, 無須使用像 JDBC 那樣繁瑣的 API。
使用Entity Bean實體類,咱們已經映射出了一個數據庫表,如今要存儲數據了,咱們須要新建一個接口
package com.cache.repository; import com.cache.entity.Product; 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; public interface ProductRepository extends JpaRepository<Product,Integer> { //因爲JPA沒有更新方法,因此須要本身寫更新方法,我這裏只寫一個更新name的方法,若是想更新所有,能夠第一個參數寫類 @Transactional @Modifying @Query("update Product set name=?1 where id=?2") int updateNameById(String name,Integer id); }
我來好好的講解一下這個接口,首先ProductRepository這個接口繼承了
JpaRepository這個類,這個類裏面有JPA的操做方法,因此只要咱們的接口繼承了這個類,咱們也就有方法能夠調用了,不須要本身寫。
可是,JPA只有正刪查,沒有更改的方法,因此咱們能夠在接口裏面本身寫,我就寫了一個更新Product實體類的name屬性的方法
@Transactional 開啓事務
@Modifying 修改方法專用註解
這兩個註解
@Query(「update Product set name=?1 where id=?2」)
此註解書寫JPql語句 其中 Product 是實體類名,name和 id 是實體類的屬性名,?1表明是第一個參數 ?2是第二個參數
注意:JPql裏面必須是實體類的類名,可不是你的數據庫表名,若是寫錯了會報 XXX is not mapped 錯誤 |
在咱們的ProductRepository接口上新建一個測試類,這個步驟不會的就太菜了
我直接貼出代碼了,我已經寫好了增刪改查的代碼了
package com.cache.repository; import com.cache.entity.Product; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; import java.util.List; import java.util.Optional; @RunWith(SpringRunner.class) @SpringBootTest public class ProductRepositoryTest { @Autowired private ProductRepository productRepository; //增長數據 @Test public void save(){ Product product=new Product(); product.setId(1); product.setName("魅族16s"); product.setPrice(2899.0); product.setType("手機類"); //調用save方法保存一個對象的時候,會返回該對象 Product p=productRepository.save(product); //斷言返回對象的值就是咱們存進去的值 Assert.assertEquals(p.getName(),"魅族16s"); } //刪除一個數據 @Test public void delete(){ productRepository.deleteById(1); } //更新,使用的是咱們本身寫的更新name方法 @Test public void update(){ productRepository.updateNameById("魅族16s Plus",2); } //查找數據 @Test public void selectAll(){ List<Product> lists=productRepository.findAll(); for (Product product : lists) { System.out.println(product); } } @Test public void selectOne(){ Optional<Product> product=productRepository.findById(2); System.out.println(product); } }
我都執行了一遍,都是ok的
因爲JPA是Hibernate實現的,因此不須要咱們寫SQL,都是自動的(除了JPQL)
簡單的說,JPA對比Mybatis,仍是簡單的不少,沒有配置文件了,不須要本身寫SQL了,連操做方法都有JpaRepository類幫咱們寫好了
若是不是須要性能優化什麼的,簡單的使用來講,仍是JPA好用