JPA全称Java Persistence API,能够经过注解或者XML描述【对象-关系表】之间的映射关系,并将实体对象持久化到数据库中。JPA的出现主要是为了简化持久层开发以及整合ORM技术,结束Hibernate、TopLink、JDO等ORM框架各自为营的局面。java
JAP为咱们提供了ORM映射元数据,JPA的API,JPQL查询语言等,但JPA仅仅是一种规范,也就是说JPA仅仅定义了一些接口,而接口是须要实现才能工做的。因此底层须要某种实现,而Hibernate就是实现了JPA接口的ORM框架。mysql
Hibernate是Java中的对象关系映射解决方案。对象关系映射或ORM是将应用程序域模型对象映射到关系数据库表的编程技术。Hibernate是一个基于Java的ORM工具,它提供了一个框架,用于将应用程序域对象映射到关系数据库表。web
Hibernate提供了Java Persistence API的参考实现,使其成为具备松散耦合优点的ORM工具的绝佳选择。spring
Spring Data是Spring Framework的一部分。Spring Data存储库抽象的目标是显著减小为各类持久性存储实现数据访问层所需的代码量。sql
Spring Data JPA不是JPA提供者。它是一个库/框架,它在咱们的JPA提供程序(如Hibernate)的顶部添加了一个额外的抽象层。数据库
Hibernate是一个JPA实现,而Spring Data JPA是一个JPA数据访问抽象。Spring Data提供了GenericDao自定义实现的解决方案,它还能够经过方法名称约定表明您生成JPA查询。编程
Spring Data JPA不是一个实现或JPA提供者,它只是一个抽象,用于显著减小为各类持久性存储实现数据访问层所需的代码量。Spring Data JPA始终须要JPA提供程序,如Hibernate。bash
JPA Spring Data:致力于减小数据访问层(DAO)的开发量,开发者惟一要作的,就只是声明持久层的接口,其余都交给Spring Data JPA来完成。mybatis
框架怎么可能代替开发者实现业务逻辑呢?好比:当有一个 UserDao.findUserById() 这样一个方法声明,大体应该能判断出这是根据给定条件的 ID 查询出知足条件的 User 对象。Spring Data JPA 作的即是规范方法的名字,根据符合规范的名字来肯定方法须要实现什么样的逻辑。mvc
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
复制代码
@Configuration
// 借助spring data实现自动化的jpa repository,只需编写接口无需编写实现类
// 至关于xml配置的<jpa:repositories base-package="com.example.repository" />
// repositoryImplementationPostfix默认就是Impl
// entityManagerFactoryRef默认就是entityManagerFactory
// transactionManagerRef默认就是transactionManager
@EnableJpaRepositories(basePackages = {"com.wtj.repository"},
repositoryImplementationPostfix = "Impl",
entityManagerFactoryRef = "entityManagerFactory",
transactionManagerRef = "transactionManager")
// 启用事务管理器
@EnableTransactionManagement
//审计功能 用来自动填充@CreateDate等
@EnableJpaAuditing(dateTimeProviderRef = "dateTimeProvider")
public class SpringDataJpaConfig {
@Bean
public DateTimeProvider dateTimeProvider(DateTimeService dateTimeService) {
return dateTimeService::getNow;
}
@Bean
public JpaVendorAdapter jpaVendorAdapter() {
HibernateJpaVendorAdapter jpaVendorAdapter = new HibernateJpaVendorAdapter();
// 设置数据库类型(可以使用org.springframework.orm.jpa.vendor包下的Database枚举类)
jpaVendorAdapter.setDatabase(Database.MYSQL);
// 设置打印sql语句
jpaVendorAdapter.setShowSql(true);
// 设置不生成ddl语句
jpaVendorAdapter.setGenerateDdl(false);
// 设置hibernate方言
jpaVendorAdapter.setDatabasePlatform("org.hibernate.dialect.MySQL5Dialect");
return jpaVendorAdapter;
}
// 配置实体管理器工厂
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory(
DataSource dataSource, JpaVendorAdapter jpaVendorAdapter) {
LocalContainerEntityManagerFactoryBean emfb = new LocalContainerEntityManagerFactoryBean();
// 注入数据源
emfb.setDataSource(dataSource);
// 注入jpa厂商适配器
emfb.setJpaVendorAdapter(jpaVendorAdapter);
// 设置扫描基本包
emfb.setPackagesToScan("com.wtj.entity");
return emfb;
}
// 配置jpa事务管理器
@Bean
public PlatformTransactionManager transactionManager(EntityManagerFactory emf) {
JpaTransactionManager transactionManager = new JpaTransactionManager();
// 配置实体管理器工厂
transactionManager.setEntityManagerFactory(emf);
return transactionManager;
}
}
复制代码
启用web支持还须要在Spring MVC配置类上添加@EnableSpringDataWebSupport
注解
@Configuration
@ComponentScan(basePackages = {"com.wtj.controller"})
@EnableWebMvc // 启用spring mvc
@EnableSpringDataWebSupport // 启用springmvc对spring data的支持
public class WebMvcConfig extends WebMvcConfigurerAdapter {
}
复制代码
配置文件
server:
port: 20000
servlet:
context-path: /
spring:
datasource:
url: jdbc:mysql://localhost:3306/mytest1?useUnicode=true&serverTimezone=UTC&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true&useSSL=false
username: root
password: root
jpa:
database: MySQL
database-platform: org.hibernate.dialect.MySQL5InnoDBDialect
show-sql: true
hibernate:
ddl-auto: update
复制代码
ddl-auto 解释:
例子简单就不写service层了,直接在controller中调用。
建立实体类
@Data
@Entity
@Table(name = "account")
@ToString
public class Account {
@Id
@GenericGenerator(name = "idGenerator", strategy = "uuid")
@GeneratedValue(generator = "idGenerator")
private String id;
@Column(name = "username", unique = true, nullable = false, length = 64)
private String username;
@Column(name = "password", nullable = false, length = 64)
private String password;
@Column(name = "email", length = 64)
private String email;
}
复制代码
主键采用UUID策略
@GenericGenerator
是Hibernate提供的主键生成策略注解,注意下面的@GeneratedValue
(JPA注解)使用generator = "idGenerator"引用了上面的name = "idGenerator"主键生成策略。
JPA自带的几种主键生成策略
TABLE: 使用一个特定的数据库表格来保存主键。
SEQUENCE: 根据底层数据库的序列来生成主键,条件是数据库支持序列。这个值要与generator一块儿使用,generator 指定生成主键使用的生成器(多是orcale中本身编写的序列)。
IDENTITY: 主键由数据库自动生成(主要是支持自动增加的数据库,如mysql)。
AUTO: 主键由程序控制,也是GenerationType的默认值。
dao层
@Repository
public interface AccountRepository extends JpaRepository<Account,String> {
}
复制代码
controller层
@RestController
@RequestMapping(value = "/role")
public class AccountController {
@Autowired
private AccountRepository repository;
@PostMapping()
public Account save(@RequestBody Account account) {
return repository.save(account);
}
@DeleteMapping("/{id}")
public void delete(@PathVariable("id") String accountId) {
repository.deleteById(accountId);
}
@PutMapping("/{id}")
public Account update(@PathVariable("id") String accountId, @RequestBody Account account) {
account.setId(accountId);
return repository.saveAndFlush(account);
}
@GetMapping("/{id}")
public Account getAccountInfo(@PathVariable("id") String accountId) {
Optional<Account> optional = repository.findById(accountId);
return optional.orElseGet(Account::new);
}
}
复制代码
最后在数据库中造几条假数据进行crud就能够了。
Repository 接口概述:
public interface Repository<T, ID extends Serializable> { }
复制代码
Repository 的子接口:
基础的 Repository提供了最基本的数据访问功能,其几个子接口则扩展了一些功能。它们的继承关系以下:
按照 Spring Data的规范,查询方法以find | read | get
开头,涉及条件查询时,条件的属性用条件关键字链接,要注意的是:条件属性以首字母大写。 好比说如今要按照account的名称进行查询:
在AccountRepository接口中新增方法
@Repository
public interface AccountRepository extends JpaRepository<Account,String> {
Account findAccountByUsername(String username);
}
复制代码
controller中新增方法:
@GetMapping("/name/{username}")
public Account getAccountByName(@PathVariable("username") String userName){
Account account = repository.findAccountByUsername(userName);
return account;
}
复制代码
这样就能够根据名称进行查询了,固然你也可使用这种方法进行复杂查询,spring data jpa中支持的关键字以下:
有些时候spring data jpa提供的查询条件知足不了业务需求的时候,可使用自定义的sql来进行查询。
想要使用自定义sql须要使用@Query
注解,@Query注解使用起来很简单,默认的属性是value,就是当前写的SQL语句,有时会用到nativeQuery属性,这个属性是用来标记当前的SQL是本地SQL,仍是符合JPA语法规范的SQL。这里须要解释一下本地SQL和JPA语法规范的SQL区别。
JPA很好的一个特性就是用JPA语法规范写的SQL,会根据当前系统使用的数据库类型改变生成的SQL语法,兼容数据库类型的切换,如以前使用的是MySQL,如今换成Oracle,因为不一样类型的数据库,SQL语法会有区别,若是使用的是mybatis,就须要手动去改SQL兼容Oracle,而JPA就不用啦,无缝对接。
很大的时候使用JPA感受都是为了兼容后期可能会有数据库切换的问题,因此在使用JPA的时候,不要去使用本地SQL,这就违背了使用JPA的初衷,让nativeQuery属性保持默认值就能够啦!
AccountRepository中新增方法
@Query("select a from Account a where a.username = :username")
Account findAccountByName(@Param("username")String name);
@Query("select a from Account a where a.email = ?1")
Account findAccountByEmail(String email);
@Query(value = "select * from account where username = ?1",nativeQuery = true)
Account getAccount(String username);
复制代码
@GetMapping("/sql/{username}")
public Account findAccountByName(@PathVariable("username") String userName){
Account account = repository.findAccountByName(userName);
return account;
}
@GetMapping("/email/{email}")
public Account findAccountByEmail(@PathVariable("email") String email){
Account account = repository.findAccountByEmail(email);
return account;
}
@GetMapping("/username/{username}")
public Account getAccount(@PathVariable("username") String username){
Account account = repository.getAccount(username);
return account;
}
复制代码
最后经过请求就能够得到数据而且在控制台能够看到打印出的响应的sql。
当自定义sql涉及到删除,修改,插入的操做的时候须要加上@Modifying
注解。注明当前方法是修改操做。