了解下JPA和Spring Data JPA
JPA诞生的缘由是为了整合第三方ORM框架,实现持久化领域的统一,简化现有Java EE和Java SE应用的对象持久化的开发工作。JPA是一套规范,而不是具体的ORM框架,JPA的标准的定制是hibernate作者参与定制的,所以可以理解JPA是Hibernate的一个功能子集。简而言之:JPA是标准接口或持久化规范,Hibernate是它的一种实现。
Spring Data是Spring提供的对数据库的访问方式,而Spring Data JPA是Spring Data的一部分,是JPA的Spring 实现方案。通过Spring Data JPA可以很方便的利用spring-framew构建基于数据库的应用程序。
在使用持久化工具的时候,一般都有一个对象来操作数据库,在原生的Hibernate中叫做Session,在JPA中叫做EntityManager,在MyBatis中叫做SqlSession,通过这个对象来操作数据库。我们一般按照三层结构来看的话,Service层做业务逻辑处理,Dao层和数据库打交道,在Dao中,就存在着上面的对象。那么ORM框架本身提供的功能有什么呢?答案是基本的CRUD,所有的基础CRUD框架都提供,我们使用起来感觉很方便,业务逻辑层面的处理ORM是没有提供的,如果使用原生的框架,业务逻辑代码我们一般会自定义,会自己去写SQL语句,然后执行。在这个时候,Spring Data JPA的威力就体现出来了,ORM提供的能力他都提供,ORM框架没有提供的业务逻辑功能Spring Data JPA也提供,全方位的解决用户的需求。使用Spring Data JPA进行开发的过程中,常用的功能,我们几乎不需要写一条sql语句,当然Spring Data JPA也提供自己写sql的方式,这个就看个人怎么选择了。
整合步骤
1. pom.xml添加依赖:
<!--使用spring-data-jpa访问数据库,springboot2默认是使用HikariCP数据源-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<!--排除springboot2默认的数据源HikariCP,使用druid连接池-->
<exclusions>
<exclusion>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--第三方连接池:druid-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.0</version>
</dependency>
<!--mysql依赖 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
2. application.yml添加数据源、连接池、JPA等配置:
#修改默认端口号和访问的上下文路径
server:
port: 8090
servlet:
context-path: /dev
# 配置MySQL数据源
spring:
datasource:
url: jdbc:mysql://localhost:3307/taobao_test?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=GMT%2B8
username: xxwei3
password: xxxxxx
driver-class-name: com.mysql.jdbc.Driver
# 使用druid连接池
type: com.alibaba.druid.pool.DruidDataSource
# 配置连接池
initialSize: 5
minIdle: 5
maxActive: 20
maxWait: 60000
timeBetweenEvictionRunsMillis: 60000
minEvictableIdleTimeMillis: 30000
filters: stat
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
poolPreparedStatements: true
maxOpenPreparedStatements: 20
sql-script-encoding: utf-8
---
# jpa相关配置
spring:
jpa:
# 更新数据表结构
hibernate:
ddl-auto: update
# 在日志中打印出执行sql语句的信息
show-sql: true
3. 基于JPA注解的映射关系配置(实体类与数据库表映射)
注意事项:
- MySQL中表名需要
tablename
特殊符号括起来才能被识别为数据库的表。 - JPA默认id为String类型,而MySQL为int类型,但数据库可以执行String类型的id。
// 配置表名,若省略则默认表名是对应的实体类Order
@Table(name = "`order`")
@Entity
public class Order implements Serializable {
@Id
//主键自增
@GeneratedValue(strategy = GenerationType.IDENTITY)
private String orderId;
private String orderSeq;
private String orderName;
// getset方法省略。。。
}
4. 基于JpaRepository<T,ID>接口操作数据库
Spring Data JPA采用接口的方式声明相应的数据库操作方法并且提供了部分基础的数据库操作方法包括save、findOne、findAll、update、delete等方法,通过查询方法还提供了分页查询的功能,也结合自己的业务需求自定义Repository并集成框架本身提供的接口就能拥有框架本身提供的数据库访问功能,针对具体的应用情况声明了特定的查询方法,针对各种简单查询,复杂查询的描述请参见spring data jpa官方手册:https://docs.spring.io/spring-data/jpa/docs/1.11.4.RELEASE/reference/html/。
public interface JPATestDao
extends JpaRepository<TDictionary,String> {}
5. 业务处理
Spring Data JPA会根据方法的名字来自动生成sql语句,我们只需要按照方法定义的规则即可,上面的方法findById,Spring Data JPA定,方法都以findBy开头,sql的where部分就是Id,被Spring Data JPA翻译之后就变成了:SELECT * FROM t_dictionary WHERE id = ?
下表能直接说明:
业务处理的代码:
//service层接口
public interface JPATestService {
// 根据id获取订单信息
Optional<Order> getOrderInfoById(String id);
// 获取全部订单信息
List<Order> getAllOrderInfos();
// 根据id删除订单
void deleteOrderById(String id);
// 添加订单
void addOrder(Order order);
}
// 实现层处理具体业务
@Service
public class JPATestServiceImpl implements JPATestService {
@Autowired
private JPATestDao jpaTestDao;
@Override
public Optional<Order> getOrderInfoById(String id) {
return jpaTestDao.findById(id);
}
@Override
public List<Order> getAllOrderInfos() {
return jpaTestDao.findAll();
}
@Transactional
@Override
public void deleteOrderById(String id) {
jpaTestDao.deleteById(id);
}
@Transactional
@Override
public void addOrder(Order order) {
jpaTestDao.save(order);
}
}
测试
在SpringBootTest中测试一下:
@SpringBootTest
class MySportHealthyApplicationTests {
Logger logger = LoggerFactory.getLogger(MySportHealthyApplicationTests.class);
@Autowired
private JPATestService jpaTestService;
@Test
void testQueryById() {
Optional<Order> order = jpaTestService.getOrderInfoById("1001");
logger.info("id为1001的订单名称为:" + order.get().getOrderName());
}
@Test
void testDelete() {
jpaTestService.deleteOrderById("1003");
}
@Test
void testQueryAll() {
List<Order> list = jpaTestService.getAllOrderInfos();
list.forEach(l -> {
logger.info("订单信息:" + l.getOrderId() + "," + l.getOrderSeq() + "," + l.getOrderName());
});
}
}
因为在JPA配置的时候,指定了显示操作sql的语句,以删除测试为例,控制台可以看到:
Hibernate: select order0_.order_id as order_id1_0_0_,
order0_.order_name as order_na2_0_0_,
order0_.order_seq as order_se3_0_0_ from `order` order0_
where order0_.order_id=?
Hibernate: delete from `order` where order_id=?
总结一下
Spring Data JPA实现不太复杂的CRUD操作基本不用写sql语句,通过构建Repository接口方法实现对数据库的操作,这个过程需要注意实体类和数据库表的映射关系配置,需要熟悉相关CRUD的API方法。