企业级应用大多数都是围绕着数据库的CURD操作进行的,得益于spring boot starter 对常用数据库的封装,可以非常方便且快速与其集成。
为了确保各微服务保持自身的独立性及整个分布式架构的效率,在设计服务模块时应尽量保持每个微服务模块使用单一且独立的数据源,各微服务模块之间的数据库互不干扰。
spring data mysql :
spring data:基于spring 提供了统一编程模型,并且支持众多不同的数据库,在保证底层数据特性的前提下,为关系型数据库或非关系型数据库提供了统一的操作方式,极大的简化了开发与学习难度。
spring-boot-starter-data-jpa :是spring基于ORM框架,JPA规范的基础上封装的一套JPA应用框架,可使开发者用极简的代码即可实现对数据的访问和操作,它提供了包括增删改查等在内的常用功能,且易于扩展。
spring.datasource.url | 数据源地址 |
spring.datasource.username | 用户名 |
spring.datasource.password | 用户密码 |
spring.datasource.driverClassName | 启动名称 |
spring.jpa.database | 指定使用的数据库 |
spring.jpa.show-sql | 控制台中显示执行的SQL |
spring.jpa.hibernate.ddl-auto | 自动创建表时所采用的策略 |
Create | 每次加载hibernate时都会删除上一次生成的表,然后根据你的model类再重新生成新表,即使两次没有任何改变也要这样执行 |
Create-drop | 每次加载hibernate时根据model类生成表,session Factory一旦关闭,表会自动删除 |
Update | 第一次加载hibernate时根据model类会自动建立起表的结构,以后加载hibernate时会根据model类自动更新表结构,即使表结构改变了表中的行也仍然存在,不会删除以前的行 |
Validate | 每次加载hibernate时,验证创建数据库表结构,只会和数据库中的表进行比较,不会创建新表但会插入新值。 |
@Entity | 标识该类为实体类,其中的name参数用于指定数据库的表名。默认以类名作为表名 |
@Id | 标识当前字段为主键 |
@GeneratedValue | 指定主键的自增长策略 |
auto | 主键由程序控制 |
Identiry | 主键由数据库控制 |
Sequence | 根据底层数据库的序列来生成主键,条件时数据库支持序列 |
Table | 使用一个特定的数据库表格来保持主键 |
@Column | 标识实体类中属性与数据表中字段的对应关系 |
Name | 数据库表中对应字段的名称 |
Unique | 唯一标识 |
Null able | 标识该字段是否可以为null值 |
Insert able | 在使用insert脚本插入数据时,是否需要插入该字段的值 |
Updatable | 在使用update脚本插入数据时,是否需要更新该字段的值 |
Columndefinition | 创建表时,该字段创建的sql语句 |
Table | 包含当前字段的表名 |
Length | 当字段的类型为varchar时,指定字段的长度 |
Precision | 数值的总长度 |
Scale | 小数点所占的位数 |
@ManyToOne | 指定多对一关系 |
TargetEntity | 指定具体实体 |
Cascade | 指定级联关系策略 |
CascadeType.refresh | 获取数据库中的最新数据 |
CascadeType.persist | 同步新增 |
CascadeType.merge | 同步更新 |
CascadeType.remove | 同步删除 |
CascadeType.all | 以上策略总和 |
Fetch | 控制加载数据策略 |
FetchType.eager | 查询到父实体类的时候加载 |
FetchType.lazy | 第一次访问数据库的时候加载 |
Optional | 指定是否为必须 |
@OneToOne | 一对一关系 |
OrphanRemoval | 是否开启自动删除外键为null的数据 |
MappedBy | 双向关联实体时,指定两者谁是维护端 |
Cascade/fetch | 与多对一的一直 |
spring data jpa 默认预先生成了一些基本的CURD(增删查)方法,创建接口并继承相应的repository(资源库)便可获得数据库的dao操作功能,并被spring 容器加载。
repository:通过用来访问领域对象的一个类似集合的接口,在领域与数据映射层之间进行协调,也就是dao.
Repository | 标识任何继承它的均为仓库接口类,方便spring自动扫描识别 |
Crudrepository | 继承自repository,实现了一组crud相关方法 |
Pagingandsortingrepository | 继承自Crudrepository ,实现了一组分页排序相关的方法 |
Jparepository | 继承自Pagingandsortingrepository,实现了一组jpa规范相关的方法 |
public interface StudentRepository extends PagingAndSortingRepository<Student,Long> {
}
PagingAndSortingRepository:继承自repository 需要操作的实体类及id的数据类型以便完成映射。
spring data 除了提供基本的操作外还支持通过方法名自动生成SQL,使用时只需根据约定好的规则定义方法名,而方法的具体实现则由spring data完成,避免了许多重复的代码。
List<Student> list = studentRepository.findByNameLikeOrderByIdAsc(String name);
关键词 | 方法名 | SQL |
And | fndByLastnameAndFirstname | ...where x.lastname = ?1 and x.firstname=?2 |
Or | findByLastnameOrFirstname | ...where x.lastname = ?1 or x.firstname = ?2 |
Is,Equals | findByFirstnameIs,findByFirstnameEquals | ...where x.firstname = ?1 |
Between | findByStartDateBetween | ...where x.startDate between ?1 and ?2 |
LessThan | findByAgeLessThan | ...where x.age < ?1 |
LessThanEqual | findByAgeLessThanEqual | ...where x.age <= ?1 |
GreaterThan | findByAgeGreaterThan | ...where x.age > ?1 |
GreaterThanEqual | findByAgeGreaterThanEqual | ...where x.age >= ?1 |
After | findByStartDateAfter | ...where x.startDate > ?1 |
Before | findByStartDateBefore | ...where x.startDate < ?1 |
IsNull | findByAgeIsNull | ...where x.age is null |
IsNotNull,NotNull | findByAge(Is)NotNull | ...where x.age not null |
Like | findByFirstnameLike | ...where x.firstname like ?1 |
NotLike | findByFirstnameNotLike | ...where x.firstname not like ?1 |
StartingWith | findByFirstnameStartingWith | ...where x.firstname like ?1(parameter bound with appended %) |
EndingWith | findByFirstnameEndingWith | ...where x.firstname like ?1(parameter bound with prepended %) |
Containing | findByFirstnameContaining | ...where x.firstname like ?1(parameter bound wrapped in %) |
OrderBy | findByAgeOrderByLastnameDesc | ...where x.age=?1 order by x.lastname desc |
Not | findByLastnameNot | ...where x.lastname <> ?1 |
In | findByAgeIn(Collection ages) | ...where x.age in ?1 |
NotIn | findByAgeNotIn(Collection age) | ...where x.age not in ?1 |
TRUE | findByActiveTrue() | ...where x.active = true |
FALSE | findByActiveFalse() | ...where x.active = false |
IgnoreCase | findByFirstnameIgnoreCase | ...where UPPER(x.firstname) = UPPER(?1) |
分页查询:
PagingAndSortingRepository从名称中可看出已经集成了分页与排序功能,在使用时只需在定义的方法中传入Pageable 参数并设置Page作为返回值。
接口:Page<Student> FindAllBy(Pageable pageable);
查询使用:
Page<Student> result = repository.findAll(new PageRequest(1,10,Sort(Sort.Direction.DESC,"ID")));
List<Student> content = result.getContent();
for(Student student:content){
sysout.out.printLn(student.getName());
}
int count = result.getTotalPages();
PageRequest: Pageable 的实现类,封装了分页所需的参数,如当前页,每页大小,排序等参数。
Page :封装了查询结果集,通过getContent()获得具体查询内容,getTotalPages获得总页数。
spring data 可以通过@Query 注解自定义SQL语句以支持更复杂的查询,删除,更新操作,但不支持保存操作。
@Query(value = "select * from Student s where s.id <= ?1",nativeQuery = true) List<Student> myQuery(Long id); @Query(value = "select s from Student s where s.id <= ?1") List<Student> myQuery2(Long id); @Query(value = "select * from Student \n#pageable\n",countName = "select * count(*) from student",nativeQuery = true) Page<Student> myQueryAll(Pageable pageable); @Modifying @Query("update Student s set s.name = :name where s.id = :id") void myUpdate(@Param("name")String name,@Param("id") int id); @Modifying @Query(value = "delete from Student where id = :id",nativeQuery = true) void myDelete(@Param("id")int id);
@Query
- value:sql 语句
- nativeQuery :是否开启原生SQL,为false 时则使用JPsql作为查询语句,SQL中的表名需要改为实体名以支持映射。
- countQuery: 分页时用于统计总数的SQL
@Modifying:告知Spring data 该sql语句为update 或delete
传参:将参数传递给SQL语句有两种方式。
- SQL语句中的?1 将按方法中参数的位置获取参数,如果为第二位则为?2
- @Param("name") 定义参数名称,在SQL语句中通过:name 获取。
分页:对方法进行分页配置后,@Query 注解中的countQuery 参数为必要项,并通过\n#pageable\n 将分页参数传递给SQL语句。
事务管理:在引入JDBC或者JPA依赖时,spring boot 已经默认注入了事务管理的实例,在使用时只需在需要开启的事务的方法或者类上添加@Transactionl注解即可。
@Transactional(rollbackFor = RuntimeException.class,propagation = Propagation.REQUIRED,isolation = Isolation.DEFAULT) public void demo(){ // 操作数据的业务逻辑 }
RollbackFor:指定该事务针对什么异常进行回滚,可以接口多个异常名称。
required | 如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务 |
supports | 如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续执行 |
mandatory | 如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常 |
requires_new | 创建一个新的事务,如果当前存在事务,则把当前事务挂起 |
not_supported | 以非事务的方式运行,如果当前存在事务,则把当前事务挂起 |
never | 以非事务的方式运行,如果当前存在事务,则抛出异常 |
nested | 如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则取值等价于required |
default | 使用底层数据库的默认隔离级别。对大部分数据库而言,通常这值就是read_committed |
read_uncommitted | 一个事务可以读取另一个事务修改但还没有提交的数据。该级别不能防止脏读和不可重复读,因此很少使用该隔离级别 |
read_committed | 一个事务只能读取另一个事务已经提交的数据。该级别可以防止脏读,这也是大多数情况下推荐的值 |
repeatable_read | 一个事务在整个过程中可以多次重复执行某个查询,并且每次返回的记录都相同。即使在多次查询之间有新增的数据满足该查询,这些新增的记录也会被忽略。该级别可以防止脏读和不可重复读。 |
serializable | 所有的事务依次逐个执行,事务之间完全不会产生干扰。 |
spring data mongoDB:
mongoDB 是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库中功能最丰富,最像关系数据库的。它支持的数据结构非常松散,是类似JSON的Bjson格式,因此可以存储比较复杂的数据类型。mongoDB最大的特点就是它支持的查询语言非常强大,其语法有点类似于面向对象的查询语言,集合可以实现类似关系数据库单表查询的绝大部分功能,而且还支持对数据建立索引。
mongoDB是由数据库,集合,文档对象三个层次组成。mongoDB中的一条记录就是一个文档,是一个数据结构,由字段和值对组成。适合对大量和无固定格式的数据进行存储,比如日志,缓存等。对事务支持较弱,不适用复杂的多文档(多表)的级联查询。