美文网首页
SpringBoot 2.x 数据库访问中间件JPA

SpringBoot 2.x 数据库访问中间件JPA

作者: kaixingdeshui | 来源:发表于2020-11-03 13:32 被阅读0次
    SpringBoot 2.x 数据库访问中间件Spring Data JPA
    ORM框架

    对象关系映射(Object Relational Mapping),用于实现面向对象编程语言里不同类型系统的数据之间的转换。
    即,ORM是通过使用描述对象和数据库之间映射的元数据,将程序中的对象和关系数据库相互映射;

    异构性:

    ORM可以解决数据库与程序间的异构性。例如java中使用String表示字符串,而Oracle使用varchar2,Mysql使用varchar,SQLServer使用nvarchar。

    映射:

    ORM提供了实现持久层的另一种模式,采用映射元数据xml来描述对象-关系的映射细节,使得ORM中间件能在任何一个java应用的业务逻辑层和数据库之间充当桥梁。

    常用ORM框架

    Hibernate: 全自动的框架,强大,复杂,笨重,学习成本高
    Mybatis :半自动的框架(懂数据库的人才能操作)必须要自己写sql
    JPA: Java Persistence API,java自带框架

    本文主要讲的是使用SpringBoot集成SpringDataJPA

    SpringBoot集成 SpringData JPA

    SpringData官网介绍 https://spring.io/projects/spring-data

    image.png
    简单介绍:
    image.png
    SpringData特点

    1.支持对象关系映射

    具备ORM框架的对象关系映射功能

    1. 统一Repository接口

    Repository<T, ID extends Serializable>
    CrudRepository<T, ID extends Serializable> 基本的CRUD操作
    PagingAndSortingRepository<T, ID extends Serializable> 基本CRUD分页

    3.统一数据访问模板类 XXXTemplre

    MongoTemplate,RedisTemplate等

    JPA简介

    JPA(Java Persistence API) 是Sun公司官方提出的Java持久化规范。它为Java开发人员提供了一种对象/关系映射工具来管理Java应用中的关系数据。主要是为简化现有的持久化开发工作和整合ORM技术。
    JPA是在吸收现有的Hibernate,TopLink,JDO等ORM框架的基础上发展而来的,具有易于使用,伸缩性强等优点。

    注意:JPA是一套规范,不是一套产品。

    SpringData 与JPA 的关系
    image.png
    image.png
    image.png

    SpringData JPA 快速入门

    1 .pom.xml 导入依赖

    <!--springdata jpa-->
    <dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <!--web-->
    <dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!---mysql-->
    <dependency>
       <groupId>mysql</groupId>
       <artifactId>mysql-connector-java</artifactId>
       <scope>runtime</scope>
    </dependency>
    

    2 .application.properties 配置SpringDataJPA

    #配置数据库
    spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
    spring.datasource.url=jdbc:mysql://localhost:3306/test?useUnicode=true&&characterEncoding=UTF-8&serverTimezone=UTC
    spring.datasource.username=root
    spring.datasource.password=123
    
    #支持sql输出
    spring.jpa.show-sql=true
    #format 一下 sql 进行输出
    spring.jpa.properties.hibernate.format_sql=true
    #自动生成开启,让表数据会自动跟随entity类的变化而变化
    spring.jpa.hibernate.ddl-auto=update
    #jpa对应的数据库类型
    spring.jpa.database=mysql
    

    3 . 实体类,自动对应数据库表

    @Data
    //该类是实体
    @Entity
    //对应表名
    @Table(name = "user")
    public class User {
    
        //主键
        @Id
        //自增长主键
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Integer id;
    
        /*
        //主键
        @Id
        //用uuid生成主键
        @GenericGenerator(name = "myuuid",strategy = "uuid")
        @GeneratedValue(generator = "myuuid")
        private Integer id;*/
    
        //name对应数据库字段;unique=ture值唯一
        @Column(name = "t_username",nullable = false,unique = true)
        private String username;
        @Column
        private String password;
    }
    

    4 .映射接口UserRepository

    /**
     * 实体类,主键类型
     * JpaRepository<TUser,Integer>
     */
    public interface UserRepository extends JpaRepository<TUser,Integer> {
        //模糊查找,命名会自动提示,按提示写,jpa会自动实现
        User findUserByUsernameLike(String username);
    }
    

    5 .Controller

    @RestController
    public class UserController {
    
        @Resource
        UserRepository userRepository;
    
        @GetMapping("/user/id/{id}")
        public Object findById(@PathVariable int id){
           // userRepository.findById(id).get() 为空的话会报500错误
            return userRepository.findById(id);
        }
    
        @GetMapping("/user")
        public User saveUser(User user){
            return userRepository.save(user);
        }
    //模糊查找
        @GetMapping("/user/username/{username}")
        public User saveUser(@PathVariable  String username){
            return userRepository.findUserByUsernameLike("%"+username+"%");
        }
    }
    

    JPA 单表sql 操作--关键字拼凑

    JpaRepository<T,ID>,自动提示


    image.png
    关键字拼凑 案例
    @Data //getter,setter,equals,hashcode,tostring
    @AllArgsConstructor
    @NoArgsConstructor
    @Builder
    @Entity
    @Table(name = "person")
    public class Person {
    
        @Id
        @GenericGenerator(name = "myuuid",strategy = "uuid")
        @GeneratedValue(generator = "myuuid")
        private String pid;
    
        @Column(unique = true)
        private String pname;
        @Column
        private String psex;
        @Column
        private Integer age;
        @Column
        private boolean getmarried;
    
    }
    

    PersonRepository

    /**
     *  sql 关键字 拼凑
     * 接口的名字必须按提示命名,除非自己实现
     */
    public interface PersonRepository extends JpaRepository<Person,String> {
    
        //查询年龄小于等于20的人
        List<Person> findAllByAgeIsLessThanEqual(Integer age);
    
        //查询年龄在20-22岁之间,并且性别是男的人
        List<Person> findAllByAgeBetweenAndPsexEquals(Integer lowage,Integer highage,String sex);
    
        //查询已结婚并且性别是男的人
        List<Person> findAllByGetmarriedIsTrueAndPsexEquals(String sex);
    
    }
    

    关键字拼凑无法解决问题

    1.实体类的属性名与表的字段名无法映射,导致关键字找不到
    2.CRUD操作方式比较另类或者是你不想用的关键字的写法
    3.涉及多表操作

    关键字注解手写sql语句

    1.使用sql语句来写sql
    2.使用HQL语句来写sql

    手写sql
    1.如果是 删改 操作,需要加上 @Modifying 和 @Transactioinal 注解
    2.如果是 SQL 语句,请在 @Query 注解上加上 NativeQuery=true 的属性
    3.传参的方式有2种:

    1.使用 ? 数字 的方式,数字从 1 开始,代表第几个参数
    2.使用 :参数名 的方式,这种方式最好配合 @Param 注解一起使用

    案例

    /**
     *  sql 关键字 拼凑
     */
    public interface PersonRepository extends JpaRepository<Person,String> {
    
        /**
         * 手写 SQl
         * 1.如果是 **删改** 操作,需要加上 @Modifying 和 @Transactioinal 注解
         * 2.如果是 SQL 语句,请在 @Query 注解上加上 NativeQuery=true 的属性
         * 3.传参的方式有2种:
         * > 1.使用 ?数字 的方式,数字从 **1** 开始,代表第几个参数
         * > 2.使用 :参数名 的方式,这种方式最好配合 **@Param** 注解一起使用
         */
        //根据名字来模糊删除一个person数据,Person对应的是实体类名
        // personRepository.deleteByName("%zh%");
        @Transactional
        @Modifying
        @Query(value = "delete from Person where pname like :pname")
        void deleteByName(@Param("pname") String pname);
    
        //personRepository.deleteByName_b("zh");
        @Transactional
        @Modifying
        @Query(value = "delete from Person where pname like %:pname%")
        void deleteByName_b(@Param("pname") String pname);
    
        //
        @Query(value = "select p from Person p where p.pname like ?1")
        List<Person> findByName_s(String pname);
    
        //HQL
        @Query(value = "select p from Person p where p.age between 20 and 30 and p.psex='女'")
        List<Person> findByNameHql();
    
        //SQL;nativeQuery = true
        @Query(value = "select * from Person where age between 20 and 30 and psex='女'",nativeQuery = true)
        List<Person> findByNameSql();
    
        //SQL;nativeQuery = true;参数是单个的值
        @Query(value = "select * from Person where age between :lowAge and :highAge and psex=:sex",nativeQuery = true)
        List<Person> findByNameSql_parm(@Param("lowAge") Integer lowAge,
                                        @Param("highAge") Integer highAge,
                                        @Param("sex") String sex);
        
        //SQL;nativeQuery = true;参数是对象
        @Query(value = "select * from Person where pname=:#{#person.pname}",nativeQuery = true)
        List<Person> findByNameSql_parm_p(@Param("person") Person person);
    
        //使用SPEL表达式;参数是对象
        @Transactional
        @Modifying
        @Query(value = "update person set pname=:#{#person.pname},psex=:#{#person.psex},age=:#{#person.age} " +
                "where pid=:#{#person.pid}",nativeQuery = true)
        void updatePerson(@Param("person") Person person);
    
        //使用SPEL表达式;参数是单个的值
        @Transactional
        @Modifying
        @Query(value = "update person set pname=:#{#p_name},psex=:#{#p_sex},age=:#{#p_age} " +
                "where pid=:#{#p_id}",nativeQuery = true)
        void updatePerson_dan(@Param("p_name") String name,
                              @Param("p_sex") String sex,
                              @Param("p_age") Integer age,
                              @Param("p_id") String pid);
    }
    
    
    Spring Data JPA 逆向工程操作和多表查询

    1.使用数据接口

    构建一个数据接口,里面的抽象方法就是SQL语句的查询结果的字段对应的getXXXX的抽象方法;
    接收查询字段,必须要为查询的字段名起别名,否则会无法取到

    2.使用集合

    直接使用 List/Map 等集合嵌套的方式来获取接收数据

    3.使用OV (View Object)

    单独构建一个跟页面展示数据对应的VO的实体类来接收数据

    Book

    //IDEA 逆向生成的entity
    @Entity
    @Table(name = "book", schema = "mall")
    public class Book {
        private int bid;
        private String bname;
        private BigDecimal bprice;
        private String pid;
    
        @Id
        @Column(name = "BID")
        public int getBid() {
            return bid;
        }
    
        public void setBid(int bid) {
            this.bid = bid;
        }
    
        @Basic
        @Column(name = "BNAME")
        public String getBname() {
            return bname;
        }
    
        public void setBname(String bname) {
            this.bname = bname;
        }
    
        @Basic
        @Column(name = "BPRICE")
        public BigDecimal getBprice() {
            return bprice;
        }
    
        public void setBprice(BigDecimal bprice) {
            this.bprice = bprice;
        }
    
        @Basic
        @Column(name = "PID")
        public String getPid() {
            return pid;
        }
    
        public void setPid(String pid) {
            this.pid = pid;
        }
    
        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            Book that = (Book) o;
            return bid == that.bid &&
                    Objects.equals(bname, that.bname) &&
                    Objects.equals(bprice, that.bprice) &&
                    Objects.equals(pid, that.pid);
        }
    
        @Override
        public int hashCode() {
            return Objects.hash(bid, bname, bprice, pid);
        }
    }
    

    PersonRepository

    /**
     *  sql 关键字 拼凑
     */
    public interface PersonRepository extends JpaRepository<Person,String> {
    
        /**
         * 手写 SQl
         * 1.如果是 **删改** 操作,需要加上 @Modifying 和 @Transactioinal 注解
         * 2.如果是 SQL 语句,请在 @Query 注解上加上 NativeQuery=true 的属性
         * 3.传参的方式有2种:
         * > 1.使用 ?数字 的方式,数字从 **1** 开始,代表第几个参数
         * > 2.使用 :参数名 的方式,这种方式最好配合 **@Param** 注解一起使用
         */
        //根据名字来模糊删除一个person数据,Person对应的是实体类名
        // personRepository.deleteByName("%zh%");
        @Transactional
        @Modifying
        @Query(value = "delete from Person where pname like :pname")
        void deleteByName(@Param("pname") String pname);
    
        //personRepository.deleteByName_b("zh");
        @Transactional
        @Modifying
        @Query(value = "delete from Person where pname like %:pname%")
        void deleteByName_b(@Param("pname") String pname);
    
        //链表查询-根据书名来查询该书籍拥有者
        @Query(value = "select p from Person p inner join Book b on p.pid = b.pid where " +
                "b.bname=:bname")
        Person findPersonByName(@Param("bname") String bname);
    
        //联表查询 -根据用户id来person和book
        //接口来接收查询结果
        @Query(value = "select p.pid as pid,p.pname as pname," +
                "p.age as page,"+
                "p.psex as psex,p.getmarried as getmarried," +
                "b.bid as bid,b.bname as bname,b.bprice as bprice " +
                "from Person p inner join Book b on p.pid=b.pid " +
                "where p.pid=:pid")
        List<PersonInfo> findAllInfo(@Param("pid") String pid);
    
        //联表查询 -根据用户id来person和book
        //集合Object来接收查询结果
        @Query(value = "select p.pid as pid,p.pname as pname," +
                "p.age as page,"+
                "p.psex as psex,p.getmarried as getmarried," +
                "b.bid as bid,b.bname as bname,b.bprice as bprice " +
                "from Person p inner join Book b on p.pid=b.pid " +
                "where p.pid=:pid")
        List<Object> findAllInfo_c(@Param("pid") String pid);
    
        //联表查询 -根据用户id来person和book
        //集合Map<String,Object>来接收查询结果
        @Query(value = "select p.pid as pid,p.pname as pname," +
                "p.age as page,"+
                "p.psex as psex,p.getmarried as getmarried," +
                "b.bid as bid,b.bname as bname,b.bprice as bprice " +
                "from Person p inner join Book b on p.pid=b.pid " +
                "where p.pid=:pid")
        List<Map<String,Object>> findAllInfo_m(@Param("pid") String pid);
    
    }
    

    相关文章

      网友评论

          本文标题:SpringBoot 2.x 数据库访问中间件JPA

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