1、什么是ORM
对象关系映射(Object Relational Mapping,简称ORM)是通过使用描述对象和数据库之间映射的元数据,将面向对象语言程序中的对象自动持久化到关系数据库中。简单来说就是将数据库表与java实体对象做一个映射
2、ORM的优缺点
优点:符合面向对象编程;技术与业务解耦,开发时不需要关注数据库的连接与释放;
缺点:orm会牺牲程序的执行效率和会固定思维模式
3、orm主流框架
hibernate(jpa)、mybatis/mybatis-plus(半自动orm)。今天主要基于jpa规范再次封装抽象实现的SpringData JPA。在介绍SpringData JPA之前,先介绍一下jpa
JPA是Java Persistence API的简称,中文名为Java持久层API,是JDK 5.0注解或XML描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中。
JPA包括以下3方面的内容:
(1)一套API标准。在javax.persistence的包下面,用来操作实体对象,执行CRUD操作,框架在后台替代我们完成所有的事情,开发者从烦琐的JDBC和SQL代码中解脱出来。
(2)面向对象的查询语言:Java Persistence QueryLanguage(JPQL)。这是持久化操作中很重要的一个方面,通过面向对象而非面向数据库的查询语言查询数据,避免程序的SQL语句紧密耦合。
(3)ORM(object/relational metadata)元数据的映射。JPA支持XML和JDK5.0注解两种元数据的形式,元数据描述对象和表之间的映射关系,框架据此将实体对象持久化到数据库表中。
通过demo示例可以了解或者掌握以下内容
1、pom.xml引入相应包
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
2、application.yml配置
spring:
datasource:
name: druidDataSource
type: com.alibaba.druid.pool.DruidDataSource
druid:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/springboot-learning?allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8&useSSL=false&autoReconnect=true&serverTimezone=UTC
username: root
password: config.file=classpath:druid.properties
filters: stat,log4j,config
max-active: 100
initial-size: 1
max-wait: 60000
min-idle: 1
db-type: mysql
time-between-eviction-runs-millis: 60000
min-evictable-idle-time-millis: 300000
validation-query: select 'x'
test-while-idle: true
test-on-borrow: false
test-on-return: false
pool-prepared-statements: true
max-open-prepared-statements: 50
max-pool-prepared-statement-per-connection-size: 20
connection-properties: config.file=classpath:druid.properties # 启用加密,配置公钥。
filter:
config:
enabled: true
jpa:
show-sql: true
hibernate:
ddl-auto: update
properties:
hibernate.format_sql: true
database-platform: org.hibernate.dialect.MySQL5InnoDBDialect
jpa一些比较核心配置属性介绍
jpa.hibernate.ddl-auto参数的作用主要用于:自动创建|更新|验证数据库表结构。如果不是此方面的需求建议取值设为none
可选参数
spring.jpa.database-platform这个参数的主要用于指定默认的数据库存储引擎,在springboot2版本中,默认mysql数据库存储引擎的是MyISAM,通过把取值设置为org.hibernate.dialect.MySQL5InnoDBDialect,就可以把默认的存储引擎切换为InnoDB
3、创建entity
@Entity
@Table(name="order_log")
@AllArgsConstructor
@NoArgsConstructor
@Data
@Builder
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
@IgnoreNullValue
public class OrderLog extends BaseEntity {
@Column(name="order_id")
private Long orderId;
@Column(name="order_content",length = 2000)
private String orderContent;
@Column(name="order_name")
private String orderName;
}
父类
@Data
@AllArgsConstructor
@NoArgsConstructor
@MappedSuperclass
public class BaseEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@CreationTimestamp
@Column(name="create_date",updatable = false)
private Date createDate;
@UpdateTimestamp
@Column(name="update_date")
private Date updateDate;
}
entity注解解释
本例只用一个entity来演示,因此没有涉及到表与表的关联,常用表与表之间的关联注解如下
4、创建Repository
通过继承JpaRepository可以实现增删改查,包括简单分页,通过继承JpaSpecificationExecutor可以实现复杂查询
public interface OrderLogRepository extends JpaSpecificationExecutor<OrderLog>,JpaRepository<OrderLog,Long> {
}
在使用Repository存在一个坑点,更新时,调用其提供的save方法会导致null属性覆盖到数据库。即如果要更新的bean中的字段,存在null值,原生的SimpleJpaRepository进行更新操作时,会把null值更新进数据库,而有时候业务上我们不需要这样,因此可以重写SimpleJpaRepository方法,其核心代码如下
/**
* 通用save方法 :新增/选择性更新
*/
@Override
@Transactional
public <S extends T> S save(S entity) {
//获取ID
ID entityId = (ID) entityInformation.getId(entity);
Optional<T> optionalT;
if (entityId == null) {
//标记为新增数据
optionalT = Optional.empty();
} else {
//若ID非空 则查询最新数据
optionalT = findById(entityId);
}
//若根据ID查询结果为空
if (!optionalT.isPresent()) {
em.persist(entity);//新增
return entity;
} else {
if(entity.getClass().isAnnotationPresent(IgnoreNullValue.class)){
IgnoreNullValue nullValue = entity.getClass().getAnnotation(IgnoreNullValue.class);
if(nullValue.value()){
//1.获取最新对象
T target = optionalT.get();
//2.将非空属性覆盖到最新对象
BeanUtil.copyNotNUllProperties(entity,target);
//3.更新非空属性
em.merge(target);
return (S) target;
}else{
em.merge(entity);
}
}else{
em.merge(entity);
}
return entity;
}
}
@IgnoreNullValue这个注解是用来指定是否要忽略空值字段。
在启动类上指定@EnableJpaRepositories注解,并将repositoryBaseClass设置为CustomSimpleJpaRepository,改成我们重写后的Repository,默认repositoryBaseClass为SimpleJpaRepository
@SpringBootApplication
@EnableJpaRepositories(basePackages = {"com.github.lybgeek.orm.jpa.repository"},repositoryBaseClass = CustomSimpleJpaRepository.class)
public class OrmApplication {
public static void main( String[] args ) {
SpringApplication.run(OrmApplication.class,args);
}
}
5、分页查询代码示例
public PageResult<OrderLog> pageOrderLogs(PageQuery<OrderLog> pageQuery) {
Sort sort = new Sort(Direction.DESC,"createDate");
Pageable pageable = PageRequest.of(pageQuery.getPageNo() - 1,pageQuery.getPageSize(),sort);
Specification<OrderLog> specification = (Specification<OrderLog>) (root, criteriaQuery, criteriaBuilder) -> {
OrderLog queryParams = pageQuery.getQueryParams();
if(queryParams != null){
List<Predicate> predicates = new ArrayList<>();
if(ObjectUtils.isNotEmpty(queryParams.getOrderId())){
Path<Long> orderId = root.get("orderId");
Predicate orderIdPredicate = criteriaBuilder.equal(orderId,queryParams.getOrderId());
predicates.add(orderIdPredicate);
}
if(StringUtils.isNotBlank(queryParams.getOrderName())){
Path<String> orderName = root.get("orderName");
Predicate orderNamePredicate = criteriaBuilder.like(orderName,"%"+queryParams.getOrderName()+"%");
predicates.add(orderNamePredicate);
}
if(CollectionUtils.isNotEmpty(predicates)){
return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
}
}
return null;
};
Page<OrderLog> orderLogPage = orderLogRepository.findAll(specification,pageable);
if(ObjectUtils.isNotEmpty(orderLogPage)){
return PageUtil.INSTANCE.getPage(orderLogPage);
}
return null;
}
https://blog.csdn.net/u014131617/article/details/85813091 https://blog.csdn.net/xudailong_blog/article/details/84336629
本文主要是介绍springdata jpa一些常规基本用法,只做入门,其具体更详细的内容,可以查看官网介绍
https://docs.spring.io/spring-data/jpa/docs/current/reference/html/
另外由于篇幅原因,其项目中包含的一些杂项诸如druid加密,flyway数据库版本管理,do和dto的相互转换,本文就不再论述,感兴趣的朋友可以查看我下边贴出来的demo链接。下篇会继续介绍mybatis、mybatisplus的基本使用
https://github.com/lyb-geek/springboot-learning/tree/master/springboot-orm