SpringBoot_12 JPA

作者: o______o | 来源:发表于2019-07-10 17:51 被阅读0次

    Spring Boot可以自动配置嵌入式H2HSQLDerby数据库。您无需提供任何连接URL。您只需要包含要使用的嵌入式数据库的构建依赖项即可。

    典型的嵌入式数据库POM依赖配置


    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <dependency>
        <groupId>org.hsqldb</groupId>
        <artifactId>hsqldb</artifactId>
        <scope>runtime</scope>
    </dependency>
    
    声明对Spring Data模块的依赖关系

    <dependencies>
      <dependency>
        <groupId>org.springframework.data</groupId>
        <artifactId>spring-data-jpa</artifactId>
      </dependency>
    <dependencies>
    

    连接到生产数据库(MySQL)


    application.properties:

    spring.datasource.url=jdbc:mysql://localhost/test
    spring.datasource.username=root
    spring.datasource.password=passwd
    spring.datasource.driver-class-name=com.mysql.jdbc.Driver
    

    至少应该通过设置spring.datasource.url 属性来指定URL 。否则,Spring Boot会尝试自动配置嵌入式数据库

    通常不需要指定driver-class-name,因为Spring Boot可以从URL推断它的驱动类型

    Spring Data Repositories

    核心概念


    Spring Data存储库抽象中的中央接口是Repository。它将域类(对应数据库中的表或者NOSQL中的文档)以及域类的ID类型(主键)作为类型参数进行管理。此接口主要用作标记接口,用于捕获要使用的类型,并帮助您发现扩展此接口的接口。CrudRepository则规定了对于正在管理的实体类复杂的CRUD功能

    CrudRepository接口


    public interface CrudRepository<T, ID extends Serializable> extends Repository<T, ID> {
      <S extends T> S save(S entity);      
      Optional<T> findById(ID primaryKey); 
      Iterable<T> findAll();               
      long count();                        
      void delete(T entity);               
      boolean existsById(ID primaryKey);   
      // … 其他
    }
    
    • 保存给定的实体。
    • 返回由给定ID标识的实体。
    • 返回所有实体。
    • 返回实体数量。
    • 删除给定的实体。
    • 指示是否存在具有给定ID的实体。

    PagingAndSortingRepository接口


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

    要访问User页面大小为20 的第二页,您可以执行以下操作:

    PagingAndSortingRepository<User, Long> repository = // … get access to a bean
    Page<User> users = repository.findAll(PageRequest.of(1, 20));
    

    派生1:计数查询


    interface UserRepository extends CrudRepository<User, Long> {
      long countByLastname(String lastname);
    }
    

    派生2:删除查询的接口定义


    interface UserRepository extends CrudRepository<User, Long> {
      long deleteByLastname(String lastname);
      List<User> removeByLastname(String lastname);
    }
    

    派生规则:基于方法名解析的概念


    JpaRepository支持接口规范方法名查询。意思是如果在接口中定义的查询方法符合它的命名规则,就可以不用写实现。

    例如:findByName这个方法表示从数据库中查询Name这个属性等于XXX的所有记录,类似于SQL语句:select * from xxTable where name=xxx这种形式
    这段话有两个重点:

    • 方法名需要在接口中设定
    • 必须符合一定的命名规范

    方法名构造方法


    find+全局修饰+By+实体的属性名称+限定词+连接词+ ...(其它实体属性)
    +OrderBy+排序属性+排序方向 例如:findDistinctByFirstNameIgnoreCaseAndLastNameOrderByAgeDesc(
    String firstName,String lastName)
    {......}

    其中:Distinct是全局修饰(非必须),FirstName和LastName是实体的属性名,And是连接词,IgnoreCase是限定词,Age是排序属性,Desc是排序方向,限定词和连接词统称为“关键词”。

    支持的关键词


    Keyword Sample JPQL snippet
    And findByLastnameAndFirstname … where x.lastname = ?1 and x.firstname = ?2
    Or findByLastnameOrFirstname … where x.lastname = ?1 or x.firstname = ?2
    Is,Equals findByFirstname,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 findByFirstnameContainin … 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<Age> ages) … where x.age in ?1
    NotIn findByAgeNotIn(Collection<Age> ages) … where x.age not in ?1
    True findByActiveTrue() … where x.active = true
    False findByActiveFalse() … where x.active = false
    IgnoreCase findByFirstnameIgnoreCase … where UPPER(x.firstame) = UPPER(?1)

    @data(省略get和set)


    IDE安装lombok插件同时pom文件添加如下配置

    <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.8</version>
        <scope>provided</scope>
    </dependency>
    

    实例:

    import lombok.Data;
    @Data
    public class User {
        private Integer id;
        private String name;
        private String password;
    }
    

    使用方法:

    public static void main(String[] args){
        User u=new User ();
        u.setId(1);
        u.setName("aName");
        u.setPassword("aPasswd");
        System.out.println(u);
    }
    

    JPA接口查询实例


    第一步:对应表和实体类直接的关系

    package com.pojo;
    import javax.persistence.Entity;
    import javax.persistence.GeneratedValue;
    import javax.persistence.Id;
    import javax.persistence.Table;
    import lombok.Data;
    /*
    实体中常用的注解:
    @Entity :声明这个类是一个实体类
    @Table:指定映射到数据库的表
    @Id :映射到数据库表的主键属性,一个实体只能有一个属性被映射为主键
    @GeneratedValue:主键的生成策略
     * */
    @Data
    @Entity
    @Table(name="user")
    public class User {
        @Id
        @GeneratedValue
        private Integer id;
        private String name;
        private String password;
    }
    

    第二步:完成接口配置

    package com.dao;
    import org.springframework.data.repository.CrudRepository;
    import org.springframework.stereotype.Repository;
    @Repository
    public interface CrudReal  extends CrudRepository<User, Integer>{}
    

    第三步:直接用

    package com.controller;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    import com.dao.CrudReal;
    import com.pojo.User;
    @RestController
    public class DataCRUD {
        
        @Autowired
        private CrudReal crudReal;
        
        @GetMapping("/dataSave")
        public String toRedict() {
            User u=new User ();
            u.setId(1);
            u.setName("aName");
            u.setPassword("aPasswd");
           
            crudReal.save(u);
            crudReal.findAll().iterator().forEachRemaining(a->System.out.println(a.toString()));
            return ""+crudReal.count();
        }
    }
    

    事务


    默认情况下,接口上可用的CRUD方法都是事务性的

    调整事务配置(定义多个存储库调用的事务)


    @Service
    class UserManagementImpl implements UserManagement {
    
      private final UserRepository userRepository;
      private final RoleRepository roleRepository;
    
      @Autowired
      public UserManagementImpl(UserRepository userRepository,
        RoleRepository roleRepository) {
        this.userRepository = userRepository;
        this.roleRepository = roleRepository;
      }
    
      @Transactional
      public void addRoleToAllUsers(String roleName) {
    
        Role role = roleRepository.findByName(roleName);
    
        for (User user : userRepository.findAll()) {
          user.addRole(role);
          userRepository.save(user);
        }
    }
    

    MySQL数据库使用实例


    为了测试使用mysql,特意从spring官网下的依赖pom文件,选了jpa和mysql等

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.1.6.RELEASE</version>
            <relativePath/> <!-- lookup parent from repository -->
        </parent>
        <groupId>com.hjc</groupId>
        <artifactId>jpaTest</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <name>jpaTest</name>
        <description>Demo project for Spring Boot</description>
        <properties>
            <java.version>1.8</java.version>
        </properties>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-data-jpa</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-devtools</artifactId>
                <scope>runtime</scope>
                <optional>true</optional>
            </dependency>
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <scope>runtime</scope>
            </dependency>
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <optional>true</optional>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
        </dependencies>
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
            </plugins>
        </build>
    </project>
    

    SQL配置:

    spring.datasource.url=jdbc:mysql://localhost/test?useUnicode=true&serverTimezone=UTC
    spring.datasource.username=用户名
    spring.datasource.password=用户密码
    

    配置了连接的地址和数据库以及用户名密码后

    报错1:时区不对
    URL加上serverTimezone=UTC

    错误2:表找不到
    没办法,初学者自己建动手建表,但懒人没办法,不想动手,那就动脑,用power designer设计表模型,然后自动生成建表的SQL文件,百度power designer教程一堆的,不解释。

    错误3,关键是table hibernate_sequence doesn't exist四处百度搜索发现是主键自增出了问题。后来找到一个解决办法,如下:
    首先修改注解@GeneratedValue

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

    修改主键自增策略,随后在数据库表的主键那里也要

    mysql> create table user (
        id int(11) not null auto_increment primary key,
        name varchar(20),
        password varchar(20)
        );
    

    加一个auto_increment来让其自增,这样后就可以了。


    想着后来可能会连接到其他的表里面,列名不一致何解?于是找了设置对应属性名和列名的注解

    @Column(name="user_name")
    private String name;
    

    这样就可以将属性name对应到表里面的user_name列了。


    要是想看自动执行了哪些SQL语句怎么办?在配置文件里面添加如下语句即可

    spring.jpa.show-sql=true 
    

    附加


    在父类接口里面找了许久都没有发现update开头的方法,百度了其他人的说法才知道原来save开始的既有添加也有修改的含义。后来为了方便执行一些复杂查询或修改语句找了下面的代码实现:

    @Query(nativeQuery = true, value = "select * from user where name=:name  or age=:girls_age ")
    List<User> findUsersByAgeAndName(@Param("name") String name, @Param("girls_age") Integer age);
    
    @Transactional
    @Modifying
    @Query(nativeQuery = true, value = "update user set username=:name where id=:id")
    public void updateOneUsers(@Param("id")Long id, @Param("name")String name);
    

    @Modifying@Transactional在修改的时候加,查询的时候就没必要加了。表示要修改一个数据且别人不能动(事务)。

    相关文章

      网友评论

        本文标题:SpringBoot_12 JPA

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