SpringBoot整合Jpa
首先需要向大伙介绍一下Jpa,Jpa(Java Persistence API)Java持久化API,它是一套ORM规范(Object Relational Mapping)框架表示对象关系映射,而不是具体的实现,Jpa的江湖地位类似于JDBC,只提供规范,所有的数据库厂商提供实现(即具体的数据库驱动),java方面ORM框架我们熟悉的可能主要是Hibernate。
pring Boot中使用的Jpa实际上是Spring Data Jpa,Spring Data是Spring家族的一个子项目,用于简化SQL和NoSQL的访问,在Spring Data中,只要你的方法名称符合规范,它就知道你想干嘛,不需要自己再去写SQL
1.单数据源
创建springboot项目,引入下面依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.28</version>
<scope>runtime</scope>
</dependency>
工程创建完成后,只需要在application.properties中进行数据库基本信息配置以及Jpa基本配置,如下:
# 数据库的基本配置
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.url=jdbc:mysql:///test01?useUnicode=true&characterEncoding=UTF-8
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
# JPA配置
spring.jpa.database=mysql
# 在控制台打印SQL
spring.jpa.show-sql=true
# 数据库平台
spring.jpa.database-platform=mysql
# 每次启动项目时,数据库初始化策略
spring.jpa.hibernate.ddl-auto=update
# 指定默认的存储引擎为InnoDB
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL57Dialect
注意:最后一行配置,默认情况下,自动创建表的时候会使用MyISAM做表的引擎,如果配置了数据库方言为MySQL57Dialect,则使用InnoDB做表的引擎。
使用ORM框架我们不必再去创建表,框架会自动根据当前项目中的实体类创建相应的数据表。因此,我这里首先创建一个User对象,如下:
@Entity(name = "t_user")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column(name = "name")
private String username;
private String address;
//省略getter/setter
}
首先@Entity注解表示这是一个实体类,那么在项目启动时会自动针对该类生成一张表,默认的表名为类名,@Entity注解的name属性表示自定义生成的表名。@Id注解表示这个字段是一个id,@GeneratedValue注解表示主键的自增长策略,对于类中的其他属性,默认都会根据属性名在表中生成相应的字段,字段名和属性名相同,如果开发者想要对字段进行定制,可以使用@Column注解,去配置字段的名称,长度,是否为空等等。
启动Spring Boot项目,就会发现数据库中多了一个名为t_user的表了。
针对该表的操作,则需要我们提供一个Repository,如下
public interface UserDao extends JpaRepository<User,Integer> {
List<User> getUserByAddressEqualsAndIdLessThanEqual(String address, Integer id);
@Query(value = "select * from t_user where id=(select max(id) from t_user)",nativeQuery = true)
User maxIdUser();
}
这里,自定义UserDao接口继承自JpaRepository,JpaRepository提供了一些基本的数据操作方法,例如保存,更新,删除,分页查询等,开发者也可以在接口中自己声明相关的方法,只需要方法名称符合规范即可,在Spring Data中,只要按照既定的规范命名方法,Spring Data Jpa就知道你想干嘛,这样就不用写SQL了,规范可以参考下图
自定义查询SQL,使用@Query注解,在注解中写自己的SQL,默认使用的查询语言不是SQL,而是JPQL,这是一种数据库平台无关的面向对象的查询语言,有点定位类似于Hibernate中的HQL,在@Query注解中设置nativeQuery属性为true则表示使用原生查询,即大伙所熟悉的SQL。上面代码中的只是一个很简单的例子,还有其他一些点,例如如果这个方法中的SQL涉及到数据操作,则需要使用@Modifying注解。
定义完Dao之后,接下来就可以将UserDao注入到Controller中进行测试了(这里为了省事,就没有提供Service了,直接将UserDao注入到Controller中)。
@RestController
public class UserController {
@Autowired
UserDao userDao;
@PostMapping("/")
public void addUser() {
User user = new User();
user.setId(1);
user.setUsername("张三");
user.setAddress("深圳");
userDao.save(user);
}
@DeleteMapping("/")
public void deleteById() {
userDao.deleteById(1);
}
@PutMapping("/")
public void updateUser() {
User user = userDao.getOne(1);
user.setUsername("李四");
userDao.flush();
}
@GetMapping("/test1")
public void test1() {
List<User> all = userDao.findAll();
System.out.println(all);
}
@GetMapping("/test2")
public void test2() {
List<User> list = userDao.getUserByAddressEqualsAndIdLessThanEqual("广州", 2);
System.out.println(list);
}
@GetMapping("/test3")
public void test3() {
User user = userDao.maxIdUser();
System.out.println(user);
}
}
如此之后,即可查询到需要的数据。
2.多数据源
首先我们创建springboot项目,创建完成后,添加Druid依赖,要使用专为Spring Boot打造的Druid,大伙可能发现了,如果整合多数据源一定要使用这个依赖,因为这个依赖中才有DruidDataSourceBuilder,最后还要记得锁定数据库依赖的版本,因为可能大部分人用的还是5.x的MySQL而不是8.x。完整依赖如下:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.28</version>
<scope>runtime</scope>
</dependency>
我们首先来配置多数据源基本信息以及DataSource,首先在application.properties中添加如下配置信息
# 数据源一
spring.datasource.one.username=root
spring.datasource.one.password=root
spring.datasource.one.url=jdbc:mysql:///test01?useUnicode=true&characterEncoding=UTF-8
spring.datasource.one.type=com.alibaba.druid.pool.DruidDataSource
# 数据源二
spring.datasource.two.username=root
spring.datasource.two.password=root
spring.datasource.two.url=jdbc:mysql:///test02?useUnicode=true&characterEncoding=UTF-8
spring.datasource.two.type=com.alibaba.druid.pool.DruidDataSource
# Jpa配置
spring.jpa.properties.database=mysql
spring.jpa.properties.show-sql=true
spring.jpa.properties.database-platform=mysql
spring.jpa.properties.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL57Dialect
这里Jpa的配置和单数据源相比key中多了properties,多数据源的配置和前文一致,然后接下来配置两个DataSource,如下
@Configuration
public class DataSourceConfig {
@Bean
@ConfigurationProperties(prefix = "spring.datasource.one")
@Primary
DataSource dsOne() {
return DruidDataSourceBuilder.create().build();
}
@Bean
@ConfigurationProperties(prefix = "spring.datasource.two")
DataSource dsTwo() {
return DruidDataSourceBuilder.create().build();
}
}
这里的配置和前文的多数据源配置基本一致,但是注意多了一个在Spring中使用较少的注解@Primary,这个注解一定不能少,否则在项目启动时会出错,@Primary表示当某一个类存在多个实例时,优先使用哪个实例。
接下来配置Jpa的基本信息,这里两个数据源,我分别在两个类中来配置,先来看第一个配置:
@Configuration
@EnableJpaRepositories(basePackages = "com.cp.jpa.dao",entityManagerFactoryRef = "localContainerEntityManagerFactoryBeanOne",transactionManagerRef = "platformTransactionManagerOne")
public class JpaConfigOne {
@Autowired
@Qualifier(value = "dsOne")
DataSource dsOne;
@Autowired
JpaProperties jpaProperties;
@Bean
@Primary
LocalContainerEntityManagerFactoryBean localContainerEntityManagerFactoryBeanOne(EntityManagerFactoryBuilder builder) {
return builder.dataSource(dsOne)
.packages("com.cp.jpa.model")
.properties(jpaProperties.getProperties())
.persistenceUnit("pu1")
.build();
}
@Bean
PlatformTransactionManager platformTransactionManagerOne(EntityManagerFactoryBuilder builder) {
LocalContainerEntityManagerFactoryBean factoryBeanOne = localContainerEntityManagerFactoryBeanOne(builder);
return new JpaTransactionManager(factoryBeanOne.getObject());
}
}
首先这里注入dsOne,再注入JpaProperties,JpaProperties是系统提供的一个实例,里边的数据就是我们在application.properties中配置的jpa相关的配置。然后我们提供两个Bean,分别是LocalContainerEntityManagerFactoryBean和PlatformTransactionManager事务管理器,不同于MyBatis和JdbcTemplate,在Jpa中,事务一定要配置。在提供LocalContainerEntityManagerFactoryBean的时候,需要指定packages,这里的packages指定的包就是这个数据源对应的实体类所在的位置,另外在这里配置类上通过@EnableJpaRepositories注解指定dao所在的位置,以及LocalContainerEntityManagerFactoryBean和PlatformTransactionManager分别对应的引用的名字。
第二个基本和这个类似,主要有几个不同点
1.dao的位置不同
2.persistenceUnit不同
3.相关bean的名称不同
注意实体类可以共用,代码如下:
@Configuration
@EnableJpaRepositories(basePackages = "com.cp.jpa.dao2",entityManagerFactoryRef = "localContainerEntityManagerFactoryBeanTwo",transactionManagerRef = "platformTransactionManagerTwo")
public class JpaConfigTwo {
@Autowired
@Qualifier(value = "dsTwo")
DataSource dsTwo;
@Autowired
JpaProperties jpaProperties;
@Bean
LocalContainerEntityManagerFactoryBean localContainerEntityManagerFactoryBeanTwo(EntityManagerFactoryBuilder builder) {
return builder.dataSource(dsTwo)
.packages("com.cp.jpa.model")
.properties(jpaProperties.getProperties())
.persistenceUnit("pu2")
.build();
}
@Bean
PlatformTransactionManager platformTransactionManagerTwo(EntityManagerFactoryBuilder builder) {
LocalContainerEntityManagerFactoryBean factoryBeanTwo = localContainerEntityManagerFactoryBeanTwo(builder);
return new JpaTransactionManager(factoryBeanTwo.getObject());
}
}
接下来,在对应位置分别提供相关的实体类和dao即可,数据源一的dao如下:
package com.cp.jpa.dao;
public interface UserDao extends JpaRepository<User,Integer> {
List<User> getUserByAddressEqualsAndIdLessThanEqual(String address, Integer id);
@Query(value = "select * from t_user where id=(select max(id) from t_user)",nativeQuery = true)
User maxIdUser();
}
数据源二的dao如下:
package com.cp.jpa.dao2;
public interface UserDao2 extends JpaRepository<User,Integer> {
List<User> getUserByAddressEqualsAndIdLessThanEqual(String address, Integer id);
@Query(value = "select * from t_user where id=(select max(id) from t_user)",nativeQuery = true)
User maxIdUser();
}
共同的实体类如下:
package com.cp.jpa.model;
@Entity(name = "t_user")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String username;
private String address;
//省略getter/setter
}
到此,所有的配置就算完成了,接下来就可以在Service中注入不同的UserDao,不同的UserDao操作不同的数据源。
到此整合结束,望对大家有帮助,欢迎评论点赞,谢谢!