一、相关概念
数据持久化(Data Persistence)
数据有两种存储方式,存储设备和内存。内存为暂存,因为电源关机就会数据丢失,如果需要反复使用,就要持久保存在存储设备(如磁盘)。因此,数据持久化用来将内存中的数据模型转换为存储模型,以及将存储模型转换为内存中的数据模型。
我们常说的持久层(Persistence Layer),也叫数据访问层(DAO层,Data Access Object),是面向对象三层架构中,专门处理数据持久化的一层。
JDBC(Java Data Base Connectivity,java数据库连接)
是一种用于执行SQL语句的Java API,它是Java十三个规范之一。可以为不同关系数据库(Mysql、Oracle)提供统一访问,它由一组用Java语言编写的类和接口组成。JDBC是直接连接到数据库并运行SQL的标准,他是java数据库访问的底层技术之一,很多ORM工具都是在JDBC基础上的一层封装。
JDBC提供了如下概念:
- java.sql:Driver,DriverManager,Connection,Statement,ResultSet
- javax.sql:DataSource,RowSet,PooledConnection,ConnectionPoolDataSource,XAConnection
JDBC会使用到连接池:
- c3p0,开放的源代码的JDBC连接池
- DBCP,依赖Jakarta commons-pool对象池机制的数据库连接池
- druid,阿里出品,淘宝与支付宝专用的数据库连接池,支持所有JDBC兼容的数据库
- HiKariCP,是数据库连接池的一个后起之秀,号称性能最好,SpringBoot2.0自带
ORM(Object Relational Mapping,对象关系映射)
ORM是一种思想,实质就是,内存中的对象与关系数据库之间的映射关系。在面向对象开发过程中,开发者可以通过操作对象来操作数据库,方便实现数据持久化。
可以不通过ORM实现持久化嘛?当然可以,比如直接用JDBC直接写SQL执行。
ORM层基本就是两大阵营,JPA和Mybatis,两者各有优缺点,逐渐形成了两派。国内用Mybatis的多,国外用JPA的多。有人喜欢轻量灵活用Mybatis,而从软件设计角度JPA更加符合规范。
对比项 | JPA | Mybatis |
---|---|---|
单表操作 | 只需继承,代码量极少,非常方便。而且支持方法名用关键字生成SQL | 可以使用代码生成工具或Mybatis-Plus等工具,也很方便,但相对JPA要弱一些。 |
多表关联查询 | 不太友好,动态SQL使用不够方便,而且SQL和代码耦合到一起 | 友好,可以有非常直观的动态SQL |
自定义SQL | SQL写在注解里面,写动态SQL有些费劲 | SQL可以写在XML里面,是书写动态SQL语法利器。也支持注解SQL。 |
学习成本 | 略高 | 较低 ,基本会写SQL就会用 |
JPA(Java persistent Api,Java持久层API)
JPA是参照ORM思想,用java语法做出来的一个规范,就是接口。
较JDBC,JPA的抽象级别更高,而JDBC更底层。JDBC是为了解决“如何从关系型数据库中获取数据”而设计的,设计的重心是如何更好的使用SQL,取回来的数据以 ResultSet的形态存在于内存中。JPA解决的是 如何将内存中“Java 对象的序列化到磁盘中”的问题, 而且设计的焦点在于如何描述内存中的Java对象,也就是对内存对象进行建模。
Hibernate
是JPA规范的实现一个框架。Spring data JPA(spring-boot-starter-data-jpa包)是spring提供的一套简化JPA开发的框架,底层还是使用了 Hibernate 的 JPA 技术实现。
Mybatis
不遵循JPA规范,是另一款优秀的ORM框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis免除了几乎所有的JDBC代码以及设置参数和获取结果集的工作。
Spring Data
是Spring用来解决数据访问问题的一揽子解决方案,包含了大量关系型和非关系型数据库的数据访问方案。
常见项目包含:
项目名称 | Maven坐标 org.springframework.data |
---|---|
Spring Data JDBC | spring-data-jdbc |
Spring Data Jpa | spring-data-jpa |
Spring Data MongoDB | spring-data-mongodb |
Spring Data Redis | spring-data-redis |
Spring Data Solr | spring-data-solr |
Spring Data Hadoop | spring-data-hadoop |
Spring Data REST | spring-data-rest-webmvc |
Spring Data JDBC Ext | spring-data-oracle |
二、Spring Data JPA
基本概念
- Spring Data JPA对JPA规范进行了进一步的抽象。
- Hibernate主导了EJB3.0的JPA(Java Persistence API)规范。
- 继承JpaRepository接口,即可拥有默认数据访问操作方法,如findAll,getOne等。
1 |
|
3、在Spring中,需要使用注解@EnableJPARepository来开启JPA支持。
定义查询方法
1、常规查询
根据属性名查询,使用findBy、Like、And、IsNull、In、OrderBy等关键字来定义查询方法。
1 | Person findByNameAndAddress(String name,String address); |
通过top和first关键字来限制结果数量。
2、JPA的NamedQuery查询
Spring Data JPA支持用JPA的NamedQuery查询防范,即一个名称映射一个查询语句。
3、@Query查询,直接将@Query注解在接口的方法上实现查询。
1 |
|
4、排序与分页,提供了Sort类以及Page接口和Pageable接口。
Spring Boot的支持
1、JDBC的自动配置
在org.springframework.boot.autoconfigure.jdbc下。
2、对JPA的自动配置
在org.springframework.boot.autoconfigure.orm.jpa下。其中JpaBaseConfiguration会自动扫描注解有@Entity的实体类。
3、对Spring Data JPA的自动配置
在org.springframework.boot.autoconfigure.data.jpa下。JpaRepositoriesAutoConfiguration依赖于HibernateJpaAutoConfiguration配置。
4、Spring Boot下的Spring Data JPA
如需使用,maven依赖中添加spring-boot-starter-data-jpa,然后只需定义DataSource、实体类和数据访问层,并在需要使用数据访问的地方注入数据访问层的Bean即可。
三、Mybatis
基础demo
基础demo包含xml、注解方式等基本查询,以及association、collection、存储过程等高级查询。
Mybatis项目添加的依赖如下:
1 | <dependencies> |
yml文件配置如下:
1 | spring: |
logback.xml用于mybatis的sql查询日志打印
1 |
|
User.java
1 | public class User implements Serializable { |
UserMapper.java
1 | package com.herr.springboot.data.mybatis.mapper; |
UserMapper.xml
1 |
|
Role.java
1 | //用于mybatis的collection中,fetchType为lazy报错 |
RoleMapper.java
1 |
|
RoleMapper.xml
1 |
|
拓展demo
拓展demo包含mapper、pagehelper、generator等插件使用,以及一二级缓存,ehcache、redis三方缓存等。
- 一级缓存,针对相同的sql多次查询,mybatis提供了一级缓存避免多次请求数据库。一级缓存在mybatis中默认是开启的并且是session,它的作用域为一次sqlSession会话。还可以通过local-cache-scope配置设置为statement,缓存只作用于一次查询,可以理解关闭一级缓存。
- 二级缓存,二级缓存的作用域更广泛,它不止局限于一个sqlSession,可以在多个sqlSession之间共享,事实上,它的作用域是namespace。mybatis的二级缓存默认也是开启的,但由于他的作用域是namespace,所以还需要在mapper.xml中加入cache标签开启才能生效。
- 缓存的优先级,通过mybatis发起的查询,作用顺序为:二级缓存->一级缓存->数据库 ,其中任何一个环节查到不为空的数据,都将直接返回结果
- 缓存失效,当在一个缓存作用域中发生了update、insert、delete 动作后,将会触发缓存失效,下一次查询将命中数据库,从而保证不会查到脏数据。
MyBatis的二级缓存默认采用的org.apache.ibatis.cache.impl.PerpetualCache实现,且支持第三方缓存,常见方案有Ehcache和Redis。
- Ehcache(分布式缓存)直接在jvm虚拟机中缓存,速度快,效率高;但是缓存共享麻烦,集群分布式应用不方便。
- Redis(集中式缓存)是通过socket访问到缓存服务,效率比ecache低,比数据库要快很多,处理集群和分布式缓存方便,有成熟的方案。
pom.xml
1 | <properties> |
UserMapper.java
1 |
|
UserMapper.xml
1 |
|
源码
四、Mybatis-Plus
『MyBatis-Plus』是一个MyBatis的增强工具,在MyBatis的基础上只做增强不做改变,为简化开发、提高效率而生。
- 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
- 损耗小:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作
- 强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器
- 支持 Lambda 形式调用:通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错
- 支持主键自动生成:支持多达 4 种主键策略(内含分布式唯一 ID 生成器 - Sequence),可自由配置,完美解决主键问题
- 支持 ActiveRecord 模式:支持 ActiveRecord 形式调用,实体类只需继承 Model 类即可进行强大的 CRUD 操作
- 支持自定义全局通用操作:支持全局通用方法注入( Write once, use anywhere )
- 内置代码生成器:采用代码或者Maven插件可快速生成Mapper、Model、Service、Controller层代码,支持模板引擎
- 内置分页插件:基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通 List 查询
- 分页插件支持多种数据库:支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer 等多种数据库
- 内置性能分析插件:可输出 Sql 语句以及其执行时间,建议开发测试时启用该功能,能快速揪出慢查询
- 内置全局拦截插件:提供全表 delete 、 update 操作智能分析阻断,也可自定义拦截规则,预防误操作
五、Mybatis Plus
简介
MyBatis-Plus是一个MyBatis的增强工具,在 MyBatis的基础上只做增强不做改变,为简化开发、提高效率而生。
- 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
- 损耗小:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作
- 强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求
- 支持 Lambda 形式调用:通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错
- 支持主键自动生成:支持多达 4 种主键策略(内含分布式唯一 ID 生成器 - Sequence),可自由配置,完美解决主键问题
- 支持 ActiveRecord 模式:支持 ActiveRecord 形式调用,实体类只需继承 Model 类即可进行强大的 CRUD 操作
- 支持自定义全局通用操作:支持全局通用方法注入( Write once, use anywhere )
- 内置代码生成器:采用代码或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 层代码,支持模板引擎,更有超多自定义配置等您来使用
- 内置分页插件:基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通 List 查询
- 分页插件支持多种数据库:支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer 等多种数据库
- 内置性能分析插件:可输出 Sql 语句以及其执行时间,建议开发测试时启用该功能,能快速揪出慢查询
- 内置全局拦截插件:提供全表 delete 、 update 操作智能分析阻断,也可自定义拦截规则,预防误操作
wapper介绍
- Wrapper,条件构造抽象类,最顶端父类,抽象类中提供4个方法
- AbstractWrapper,用于查询条件封装,生成sql的where条件
- AbstractLambdaWrapper,Lambda语法使用Wrapper统一处理解析lambda获取column。
- LambdaQueryWrapper,用于Lambda语法使用的查询Wrapper
- LambdaUpdateWrapper,Lambda更新封装Wrapper
- QueryWrapper,Entity对象封装操作类,不是用lambda语法
- UpdateWrapper,Update条件封装,用于Entity对象更新操作
六、声明式事务
所有的数据访问技术都有事务处理机制
数据访问技术 | 实现 |
---|---|
JDBC | DataSourceTransactionManager |
JPA | JpaTransactionManager |
Hibernate | Hibernate TransactionManager |
JDO | JdoTransactionManager |
分布式事务 | JtaTransactionManager |
@Transactional注解
Transactional(来自org.springframework.transaction.annotation包)基于AOP的实现操作,被注解的方法在被调用时开启事务。
Spring提供一个@EnableTransactionManagement注解在配置类来开启声明式事务的支持,Spring容器会自动扫描注解@Transactional的方法和类。
属性包括:
1、propagation生命周期,默认为REQUIRED。
2、isolation隔离级别确定了事务的完整性。默认为DEFAULT,使用数据库的默认隔离级别。Mysql是REPEATABLE_READ,Oracle是READ_COMMITTED。
3、readOnly,只读事务,默认false
4、timeout,事务过期时间
5、rollbackFor,noRollbackFor,指定哪些异常(不)可以引起事务回滚
例如当捕获某个异常时进行回滚操作。
@Transactional(rollbackFor={IllegalArgumentException.class})
Spring Boot的事务支持
1、自动配置的事务管理器
使用JDBC作为数据访问技术时,DataSourceTransactionManagerAutoConfiguration类定义了DataSourceTransactionManager的Bean。
使用JPA作为数据访问技术时,or.jpa.JpaBaseConfiguration类定义了JpaTransactionManager的Bean。
2、自动开启注解事务的支持
transaction.TransactionAutoConfiguration类,依赖于上面两个类。在Spring Boot中无须显示开启使用@EnableTransactionManagement注解。
七、数据源和连接池
数据源以及SpringBoot的自动配置原理
找到org.springframework.boot.autoconfigure.jdbc包下的DataSourceConfiguration类,原理大概是如果在classpath下存在org.apache.tomcat.jdbc.pool.DataSource.class类,并且在配置文件中指定spring.datasource.type的值为org.apache.tomcat.jdbc.pool.DataSource,或者不写都会认为可以通过。只有通过才会进入这段配置代码,才能注入DataSourceBean。
SpringBoot默认可以支持;
org.apache.tomcat.jdbc.pool.DataSource、HikariDataSource、BasicDataSource等。通过以下方式可自定义数据源。
1 |
|
数据库连接池
当我们使用了如上所述的默认数据源之后,那么已默认启用了数据库链接池。
Spring Boot为我们准备了最佳的数据库连接池方案,只需要在属性文件(例如application.properties)中配置需要的连接池参数即可,使用spring.datasource.type属性。
Tomcat7之前,Tomcat本质应用了DBCP连接池技术来实现的JDBC数据源,但在Tomcat7之后,Tomcat提供了新的JDBC连接池方案,作为DBCP的替换或备选方案,解决了许多之前使用DBCP的不利之处,并提高了性能。
在引入spring-boot-starter-jdbc后,内部包含了tomcat-jdbc包,里面有tomcat连接池.然后通过自动配置DataSourceAutoConfigurer创建DataSource对象。
SpringBoot 1.x版本,创建默认DataSource时,规则如下:
- 优先寻找创建Tomcat连接池
- 如果没有Tomcat连接池,会查找创建HikariCP
- 如果没有HikariCP连接池,会查找创建dbcp
- 如果没有dbcp连接池,会查找创建dbcp2
SpringBoot 2.x版本,默认使用HikariCP连接池。
Druid连接池
- Druid是Alibaba开源的数据库连接池。Druid能够提供强大的监控和扩展功能
- 可以监控数据库访问性能, Druid内置提供了一个功能强大的StatFilter插件,能够详细统计 SQL 的执行性能
- 数据库密码加密。DruidDruiver和DruidDataSource都支持PasswordCallback
- SQL执行日志,Druid 提供了不同的LogFilter,能够支持Common-Logging、Log4j和JdkLog
- 扩展JDBC,如果你要对JDBC层有编程的需求,可以通过Druid提供的Filter机制,很方便编写JDBC层的扩展插件
『druid-spring-boot-starter集成传送门』
1 | <!-- druid连接池传统依赖包 --> |
yml文件配置如下:
1 | spring: |
可访问http://localhost:8080/druid,查看数据库连接池相关情况。
HikariCP连接池