工作生活

SpringBoot_12 JPA

2019-07-10  本文已影响0人  o______o

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);   
  // … 其他
}

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在修改的时候加,查询的时候就没必要加了。表示要修改一个数据且别人不能动(事务)。

上一篇下一篇

猜你喜欢

热点阅读