Spring Data JPA实现数据库访问

1.创建子模块

右键点击工程名[mapcloudservice] --> New --> Module --> 选择Maven -->设置子模块的名称[datamanager] --> Finish
创建成功后如下图所示:
在这里插入图片描述

2.配置pom.xml

<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-data-rest</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.19</version>
            <scope>runtime</scope>
        </dependency>
    </dependencies>

查看该项目的依赖关系图:
方法一:右键点击pom.xml文件中的任意处 --> Diagrams --> Show Dependencies
方法二:打开Maven工具栏,选择 Show Dependencies

3.配置数据源

3.1 配置application.yml

首先在目录/src/main/resources下创建application.yml,配置内容示例如下:

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/db_example?serverTimezone=UTC&useSSL=true&autoReconnect=true&failOverReadOnly=false
    username: chaoshui
    password: 123456
  jpa:
    database: mysql
    show-sql: true
    hibernate:
      ddl-auto: update
      naming:
        physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
    open-in-view: false
3.2 注意事项

  命名策略physical-strategy使用:org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl,Hibernate 会默认以实体名和属性名分别作为表名及字段名进行映射,但是如果添加了注解@Table和@Column,则以注解属性值进行映射命名。

4.创建Entity类

entity用于关联映射数据库中的一张表,entity类需要完成以下几项工作:
(1)注解
  @Entity:表明这是一个实体类,与指定的数据库表进行映射
  @Id:该属性映射为数据库的主键
  @GeneratedValue:默认使用主键生成方式为自增,hibernate会自动生成一个名为HIBERNATE_SEQUENCE的序列
  @Table:指定映射的表名,若没有则根据类的名称进行映射
  @Column:指定映射的字段名
  @OneToOne/@OneToMany/ManyToOne:一对一、一对多、多对一的关联
  
(2)定义属性,类型为私有
(3)创建所有属性所对应的setter和getter方法
(4)创建带参数的构造器和无参数的构造函数
(5)重写父类中的eauals()方法和hashcode()方法
(6)实现序列化并赋予其一个版本号。
示例代码:

package com.emapgo.datamanager.entity;

import net.bytebuddy.implementation.HashCodeMethod;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cglib.core.HashCodeCustomizer;
import sun.security.util.AuthResources_pt_BR;

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

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

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "clientID")
    private String clientID;

    @Column(name = "username")
    private String username;
    @Column(name = "password")
    private String password;
    @Column(name = "credentials")
    private String credentials;
    @Column(name = "grantType")
    private String grantType;
    @Column(name = "accessToken")
    private String accessToken;
    @Column(name = "tokenType")
    private String tokenType;
    @Column(name = "expireIN")
    private String expireIN;
    @Column(name = "scope")
    private String scope;

    public UserManage(){}

    public UserManage(String _clientID,
                      String _username,
                      String _password,
                      String _credentials,
                      String _grantType,
                      String _accessToken,
                      String _tokenType,
                      String _expireIN,
                      String _scope){
        this.clientID = _clientID;
        this.username = _username;
        this.password = _password;
        this.credentials = _credentials;
        this.grantType = _grantType;
        this.accessToken = _accessToken;
        this.tokenType = _tokenType;
        this.expireIN = _expireIN;
        this.scope = _scope;
    }

    // getter and setter methods
    public String getClientID() {
        return clientID;
    }
    public String getUsername() {
        return username;
    }
    public String getPassword() {
        return password;
    }
    public String getCredentials() {
        return credentials;
    }
    public String getGrantType() {
        return grantType;
    }
    public String getAccessToken() {
        return accessToken;
    }
    public String getTokenType() {
        return tokenType;
    }
    public String getExpireIN() {
        return expireIN;
    }
    public String getScope() {
        return scope;
    }
    public void setClientID(String clientID) {
        this.clientID = clientID;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public void setPassword(String password) {
        this.password = password;
    }
    public void setCredentials(String credentials) {
        this.credentials = credentials;
    }
    public void setGrantType(String grantType) {
        this.grantType = grantType;
    }
    public void setAccessToken(String accessToken) {
        this.accessToken = accessToken;
    }
    public void setTokenType(String tokenType) {
        this.tokenType = tokenType;
    }
    public void setExpireIN(String expireIN) {
        this.expireIN = expireIN;
    }
    public void setScope(String scope) {
        this.scope = scope;
    }
    
    @Override
    public String toString(){
        return  "Table-UserManage: " + "(" + this.clientID + "," + this.username + "," +
                this.password + "," + this.credentials + "," +
                this.grantType + "," + this.accessToken + "," +
                this.expireIN + "," + this.scope + ")\n";
    }

    // @Override
    // public int hashCode(){}

    // @Override
    // public boolean equals(Object obj){
    //     if(this == obj){
    //         return true;
    //     }
    //     if(obj == null || (getClass() != obj.getClass())){
    //         return false;
    //     }

    //     UserManage other = (UserManage) obj;
    //     if(!this.clientID.equals(other.clientID)){
    //         return false;
    //     }
    //     return true;
    // }
}

5.创建Repository接口

5.1创建repository接口

目的是通过repository访问MySQL数据库。

(1) 需要添加entity的类型和ID的类型用于表示关联哪个entity。
(2) 增删改查等操作方法只需按照书写规范进行声明,不需要实现,spring data jpa会在运行程序时根据方法名称自动创建相关的实现,如下图所示是CrudRepository接口中的全部方法

@NoRepositoryBean
public interface CrudRepository<T, ID> extends Repository<T, ID> {
	// 保存指定的entity
    <S extends T> S save(S var1);
	// 保存所有的entity
    <S extends T> Iterable<S> saveAll(Iterable<S> var1);
	// 根据指定属性返回entity
    Optional<T> findById(ID var1);
	// 判断具有指定属性的entity是否存在
    boolean existsById(ID var1);
	// 返回全部entity
    Iterable<T> findAll();
	// 根据指定属性返回全部entity
    Iterable<T> findAllById(Iterable<ID> var1);
	// 返回entity的数量
    long count();
	// 根据指定的属性删除entity
    void deleteById(ID var1);
	// 删除指定的entity
    void delete(T var1);
	// 删除全部entity
	void deleteAll();
   
	void deleteAll(Iterable<? extends T> var1);   
}

(3) 方法名支持的Query关键字:

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, Null findByAge(Is)Null … 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 findByFirstnameContaining … 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 ages) … where x.age in ?1
NotIn findByAgeNotIn(Collection 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)

(4) 可以继承的接口有四个:

Repository
CrudRepository
PagingAndSortingRepository
QueryByExampleExecutor

接口间继承关系如下:
在这里插入图片描述

5.2基于Query注解的CRUD

  在继承JpaRepository接口的方法中,可以在自定义的查询方法上使用@Query,来指定该方法要执行的自定义的查询语句。其中的value值可以是任意的查询语句,同样只需要进行方法的定义,无需进行实现。

5.3示例代码
package com.emapgo.datamanager.repository;

import com.emapgo.datamanager.entity.UserManage;
import org.springframework.data.repository.CrudRepository;
import java.util.List;

public interface UserManageRepository extends CrudRepository<UserManage, String>
{
    // find
    List<UserManage> findAllByClientID(String clientID);
    List<UserManage> findAllByUsername(String username);
    List<UserManage> findAllByPassword(String password);
    List<UserManage> findAllByCredentials(String credentials);
    List<UserManage> findAllByGrantType(String grantType);
    List<UserManage> findAllByAccessToken(String accessToken);
    List<UserManage> findAllByTokenType(String tokenType);
    List<UserManage> findAllByExpireIN(String expireIN);
    List<UserManage> findAllByScope(String scope);

    UserManage findByClientID(String clientID);
    UserManage findByUsername(String username);
    UserManage findByPassword(String password);
    UserManage findByCredentials(String credentials);
    UserManage findByGrantType(String grantType);
    UserManage findByAccessToken(String accessToken);
    UserManage findByTokenType(String tokenType);
    UserManage findByExpireIN(String expireIN);
    UserManage findByScope(String scope);

    UserManage findByClientIDAndAccessToken(String cleintID, String accessToken);
    // ...等等

    // save
    // 略

    // update
    @Modifying
    @Transactional
    @Query(value = "update UserManage um set um.username = ?1 where um.clientID = ?2", nativeQuery = true)
    public void UpdateUsernameByClientID(String username, String clientID);
    //  ...等等

    // delete
    @Modifying
    @Transactional
    int deleteByClientID(String clientID);
    //  ...等等
}
5.3选择性暴露部分CRUD方法

示例如下

@NoRepositoryBean
interface BaseRepository<T, ID> extends Repository<T, ID> {
	Optional<T> findById(ID id);
	<S extends T> S save(S entity);
}
interface UserManageRepository extends BaseRepository<User, Long> {
	// 略
}

6.创建Controller

7.添加主程序,测试

@SpringBootApplication
public class datamanageapplication {
    @Autowired
    UserManageRepository umr;

    public static void main(String[] args) {
        SpringApplication.run(datamanageapplication.class, args);
    }
    @Bean
    public CommandLineRunner userManageDemo(){
        System.out.println("-----------------------> **hello world** <-------------------------");

        return (args) -> {
            // insert
            umr.save(new UserManage("client_00", "lingwen_00", "123456_00", "creden_00", "grant_00","access_00", "token_00", "expire_00", "scope_00"));
            umr.save(new UserManage("client_01", "lingwen_01", "123456_01", "creden_01", "grant_01","access_01", "token_01", "expire_01", "scope_01"));


            // update
            umr.UpdateUsernameByClientID("lingwen_01", "client_00");
            System.out.println("Updated OK!");

            // fetch all records
            System.out.println("usermanager found with findAll(): ");
            System.out.println("----------------------------------");
            for(UserManage um : umr.findAll()){
                System.out.println(um.toString());
            }
            System.out.println();

            // fetch all records by clientID
            List<UserManage> um1 = umr.findAllByClientID("client_00");
            System.out.println("user manage found with findById(1L):");
            System.out.println("-----------------------------");
            System.out.println(um1.toString());

            // fetch all records by grant_type
            UserManage um2 = umr.findByScope("scope_00");
            System.out.println("user manage found with findById(2L):");
            System.out.println("-----------------------------");
            if(um2 != null){
                System.out.println(um2.toString());
            }else {
                System.out.println("cannot find any record that have attribute 'scope_00' in table UserManage!");
            }
            System.out.println();

            // fetch all user manage by ******
            // 略

            // delete
            umr.deleteByClientID("client_08");
            System.out.println("deleted OK!");

        };

   }


}

8.可能遇到的问题

写entity类的时候,相关注解会出现红色波浪线,并且在最终运行程序的时候会失败(但是底层Hibernate显示可以连接上数据库),如下图所示
在这里插入图片描述
解决方法:

  1. 点击View --> ToolWindows -> Persistence,在左下区域出现Persistence
    在这里插入图片描述
  2. 右键点击Entity --> Generate Persistence Mapping --> By Database Schema,在弹出的对话框中选择Choose Data Source
    在这里插入图片描述
  3. 配置好数据库相关的选项,可以点击Test Connection测试能否连接成功
    在这里插入图片描述
  4. 完了之后点击OK, 回到上一个对话框,点击Database Schema mapping下的刷新,选中UserManage表 --> OK (必须点刷新,不点刷新不会自动出现这些内容)
    在这里插入图片描述
  5. 右键单击Entity --> Assign Datasource 配置数据源
    在这里插入图片描述
    配置完以后,红色波浪线消失,程序能够正常运行,增删改查等操作执行也没有问题
    在这里插入图片描述
  6. 原因分析:暂时不清楚

参考资料

1.Spring Data JPA - Reference Documentation
2.Accessing Data with Spring Data JPA and MySQL
3.Getting Started with Spring Data JPA
4.spring data jpa 实战之增删改查(干货!你想要的查询!)
5.Spring Data JPARepository Example
其他相关参考资料:
Create your first Java application
Spring MVC框架入门教程
MySQL Java tutorial

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章