1. 程式人生 > >Spring Boot2(九):整合Jpa的基本使用

Spring Boot2(九):整合Jpa的基本使用

一、前言

今天早上看到一篇微信文章,說的是國內普遍用的Mybatis,而國外確普遍用的是Jpa。我之前也看了jpa,發現入門相當容易。jpa對於簡單的CRUD支援非常好,開發效率也會比Mybatis高出不少,因為JpaRepository會根據你定製的實體類,繼承了JpaRepository會有一套完整的封裝好了的基本條件方法。減少了很多開發量。你只需要寫SQL就行了。可能我才剛入門Jpa,對一些認識還是很淺顯。我覺得Jpa對於多表查詢,開發起來有點吃力。。

這是我開始玩Jpa的最初的感受,但是Jpa卻受到了極大的支援和讚揚,在國外Jpa遠比Mybatis流行得多得多。國內卻還是在流程用Mybatis,估計也是收到很多培訓機構或者大V的帶領下,很多國內優秀的開源專案也是用的Mybatis,因為已經用得非常熟練了。

話不多說,先看看SpringBoot如何整合使用Jpa吧!

這裡具體講一講Jpa的搭建,幾種常見的場景的使用:增刪改查、多表查詢,非主鍵查詢這幾種情況的一個學習總結。

二、程式碼部署

1、新增Maven依賴

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

其實Jpa關鍵用到的是最下面兩塊

2、配置application

application.yml

server:
  port: 8081
#指定配置檔案為test
spring:
  profiles:
    active: test

application-test.yml

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/jpatest?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=true
    username: root
    password: root
  jpa:
    # 資料庫型別
    database: mysql
    #列印SQL
    show-sql: true
    hibernate:
      ddl-auto: update  #第一次啟動建立表,之後修改為update

application-test.yml需要了解的是jpa分支,如果需要通過jpa在資料庫中建表,就將spring.jpa.hibernate.ddl-auto改為create,建完表之後,建議改為update,否則你再次重啟,表會回爐重造,資料相應的會丟失。可得注意啦。

3、建立實體類

使用者表sys_user的實體類

@Data
@Entity
@Table(name = "sys_user")
public class SysUser implements Serializable {

    @Id
    private String userId;

    @Column(nullable = false)
    private String userName;

    @Column(nullable = false)
    private String passWord;

    @Column(nullable = false, unique = true)
    private String email;

    @Column(nullable = false, unique = true)
    private String salt;

    @Column(nullable = false)
    private Date regTime;
    
}

使用者角色對照表sys_user_role的實體類

@Entity
@Data
@Table(name = "sys_user_role")
public class SysUserRole implements Serializable {

    @Id
    @GeneratedValue
    private int id;

    // 使用者ID
    private String userId;

    // 角色ID
    private int roleId;
}

4、Dao層

使用者表SysUserDao

public interface SysUserDao extends JpaRepository<SysUser, Integer> {
    
}

使用者角色對照表SysUserRoleDao

public interface SysUserRoleDao extends JpaRepository<SysUserRole, Integer> {
}

5、Controller層

@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    private SysUserDao sysUserDao;

    @Autowired
    private SysUserRoleDao sysUserRoleDao;

    /**
     * 使用者表sys_user,使用者角色對照表sys_user_role。資料初始化
     */
    //傳送get請求進行資料新增:127.0.0.1:8081/user/init
    @RequestMapping(value = "/init", method = RequestMethod.GET)
    public String initData() {
        for (int i = 1; i < 6; i++) {
            // 根據時間戳生成userId
            String userId = String.valueOf(System.currentTimeMillis());
            // new出使用者表和使用者角色表的物件
            SysUser sysUser = new SysUser();
            SysUserRole sysUserRole = new SysUserRole();
            // 新增使用者表
            sysUser.setUserId(userId);
            sysUser.setUserName("username_num" + i);
            sysUser.setPassWord("password_num" + i);
            sysUser.setEmail("email_num" + i + "@qq.com");
            sysUser.setSalt(i + "");
            sysUser.setRegTime(new Date());
            sysUserDao.save(sysUser);

            // 暫時規定小於3的,角色為1,新建使用者角色表
            if (i < 3) {
                sysUserRole.setId(i);
                sysUserRole.setUserId(userId);
                sysUserRole.setRoleId(1);
                sysUserRoleDao.save(sysUserRole);
            } else {
                // 大於3的,角色為2
                sysUserRole.setId(i);
                sysUserRole.setUserId(userId);
                sysUserRole.setRoleId(2);
                sysUserRoleDao.save(sysUserRole);
            }
        }
        return "init data success";
    }

    /**
     * 刪除
     */
    // 傳送get請求:127.0.0.1:8081/user/delete/1562486017644
    @RequestMapping(value = "/delete/{userId}", method = RequestMethod.GET)
    public String deleteUser(@PathVariable("userId") String userId) {
        sysUserDao.deleteByUserId(userId);
        return "delete success";
    }

    /**
     * 查詢全部
     * @return
     */
    // 傳送get請求:127.0.0.1:8081/user/list
    @RequestMapping(value = "/list", method = RequestMethod.GET)
    public List<SysUser> getUsers() {
        return sysUserDao.findAll();
    }

    /**
     * 根據id查詢
     */
    // 傳送get請求:127.0.0.1:8081/user/info/1562486017644
    @RequestMapping(value = "/info/{userId}", method = RequestMethod.GET)
    public Optional<SysUser> getUserById(@PathVariable("userId") String userId) {
        return sysUserDao.findByUserId(userId);
    }

    /**
     * 更新
     */
    // 傳送post請求:127.0.0.1:8081/user/update
    // 傳送報文體如下
    /*
     {
        "userId":"1562486017551",
        "passWord": "231231231212312",
        "userName":"Tom",
        "email": "[email protected]"
     }
     */
    @RequestMapping(value = "/update", method = RequestMethod.POST)
    public String updateAccount(@RequestBody HashMap<String, String> map) {
        // 根據Id更新使用者資訊
        sysUserDao.updateOne(
                map.get("email"),
                map.get("userName"),
                map.get("passWord"),
                map.get("userId"));
        return "update success";
    }

    /**
     * 關聯查詢使用者的角色資訊
     */
    // 傳送post請求:127.0.0.1:8081/user/getUserRole
    // 傳送報文體如下
    /*
      {
         "userId":"1562486017629"
      }
     */
    @RequestMapping(value = "/getUserRole", method = RequestMethod.POST)
    public List<SysUserInfo> getUserRole(@RequestBody HashMap<String, String> map) {
        return sysUserDao.findUserRole(map.get("userId"));
    }

    /**
     * 根據非主鍵username模糊查詢
     */
    // 傳送post請求:127.0.0.1:8081/user/getUserByUserName
    // 傳送報文體如下
    /*
    {
        "userName":"username"
    }
     */
    @RequestMapping(value = "/getUserByUserName", method = RequestMethod.POST)
    public List<SysUser> getUserByUserName(@RequestBody HashMap<String, String> map) {
        return sysUserDao.findUserName(map.get("userName"));
    }
}

程式碼有點多,只是我寫的例子多了點

6、補充Dao

public interface SysUserDao extends JpaRepository<SysUser, Integer> {

    /**
     * 根據userId刪除資料
     */
    @Transactional
    @Query(value = "delete u from sys_user u where u.user_id = ?1", nativeQuery = true)
    @Modifying
    void deleteByUserId(String userId);

    /**
     * 根據UserId查詢
     * @param userId
     * @return
     */
    @Query(value = "select u.* from sys_user u where u.user_id = ?1", nativeQuery = true)
    Optional<SysUser> findByUserId(String userId);

    /**
     * 根據Id更新使用者相關資訊
     * nativeQuery = true 新增該屬性等於true則是原生SQL語句查詢,不新增則是HQL語句
     */
    @Transactional
    @Query(value = "update  sys_user set email=?1, user_name=?2, pass_word=?3 where user_id=?4", nativeQuery = true)
    @Modifying
    public void updateOne(String email, String userName, String passWord, String userId);

    /**
     * 查詢使用者角色
     * @param userId
     * @return
     */
    @Query(value = "SELECT " +
            "t.user_id AS userId, " +
            "t.user_name AS userName, " +
            "t.email AS email, " +
            "t.pass_word AS passWord, " +
            "r.role_id AS roleId " +
            "FROM sys_user t LEFT JOIN sys_user_role r " +
            "ON r.user_id = t.user_id " +
            "WHERE t.user_id = ?1", nativeQuery = true)
    List<SysUserInfo> findUserRole(String userId);

    /**
     * 根據username查詢使用者資訊
     * @return
     */
    @Query(value = "select u.* from sys_user u where u.user_name like CONCAT('%',?1,'%')", nativeQuery = true)
    List<SysUser> findUserName(String nickName);
}

這裡需要注意的在findUserRole方法,是聯表查詢,其結果集在SysUserInfo

public interface SysUserInfo {

    String getUserId();

    String getUserName();

    String getEmail();

    String getPassWord();

    int getRoleId();
}

三、測試

啟動專案之前,將spring.jpa.hibernate.ddl-auto改為create。啟動完成之後改為update或者none。

會生成兩張表sys_user使用者表,sys_user_role使用者角色對應表

然後通過controller裡的一個介面init,傳送get請求

生成一些資料。

之後可以進行具體的資料庫介面操作啦。

四、總結

在學習過程中,敲程式碼也遇到不少坑,感覺Jpa還行,確實比Mybatis快了不少,不需要建立mapper.xml檔案。

可是在專案中不可能都是一些簡單的查詢SQL呀,肯定會遇到許多複雜的SQL,如果用Jpa的話,感覺並不是那麼好用。當然我還沒有深入去學習它。肯定有許多我不太明白的技術。肯定可以解決不復雜SQL。

我在網上也搜尋了,有些人會建議將Jpa和Mybatis結合使用。我也感覺這點子不錯。後續會繼續研究

原始碼

github原始碼地址:Spring Boot2(九):整合Jpa的基本使用

原文地址:https://niaobulashi.com/archives/springboot-jpa.html

To be continued