Spring Data之JPA开篇

背景说明

目前Spring Boot大行其道,其便捷性给开发人员带来了很大的效率提升。它简化了样板配置,通过关键的说明或者约定就能快速搭建起想要的框架。

Spring Boot可适配的组件众多,由于绝大多数应用系统都会同数据库打交道的,这就涉及到Spring Data家族的使用。为什么说是家族呢,因为Spring Data包含JDBC、JPA、LDAP、MongoDB、Redis、Elasticsearch等多种类型的数据源适配操作。

通过Spring Data的封装组件化之后,可带来同等的编程体验。那么简化的背后其实是复杂的逻辑支撑,例如无需任何编码只需@Autowired private JdbcTemplate jdbcTemplate;就能通过jdbcTemplate执行sql操作数据库,它背后发生了什么呢,本系列博客就将通过源码和示例结合的方式,解析Spring Data背后的实现原理。目的是为了通过了解Spring Data的框架结构、设计思路来提升平时业务系统开发中的代码设计能力,搬砖也要搬的有水平!

工程搭建

首先创建一个Spring Boot工程,有两种方式:

  • 方式一
    通过在线的https://start.spring.io/创建,其中依赖的模块选上JDBC、H2
    在这里插入图片描述
    点击 Generte Project就能下载一个zip的工程文件,解压导入即可。第一次导入可能有点慢,会下载相关的maven依赖包
  • 方式二
    通过idea创建,idea集成了Spring Initializr向导
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

编码实现

工程搭好后,我们用最少的代码量,实现一个对User的操作(其中依赖了Lombok减少样板代码)。

  • 定义Entity
@Data
@Entity
@Table(name = "t_user")
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String firstName;

    private String lastName;
}
  • 定义Repository
public interface UserRepository extends JpaRepository<User,Long> {
}
  • application.propertites
    这里为了能直接Run起来,使用h2作为数据源
spring.datasource.url=jdbc:h2:mem:test;DB_CLOSE_ON_EXIT=FALSE
spring.datasource.username=sa
spring.datasource.password=
spring.jpa.show-sql=true
  • Test
@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest
public class JpaTests {

    @Autowired
    private UserRepository userRepository;

    @Before
    public void before(){
        User user = new User();
        user.setFirstName("张");
        user.setLastName("三");

        userRepository.save(user);
    }

    @Test
    public void queryAll() {
       List<User> users = userRepository.findAll();
       log.info("result:{}",users);
    }
}
  • 控制台输出
 .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.0.4.RELEASE)

2018-10-25 09:32:19.848  INFO 37469 --- [           main] com.learn.data.JpaTests                  : Starting JpaTests on fangliangshengdeMacBook-Pro.local with PID 37469 (started by fangliangsheng in /Users/fangliangsheng/Documents/git/learn-data)
2018-10-25 09:32:19.849  INFO 37469 --- [           main] com.learn.data.JpaTests                  : No active profile set, falling back to default profiles: default
2018-10-25 09:32:19.868  INFO 37469 --- [           main] s.c.a.AnnotationConfigApplicationContext : Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@2d52216b: startup date [Thu Oct 25 09:32:19 CST 2018]; root of context hierarchy
2018-10-25 09:32:20.645  INFO 37469 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Starting...
2018-10-25 09:32:20.791  INFO 37469 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.
2018-10-25 09:32:20.846  INFO 37469 --- [           main] j.LocalContainerEntityManagerFactoryBean : Building JPA container EntityManagerFactory for persistence unit 'default'
2018-10-25 09:32:20.867  INFO 37469 --- [           main] o.hibernate.jpa.internal.util.LogHelper  : HHH000204: Processing PersistenceUnitInfo [
	name: default
	...]
2018-10-25 09:32:20.937  INFO 37469 --- [           main] org.hibernate.Version                    : HHH000412: Hibernate Core {5.2.17.Final}
2018-10-25 09:32:20.938  INFO 37469 --- [           main] org.hibernate.cfg.Environment            : HHH000206: hibernate.properties not found
2018-10-25 09:32:21.020  INFO 37469 --- [           main] o.hibernate.annotations.common.Version   : HCANN000001: Hibernate Commons Annotations {5.0.1.Final}
2018-10-25 09:32:21.160  INFO 37469 --- [           main] org.hibernate.dialect.Dialect            : HHH000400: Using dialect: org.hibernate.dialect.H2Dialect
Hibernate: drop table t_user if exists
Hibernate: create table t_user (id bigint generated by default as identity, first_name varchar(255), last_name varchar(255), primary key (id))
2018-10-25 09:32:21.588  INFO 37469 --- [           main] o.h.t.schema.internal.SchemaCreatorImpl  : HHH000476: Executing import script 'org.hibernate.tool.schema.internal.exec.ScriptSourceInputNonExistentImpl@5d97caa4'
2018-10-25 09:32:21.591  INFO 37469 --- [           main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
2018-10-25 09:32:22.023  INFO 37469 --- [           main] com.learn.data.JpaTests                  : Started JpaTests in 2.639 seconds (JVM running for 3.416)
Hibernate: insert into t_user (id, first_name, last_name) values (null, ?, ?)
2018-10-25 09:32:22.178  INFO 37469 --- [           main] o.h.h.i.QueryTranslatorFactoryInitiator  : HHH000397: Using ASTQueryTranslatorFactory
Hibernate: select user0_.id as id1_0_, user0_.first_name as first_na2_0_, user0_.last_name as last_nam3_0_ from t_user user0_
2018-10-25 09:32:22.276  INFO 37469 --- [           main] com.learn.data.JpaTests                  : result:[User(id=1, firstName=, lastName=)]
2018-10-25 09:32:22.281  INFO 37469 --- [       Thread-2] s.c.a.AnnotationConfigApplicationContext : Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@2d52216b: startup date [Thu Oct 25 09:32:19 CST 2018]; root of context hierarchy
2018-10-25 09:32:22.283  INFO 37469 --- [       Thread-2] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default'
2018-10-25 09:32:22.283  INFO 37469 --- [       Thread-2] .SchemaDropperImpl$DelayedDropActionImpl : HHH000477: Starting delayed drop of schema as part of SessionFactory shut-down'
Hibernate: drop table t_user if exists
2018-10-25 09:32:22.287  INFO 37469 --- [       Thread-2] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown initiated...
2018-10-25 09:32:22.288  INFO 37469 --- [       Thread-2] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown completed.

在控制台的日志中,可以清楚的看到运行过程

  1. 先是启动了hikari数据源
    HikariPool-1 - Starting…

    在不指定数据源类型的情况下,Spring Boot默认以hikari作为数据源

  2. 创建EntityManagerFactory
    Building JPA container EntityManagerFactory for persistence unit ‘default’

    EntityManagerFactory是 JSR 338 JPA规范中定义的一个接口,用来创建EntityManager。这是出现的第一个Factory,在后续的源码分析中,还会看到很多Factory

  3. 启动Hibernate
    HHH000412: Hibernate Core {5.2.17.Final}

    在我们的pom.xml和application.properties中都没有出现Hibernate的字样,这里为什么会出现Hibernate呢。是由于Spring Data JPA使用Hibernate作为JPA的默认实现

  4. 创建Entity表
    Hibernate: drop table t_user if exists

    因为Hibernate实现了JPA规范,而@Entity正是JPA规范中的重要注解,用来标识一个domain是否为数据映射实体。Hibernate发现该注解后,就开始为该domain创建对应的表,

  5. 启动完成
    Initialized JPA EntityManagerFactory for persistence unit ‘default’

    至此应用才算启动完成

  6. 执行Test
    Hibernate: insert into t_user (id, first_name, last_name) values (null, ?, ?)

    先是执行了@Before注解的方法,创建一条User数据

    Hibernate: select user0_.id as id1_0_, user0_.first_name as first_na2_0_, user0_.last_name as last_nam3_0_ from t_user user0_

    执行@Test中的findAll方法,可见findAll被翻译成了上面了select语句,这也是后续我们将深入分析的地方,Spring Data JPA的查询方式非常丰富

  7. 释放资源
    Closing JPA EntityManagerFactory for persistence unit ‘default’

    关闭EntityManagerFactory

    HikariPool-1 - Shutdown initiated…

    关闭数据源

结束语

入门的JPA使用就结束了,其中Spring Boot、Spring Data为我们做了很多初始化的工作,后续将以该简单示例为基础,来深入分析其背后的工作原理。

猜你喜欢

转载自blog.csdn.net/f4761/article/details/83352256