• spring-boot-starter-data-jpa 解析


    网上看到的,记录一下,原文:https://blog.csdn.net/Lee_Ho_/article/details/81014215

    一:引言
        对于传统关系型数据库,Spring Boot使用JPA(Java Persistence API)资源库来实现对数据库的操作,简单来说,JPA就是为POJO(Plain Ordinary Java Object)提供持久化的标准规范,即将Java普通对象通过对象关系映射(Object Relational Mapping,ORM)持久化到数据库中。

    二:使用方式
    2.1:JPA配置
        为了使用JPA和MySQL,创建Spring Boot的Maven工程,在POM文件当中引入如下依赖:

    <?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>

    <groupId>com.example</groupId>
    <artifactId>spring-boot-jpa</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>spring-boot-jpa</name>
    <description>Demo project for Spring Boot</description>

    <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.0.3.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <java.version>1.8</java.version>
    </properties>

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

    <dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
    </dependency>
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
    </dependency>
    </dependencies>

    <build>
    <finalName>jpa</finalName>
    <plugins>
    <plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <executions>
    <execution>
    <goals>
    <goal>
    repackage
    </goal>
    </goals>
    </execution>
    </executions>
    </plugin>
    </plugins>
    </build>


    </project>
    application.yml配置:

    spring:
    datasource:
    url: jdbc:mysql://localhost:3306/test?characterEncoding=utf8
    username: root
    password: cuoai1995
    jpa:
    database: mysql
    show-sql: true
    #Hibernate ddl auto (validate|create|create-drop|update)
    hibernate:
    ddl-auto: update
    naming-strategy: org.hibernate.cfg.ImprovedNamingStrategy
    properties:
    hibernate:
    dialect: org.hibernate.dialect.MySQL5Dialect

    2.2:实体建模:
        为了演示JPA的使用方式,建立适当的实体关系,并演示如何通过注解方式实现实体建模:

    实体之间的关系如下图所示:

    根据图上关系进行实体建模:

    部门类:

    import javax.persistence.*;
    import java.io.Serializable;

    @Entity
    @Table(name = "department")
    public class Department implements Serializable{

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

    public Long getId() {
    return id;
    }

    public void setId(Long id) {
    this.id = id;
    }

    public String getName() {
    return name;
    }

    public void setName(String name) {
    this.name = name;
    }
    }
    角色类:

    import javax.persistence.*;
    import java.io.Serializable;

    @Entity
    @Table(name = "role")
    public class Role implements Serializable {

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

    public Long getId() {
    return id;
    }

    public void setId(Long id) {
    this.id = id;
    }

    public String getName() {
    return name;
    }

    public void setName(String name) {
    this.name = name;
    }
    }
    用户类(getter and setter...):

    import com.fasterxml.jackson.annotation.JsonBackReference;
    import org.springframework.format.annotation.DateTimeFormat;

    import javax.persistence.*;
    import java.io.Serializable;
    import java.util.Date;
    import java.util.List;

    @Entity
    @Table(name = "user")
    public class User implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private Date createDate;

    @ManyToOne
    @JoinColumn(name = "did")
    @JsonBackReference
    private Department department;

    @ManyToMany(cascade = {}, fetch = FetchType.EAGER)
    @JoinTable(name = "user_role", joinColumns = {@JoinColumn(name = "user_id")},
    inverseJoinColumns = {@JoinColumn(name = "roles_id")})
    private List<Role> roles;
    这里使用了一张新表user_role来表示用户表和角色表多对多的依赖关系。

    2.3:Spring Boot配置JPA测试环境:
    创建JPA的配置类:JpaConfiguration,相关说明见配置类注释:

    import org.springframework.boot.autoconfigure.domain.EntityScan;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.core.Ordered;
    import org.springframework.core.annotation.Order;
    import org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor;
    import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
    import org.springframework.transaction.annotation.EnableTransactionManagement;

    @Order(Ordered.HIGHEST_PRECEDENCE)//定义组件的加载顺序,这里为最高级
    @Configuration//表明这是一个配置类
    @EnableTransactionManagement(proxyTargetClass = true)//启用JPA的事物管理
    @EnableJpaRepositories(basePackages = "com.example.springbootjpa.repository")//启动JPA资源库并设置接口资源库的位置
    @EntityScan(basePackages = "com.example.springbootjpa.pojo")//实体类位置
    public class JpaConfiguration {

    /**
    * @Description: 这里说明为什么要声明一个PersistenceExceptionTranslationPostProcessor 的Bean对象,引用Spring官方文档的一句话:
    * (1)scanned by Spring component-scanning
    * (2)catch platformspecific exceptions and rethrow them as one of Spring’s unified unchecked exceptions
    But if you’re using Hibernate contextual sessions and not a Hibernate template,how can the exception
    translation take place?
    翻译过来就是:@Repository有两作用:
    (1):用于被容器扫描:
    (2):捕获平台特定的异常并将它们重新抛出,作为Spring的一个未检查的异常。(用于事务的管理,例如捕获异常回滚)
    但是,如果您使用的是Hibernate contextual sessions上下文会话而不是Hibernate template,那么异常转换是如何发生的呢?
    那么,这就是配置这个类的作用。
    * @return
    */
    @Bean
    PersistenceExceptionTranslationPostProcessor persistenceExceptionTranslationPostProcessor(){
    return new PersistenceExceptionTranslationPostProcessor();
    }
    }
    三:创建实体对应的Jpa接口
    用户接口:

    import com.example.springbootjpa.pojo.User;
    import org.springframework.data.jpa.repository.JpaRepository;
    import org.springframework.stereotype.Repository;

    @Repository
    public interface UserRepository extends JpaRepository<User, Long> {

    User findByName(String name);
    }
    部门接口:

    import com.example.springbootjpa.pojo.Department;
    import org.springframework.data.jpa.repository.JpaRepository;
    import org.springframework.stereotype.Repository;

    @Repository
    public interface DepartmentRepository extends JpaRepository<Department, Long> {
    }
    角色接口:

    import com.example.springbootjpa.pojo.Role;
    import org.springframework.data.jpa.repository.JpaRepository;
    import org.springframework.stereotype.Repository;

    @Repository
    public interface RoleRepository extends JpaRepository<Role, Long> {
    }
    四:测试
        在做完如上工作之后,就可以进行下一步测试了。

    import com.example.springbootjpa.pojo.Department;
    import com.example.springbootjpa.pojo.Role;
    import com.example.springbootjpa.pojo.User;
    import com.example.springbootjpa.repository.DepartmentRepository;
    import com.example.springbootjpa.repository.RoleRepository;
    import com.example.springbootjpa.repository.UserRepository;
    import org.junit.Assert;
    import org.junit.Before;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.data.domain.Page;
    import org.springframework.data.domain.PageRequest;
    import org.springframework.data.domain.Pageable;
    import org.springframework.data.domain.Sort;
    import org.springframework.test.context.junit4.SpringRunner;

    import java.util.Date;
    import java.util.List;

    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class MysqlTest {

    private static Logger logger = LoggerFactory.getLogger(MysqlTest.class);

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private DepartmentRepository departmentRepository;

    @Autowired
    private RoleRepository roleRepository;

    @Before
    public void initData(){
    userRepository.deleteAll();
    roleRepository.deleteAll();
    departmentRepository.deleteAll();

    Department department = new Department();
    department.setName("开发部");
    departmentRepository.save(department);
    Assert.assertNotNull(department.getId());

    Role role = new Role();
    role.setName("admin");
    roleRepository.save(role);
    Assert.assertNotNull(role.getId());

    User user = new User();
    user.setName("user");
    user.setCreateDate(new Date());
    user.setDepartment(department);
    List<Role> roles = roleRepository.findAll();
    Assert.assertNotNull(roles);
    user.setRoles(roles);
    userRepository.save(user);
    Assert.assertNotNull(user.getId());
    }

    @Test
    public void findPage(){
    Pageable pageable = PageRequest.of(0, 10, new Sort(Sort.Direction.ASC, "id"));
    Page<User> page = userRepository.findAll(pageable);
    Assert.assertNotNull(page);
    for (User user : page.getContent()){
    logger.info("====user==== user name:{}, department name:{}, role name:{}", user.getName(),
    user.getDepartment().getName(), user.getRoles().get(0).getName());
    }
    }

    @Test
    public void testFindByName(){
    String name = "user";
    User user = userRepository.findByName(name);
    Assert.assertNotNull(user);
    logger.info(user.getName());
    }
    }
    结果:

    六:总结
    一:为什么要继承JpaRepository?

    以UserRepository为例,来看看整个的继承体系:

    可见,Jpa资源库已经给我们提供了丰富的方法来满足普通的操作需求。

    二:自定义方法的实现:

    Jpa本身还提供了一些自定义声明方法的规则,例如:在接口中使用关键字findBy、readBy、getBy作为方法名的前缀,拼接实体类中的属性字段(首字母大写),并可选择拼接一些SQL关键字来组合成一个查询方法,例如,对于用户实体,关键字可以这样使用:

    1.And,如:findByIdAndName(Long id, String name);

    2.Or,如:findByIdOrName(Long id, String name);

    3.Between,如:findByCreateDateBetween(Date start, Date end);

    4.LessThan,如:findByCreateDateLessThan(Date start);

    5.GreaterThan,如:findByCreateDateGreaterThan(Date start);

    6.IsNull,如:findByNameIsNull();

    7.IsNotNull,与上等价

    8.Like,如:findByNameLike(String name);

    9.NotLike:与上等价

    10.OrderBy,如:findByNameOrderByIdAsc(String name);

    11.Not,如:findByNameNot(String name);

    12.In,如:findByNameIn(Collection<String> nameList);

    13.NotIn,与上等价。

    加入说上面这些还是不能够满足你的业务需求,你同样可以写一个自定义的方法,使用@Query注解+HQL语句实现你想要的效果。
    ---------------------
    版权声明:本文为CSDN博主「笼中人.」的原创文章,遵循CC 4.0 by-sa版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/Lee_Ho_/article/details/81014215

  • 相关阅读:
    sql语句 之聚合函数
    UML类图几种关系的总结
    关于Object.defineProperty的get和set
    devDependencies和dependencies的区别
    函数声明和函数表达式的区别
    移动端滑屏滚动事件的问题(横向滑动阻止垂直页面滚动)
    使用Cordova和JQM在ios上需要注意的问题
    阻止事件冒泡,阻止默认事件,event.stopPropagation()和event.preventDefault(),return fal的区别
    有关闭包的总结
    CSS命名规范——BEM思想(非常赞的规范)
  • 原文地址:https://www.cnblogs.com/linwenbin/p/11357368.html
Copyright © 2020-2023  润新知