美文网首页
第6章 数据持久化 Spring Data JPA

第6章 数据持久化 Spring Data JPA

作者: runewbie | 来源:发表于2019-12-01 15:29 被阅读0次

    6.1、本节目标:

    • JPA 简介
    • Spring Data JPA 用法介绍
    • Spring Data JPA、Hibernate/Mybatis/Mybatis-plus 与 Spring Boot 集成
    • 数据持久化实战

    6.2、JPA 简介

    6.2.1、什么是JPA?

    • JPA是Java Persistence API的简称,中文名Java持久层API,是JDK 5.0注解或XML描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中。

    • 最新规范为 JSR 338: JavaTM Persistence 2.2

    • 实现: 支持 JPA 2.2 版本的框架

    6.2.2、JPA 核心概念

    • 实体

      • 实体表示关系数据库中的表
      • 每个实体实例对应于该表中的行
      • 类必须用 javax.persistence.Entity 注解
      • 类必须有一个 publicprotected 的无参构造函数
      • 实体实例被当做值以分离对象方式进行传递(例如通过会话bean的远程业务接口),则该类必须实现 Serializable 接口
      • 唯一的对象识别符:简单主键(javax.persistence.idjavax.persistence.Id)、复合主键(javax.persistence.EmbeddedIdjavax.persistence.IdClass
    • 关系

      • 一对一:@OneToOne
      • 一对多:@OneToMany
      • 多对一:@ManyToOne
      • 多对多:@ManyToMany

    6.2.3、EntityManager

    EntityManager接口:

    • 定义用于与持久性上下文进项交互的方法
    • 创建和删除持久实体实例,通过实体的主键查找实体
    • 允许在实体上运行查询

    获取 EntityManager 实例:

    EntityManagerFactory emf=Persistence.createEntityManagerFactory("Student_details");  
    

    查找实体:

    EntityManagerFactory emf=Persistence.createEntityManagerFactory("Student_details");  
    EntityManager em=emf.createEntityManager();  
    StudentEntity s=em.find(StudentEntity.class,101); 
    

    6.3、Spring Data JPA

    6.3.1、什么是 Spring Data JPA?

    • 是较大的 Spring Data 家族的一部分
    • 对基于 JPA 的数据访问层的增强支持
    • 使得构建使用数据访问技术的 spring 驱动的应用程序更加容易
    • 官方文档

    6.3.2、常用接口

    CrudRepository:

    @NoRepositoryBean
    public interface CrudRepository<T, ID> extends Repository<T, ID> {
        <S extends T> S save(S var1);
    
        <S extends T> Iterable<S> saveAll(Iterable<S> var1);
    
        Optional<T> findById(ID var1);
    
        boolean existsById(ID var1);
    
        Iterable<T> findAll();
    
        Iterable<T> findAllById(Iterable<ID> var1);
    
        long count();
    
        void deleteById(ID var1);
    
        void delete(T var1);
    
        void deleteAll(Iterable<? extends T> var1);
    
        void deleteAll();
    }
    

    PagingAndSortingRepository用来分页:

    public interface PagingAndSortingRepository<T, ID> extends CrudRepository<T, ID> {
        Iterable<T> findAll(Sort var1);
    
        Page<T> findAll(Pageable var1);
    }
    

    自定义查询:根据方法名创建查询,继承Repository

    6.4、Spring Data JPA、Hibernate 与 Spring Boot 集成

    环境准备

    • Mysql 8
    • Spring Data JPA
    • Hibernate
    • Mysql Connector/J

    新建一个 jpa-in-action 的项目,将上一节中thymeleaf-in-action 中的内容拷贝过来。

    修改pom文件,添加相关依赖:

    <!-- spring-boot-starter-data-jpa依赖,可以省略版本,Spring Boot中已已自动帮我们定义依赖版本 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <!-- mysql依赖 -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.16</version>
    </dependency>
    <!-- 内存数据库,只在运行时使用,因为目前还没有使用mysql数据库,引入了mysql的依赖之后启动会报错,所以先引入h2内存数据库-->
    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
        <version>1.4.199</version>
        <scope>runtime</scope>
    </dependency>
    

    注意:上面引入了H2内存数据库,在运行时使用,如果不引入,因为我们目前还没有指定数据源,但是又引入了mysql的依赖,直接启动项目回报如下错误:

    Action:

    Consider the following:
    If you want an embedded database (H2, HSQL or Derby), please put it on the classpath.
    If you have database settings to be loaded from a particular profile you may need to activate it (no profiles are currently active).

    修改我们的实体类User

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    @Entity
    public class User implements Serializable {
        /** 用户的唯一标识 */
        @Id
        private Long id;
        private String name;
        private Integer age;
    }
    

    注意:我们要在实体类上添加@Entity@Id注解,同时要实现Serializable,不然我们之后在浏览器端进行用户创建操作的时候无法在h2中自动创建表。

    删除原有的 impl 包及其包中的内容,修改 UserRepository,使其继承JPA的CrudRepository接口:

    public interface UserRepository extends CrudRepository<User, Long> {
    
    }
    

    同时我们还要修改UserController,使其使用CrudRepository提供的默认方法:

    @RestController
    @RequestMapping("/users")
    public class UserController {
    
        @Autowired
        private UserRepository userRepository;
    
        /**
         * 从 用户存储库 获取用户列表
         *
         * @return
         */
        private List<User> getUserList() {
            List<User> list = new ArrayList<>();
            Iterable<User> users = userRepository.findAll();
            users.forEach(user -> {
                list.add(user);
            });
            return list;
        }
    
        /**
         * 查询所用用户
         *
         * @param model
         * @return
         */
        @GetMapping
        public ModelAndView list(Model model) {
            model.addAttribute("userList", this.getUserList());
            model.addAttribute("title", "用户管理");
            return new ModelAndView("users/list", "userModel", model);
        }
    
        /**
         * 根据id查询用户
         *
         * @param id
         * @param model
         * @return
         */
        @GetMapping("{id}")
        public ModelAndView view(@PathVariable("id") Long id, Model model) {
            Optional<User> user = userRepository.findById(id);
            model.addAttribute("user", user);
            model.addAttribute("title", "查看用户");
            return new ModelAndView("users/view", "userModel", model);
        }
    
        /**
         * 获取 form 表单页面
         *
         * @param model
         * @return
         */
        @GetMapping("/form")
        public ModelAndView createForm(Model model) {
            model.addAttribute("user", new User());
            model.addAttribute("title", "创建用户");
            return new ModelAndView("users/form", "userModel", model);
        }
    
        /**
         * 新建用户
         *
         * @param user
         * @return
         */
        @PostMapping
        public ModelAndView create(User user) {
            user = userRepository.save(user);
            return new ModelAndView("redirect:/users");
        }
    
        /**
         * 删除用户
         *
         * @param id
         * @param model
         * @return
         */
        @GetMapping(value = "delete/{id}")
        public ModelAndView delete(@PathVariable("id") Long id, Model model) {
            userRepository.deleteById(id);
            model.addAttribute("userList", this.getUserList());
            model.addAttribute("title", "删除用户");
            return new ModelAndView("users/list", "userModel", model);
        }
    
        /**
         * 修改用户
         *
         * @param id
         * @param model
         * @return
         */
        @GetMapping(value = "modify/{id}")
        public ModelAndView modifyForm(@PathVariable("id") Long id, Model model) {
            Optional<User> user = userRepository.findById(id);
            model.addAttribute("user", user);
            model.addAttribute("title", "修改用户");
            return new ModelAndView("users/form", "userModel", model);
        }
    
    }
    

    同时我们在application.properties文件中添加h2的web访问配置,这样我们就可以在浏览器端访问内存数据库:

    # 使用 h2 的控制台,便于我们在web端访问内存数据库,
    spring.h2.console.enabled=true
    

    启动我们的应用,访问 http://localhost:8080/users 创建几条数据,然后在浏览器访问 http://localhost:8080/h2-console ,可以看到h2的控制界面:

    image-20191127215227122

    默认是没有密码的,我们直接点击 Connect 就可以连接上。 注意:JDBC URL默认是jdbc:h2:~/test,而Spring Boot的默认数据库url应该是jdbc:h2:mem:testdb,否则进去后找不到JPA创建的数据表,如果连接报错,一般是JDBC URL错误,我们可以在启动日志中找到我们的内存数据库的地址:

    image-20191127215126139

    我们点击 Connect 后可以看到下面的界面:

    image-20191127230546624

    6.5、数据持久化实战

    我们接着上一节的项目来学习,在6.4节我们将数据保存到了内存数据库h2中。但是在实际的生产环境中,我们是不可能将数据保存在内存中的,而是持久化到Mysql等数据库中。这一节我们就介绍如何将数据保存到mysql中。

    修改application.properties,添加数据源:

    # DataSource
    spring.datasource.url=jdbc:mysql://localhost/blog?characterEncoding=utf-8&useSSL=false&serverTimezone=UTC
    spring.datasource.username=root
    spring.datasource.password=123456
    spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
    
    # JPA 打印sql
    spring.jpa.show-sql = true
    # 在应用每次启动时删除数据库重新创建
    spring.jpa.hibernate.ddl-auto=create-drop
    

    安装启动 Mysql Server

    安装mysql可以选择在本地安装,也可以选择安装在linux虚拟机中,或者在虚拟机中安装docker,使用docker容器安装都可以,这里不过多叙述,读者请自行安装准备好。

    Mysql 数据库中创建blog数据库:

    CREATE DATABASE blog;
    

    启动项目,我们可以看到在idea的控制台打印了如下信息:

    Hibernate: drop table if exists user
    Hibernate: create table user (id bigint not null auto_increment, age integer, name varchar(255), primary key (id)) engine=InnoDB
    

    打开数据库管理器可以看到JPA自动帮我们在数据库中创建了数据表:

    image-20191128230029112

    我们在浏览器端访问我们的项目界面,插入数据,可以看到用户信息被持久化到了mysql中。而我们访问 http://localhost:8080/h2-console 查看我们的内存数据库,发现内存数据库是无法进入的,因为这个时候我们指定了数据源为mysql数据库,因此内存数据库中就不会存在数据库表,我们在控制台也可以看到如下信息:

    H2 console available at '/h2-console'. Database available at 'jdbc:mysql://localhost/blog?characterEncoding=utf-8&useSSL=false&serverTimezone=UTC
    

    以上,就是我们有关Spring Data JPA 的简单介绍,更多内容我们在之后的使用中还会讲到。更对内容可以查看源代码获取。

    源代码

    jpa-in-action

    相关文章

      网友评论

          本文标题:第6章 数据持久化 Spring Data JPA

          本文链接:https://www.haomeiwen.com/subject/scfwwctx.html