什么是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好用