本文在個人技術博客【鳥不拉屎】同步發布,詳情可猛戳 亦可掃描文章末尾二維碼關注個人公眾號【鳥不拉屎】
一、前言
今天早上看到一篇微信文章,說的是國內普遍用的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": "1111111@qq.com"
}
*/
@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...