自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

三分鐘數(shù)據(jù)持久化:Spring Boot, JPA 與 SQLite 的完美融合

數(shù)據(jù)庫 其他數(shù)據(jù)庫
SQLite 是一個(gè)用 C 語言編寫的開源、輕量級(jí)、快速、獨(dú)立且高可靠性的 SQL 數(shù)據(jù)庫引擎,它提供了功能齊全的數(shù)據(jù)庫解決方案。對于大多數(shù)的應(yīng)用,SQLite 都可以滿足。

在快節(jié)奏的軟件開發(fā)領(lǐng)域,每一個(gè)簡化工作流程的機(jī)會(huì)都不容錯(cuò)過。想要一個(gè)無需繁瑣配置、能夠迅速啟動(dòng)的數(shù)據(jù)持久化方案嗎?這篇文章將是你的首選攻略。在這里,我們將向你展示如何將 Spring Boot 的便捷性、JPA 的強(qiáng)大查詢能力和 SQLite 的輕量級(jí)特性結(jié)合在一起,實(shí)現(xiàn)快速而又優(yōu)雅的數(shù)據(jù)管理。

為什么選擇 SQLite

SQLite 是一個(gè)用 C 語言編寫的開源、輕量級(jí)、快速、獨(dú)立且高可靠性的 SQL 數(shù)據(jù)庫引擎,它提供了功能齊全的數(shù)據(jù)庫解決方案。對于大多數(shù)的應(yīng)用,SQLite 都可以滿足。使用 SQLite 可以零配置啟動(dòng),對于小型應(yīng)用或者快速原型設(shè)計(jì)是一個(gè)非常大的優(yōu)勢。

使用 SQLite 具有下面幾個(gè)優(yōu)點(diǎn):

  1. 1. 輕量級(jí):SQLite很小巧,不需要獨(dú)立服務(wù)器,便于集成到應(yīng)用中。
  2. 2. 零配置:啟用 SQLite 無需復(fù)雜配置,只需指定一個(gè)文件路徑存放 DB 文件,簡化了數(shù)據(jù)庫的設(shè)置流程。
  3. 3. 便于移植:數(shù)據(jù)庫是單一文件,方便備份和在不同環(huán)境間遷移。
  4. 4. 跨平臺(tái):SQLite 支持各種操作系統(tǒng),容易實(shí)現(xiàn)應(yīng)用的跨平臺(tái)運(yùn)行。
  5. 5. 性能良好:對于小型應(yīng)用,SQLite 提供足夠的讀寫性能。
  6. 6. 遵循ACID:SQLite事務(wù)符合ACID原則,數(shù)據(jù)操作可靠。
  7. 7. 社區(qū)支持:雖然簡單,但擁有強(qiáng)大的社區(qū)和廣泛的文檔資源。

之前寫過一篇 SQLite 入門教程 (https://www.wdbyte.com/db/sqlite/)[1],感情的同學(xué)可以參考。

為什么 選擇 JPA

Spring Data JPA 是Spring Data項(xiàng)目的一部分,旨在簡化基于JPA(Java Persistence API)的數(shù)據(jù)訪問層(Repository層)的實(shí)現(xiàn)。JPA是一種 ORM(對象關(guān)系映射)規(guī)范,它允許開發(fā)者以面向?qū)ο蟮姆绞絹聿僮鲾?shù)據(jù)庫,

通常應(yīng)用程序?qū)崿F(xiàn)數(shù)據(jù)訪問層可能非常麻煩,必須編寫太多的樣板代碼才能實(shí)現(xiàn)簡單的查詢,更不用說分頁等其他操作,而 Spring Data JPA 可以讓開發(fā)者非常容易地實(shí)現(xiàn)對數(shù)據(jù)庫的各種操作,顯著減少實(shí)際需要的工作量。

詳細(xì)介紹 JPA 并不是本文目的,關(guān)于 JPA 的更多內(nèi)容可以訪問:

  1. 1. Spring Data JPA 官網(wǎng):https://spring.io/projects/spring-data-jpa[2]。
  2. 2. Spring Boot 使用 Spring Data JPA[3]

創(chuàng)建 Spring Boot 項(xiàng)目

用于后續(xù)演示,首先創(chuàng)建一個(gè)簡單的 Spring Boot 項(xiàng)目。你可以自由創(chuàng)建,或者使用 Spring 官網(wǎng)提供的快速創(chuàng)建工具:https://start.spring.io/[4]

注意,文章示例項(xiàng)目使用 Java 21 進(jìn)行演示。

為了方便開發(fā),創(chuàng)建一個(gè)基礎(chǔ)的 Spring Boot 項(xiàng)目后,添加以下依賴。

<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>
<!-- 從 Hibernate 6 開始,支持 SQLite 方言。-->
<!-- https://mvnrepository.com/artifact/org.hibernate.orm/hibernate-community-dialects -->
<dependency>
    <groupId>org.hibernate.orm</groupId>
    <artifactId>hibernate-community-dialects</artifactId>
    <version>6.4.3.Final</version>
</dependency>
<!-- sqlite jdbc 驅(qū)動(dòng) -->
<dependency>
    <groupId>org.xerial</groupId>
    <artifactId>sqlite-jdbc</artifactId>
    <version>3.45.1.0</version>
</dependency>
<!-- Lombok 簡化 get set tostring log .. -->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>
<!-- apache java 通用工具庫 -->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.13.0</version>
</dependency>
<!-- 編碼通用工具庫 -->
<dependency>
    <groupId>commons-codec</groupId>
    <artifactId>commons-codec</artifactId>
    <version>1.16.0</version>
</dependency>

配置 SQLite & JPA

在 Spring Boot 中,對 SQLite 的配置非常簡單,只需要指定一個(gè)位置存放 SQLite 數(shù)據(jù)庫文件。SQLite 無服務(wù)端,因此可以直接啟動(dòng)。

spring.datasource.url=jdbc:sqlite:springboot-sqlite-jpa.db
spring.datasource.driver-class-name=org.sqlite.JDBC
# JPA Properties
spring.jpa.database-platform=org.hibernate.community.dialect.SQLiteDialect
# create 每次都重新創(chuàng)建表,update,表若存在則不重建
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true

配置實(shí)體映射

在使用 JPA 開發(fā)時(shí),就是使用 jakarta.persistence 包中的注解配置 Java 實(shí)體類和表的映射關(guān)系,比如使用 @Table 指定表名,使用 @Column 配置字段信息。

import java.time.LocalDateTime;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

@Entity
@Getter
@Setter
@ToString
@Table(name = "website_user")
public class WebsiteUser {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    @Column(name = "username", nullable = false, unique = true, length = 64)
    private String username;

    @Column(name = "password", nullable = false, length = 255)
    private String password;

    @Column(name = "salt", nullable = false, length = 16)
    private String salt;

    @Column(name = "status", nullable = false, length = 16, columnDefinition = "VARCHAR(16) DEFAULT 'active'")
    private String status;

    @Column(name = "created_at", nullable = false, columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP")
    private LocalDateTime createdAt;
  
    @Column(name = "updated_at", nullable = false, columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP")
    private LocalDateTime updatedAt;
}

編寫 JPA 查詢方法

Spring Data JPA 提供了多種便捷的方法來實(shí)現(xiàn)對數(shù)據(jù)庫的查詢操作,使得能夠以非常簡潔的方式編寫對數(shù)據(jù)庫的訪問和查詢邏輯。比如 Spring Data JPA 允許通過在接口中定義遵循一定命名方法的方式來創(chuàng)建數(shù)據(jù)庫查詢。如findByName 將生成一個(gè)根據(jù) name 查詢指定實(shí)體的 SQL。

代碼示例:

@Repository
public interface WebsiteUserRepository extends CrudRepository<WebsiteUser, Long> {

    /**
     * 根據(jù) username 查詢數(shù)據(jù)
     * @param name
     * @return
     */
    WebsiteUser findByUsername(String name);
}

代碼示例中,繼承的 CrudRepository 接口中包含了常見的 CURD 操作方法。自定義的 findByUsername 方法可以根據(jù) WebsiteUser 中的 Username 進(jìn)行查詢。

編寫 Controller

編寫三個(gè) API 用來演示 Spring Boot 結(jié)合 SQLite 以及 JPA 是否成功。

初始化方法 init():

  • ? 映射到 "/sqlite/init" 的 GET請求。
  • ? 創(chuàng)建了10個(gè) WebsiteUser 實(shí)體,為每個(gè)用戶生成隨機(jī)的用戶名和鹽值,并用MD5加密其密碼("123456" + 鹽)。
  • ? 用戶信息包括用戶名、加鹽后的密碼、創(chuàng)建和更新的時(shí)間戳,以及用戶狀態(tài)。
  • ? 用戶信息被保存到數(shù)據(jù)庫中,并記錄日志。

查找用戶方法 findByUsername(String username):

  • ? 映射到 "/sqlite/find" 的GET請求。
  • ? 通過用戶名查詢用戶。如果找到,返回用戶的字符串表示;否則返回 null。

登錄方法 findByUsername(String username, String password):

  • ? 映射到 "/sqlite/login" 的GET請求。
  • ? 驗(yàn)證傳入的用戶名和密碼。首先通過用戶名查詢用戶,然后將傳入的密碼與鹽值結(jié)合,并與數(shù)據(jù)庫中存儲(chǔ)的加鹽密碼進(jìn)行MD5加密比對。
  • ? 如果密碼匹配,則認(rèn)證成功,返回 "login succeeded";否則,返回 "login failed"。

代碼示例:

import java.time.LocalDateTime;
import com.wdbyte.springsqlite.model.WebsiteUser;
import com.wdbyte.springsqlite.repository.WebsiteUserRepository;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
 * @author https://www.wdbyte.com
 */
@Slf4j
@RestController
public class SqliteController {

    @Autowired
    private WebsiteUserRepository userRepository;

    @GetMapping("/sqlite/init")
    public String init() {
        for (int i = 0; i < 10; i++) {
            WebsiteUser websiteUser = new WebsiteUser();
            // 隨機(jī)4個(gè)字母
            websiteUser.setUsername(RandomStringUtils.randomAlphabetic(4));
            // 隨機(jī)16個(gè)字符用于密碼加鹽加密
            websiteUser.setSalt(RandomStringUtils.randomAlphanumeric(16));
            String password = "123456";
            // 密碼存儲(chǔ) = md5(密碼+鹽)
            password = password + websiteUser.getSalt();
            websiteUser.setPassword(DigestUtils.md5Hex(password));
            websiteUser.setCreatedAt(LocalDateTime.now());
            websiteUser.setUpdatedAt(LocalDateTime.now());
            websiteUser.setStatus("active");
            WebsiteUser saved = userRepository.save(websiteUser);
            log.info("init user {}", saved.getUsername());
        }
        return "init success";
    }

    @GetMapping("/sqlite/find")
    public String findByUsername(String username) {
        WebsiteUser websiteUser = userRepository.findByUsername(username);
        if (websiteUser == null) {
            return null;
        }
        return websiteUser.toString();
    }

    @GetMapping("/sqlite/login")
    public String findByUsername(String username, String password) {
        WebsiteUser websiteUser = userRepository.findByUsername(username);
        if (websiteUser == null) {
            return "login failed";
        }
        password = password + websiteUser.getSalt();
        if (StringUtils.equals(DigestUtils.md5Hex(password), websiteUser.getPassword())) {
            return "login succeeded";
        } else {
            return "login failed";
        }
    }
}

至此,項(xiàng)目編寫完成,完整目錄結(jié)構(gòu)如下:

├── pom.xml
└── src
    ├── main
        ├── java
        │   └── com
        │       └── wdbyte
        │           └── springsqlite
        │               ├── SpringBootSqliteApp.java
        │               ├── controller
        │               │   └── SqliteController.java
        │               ├── model
        │               │   └── WebsiteUser.java
        │               └── repository
        │                   └── WebsiteUserRepository.java
        └── resources
            ├── application.properties
            ├── static
            └── templates

啟動(dòng)測試

Spring Boot 啟動(dòng)時(shí)由于庫表不存在,自動(dòng)創(chuàng)建庫表:

Hibernate: create table website_user (id integer, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP not null, password varchar(255) not null, salt varchar(16) not null, status VARCHAR(16) DEFAULT 'active' not null, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP not null, username varchar(64) not null unique, primary key (id))
Hibernate: alter table website_user drop constraint UK_61p1pfkd4ht22uhlib72oj301
2024-02-27T20:00:21.279+08:00  INFO 70956 --- [main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
2024-02-27T20:00:21.578+08:00  WARN 70956 --- [main] JpaBaseConfiguration$JpaWebConfiguration : spring.jpa.open-in-view is enabled by default. Therefore, database queries may be performed during view rendering. Explicitly configure spring.jpa.open-in-view to disable this warning
2024-02-27T20:00:21.931+08:00  INFO 70956 --- [main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port 8080 (http) with context path ''
2024-02-27T20:00:21.938+08:00  INFO 70956 --- [main] c.w.springsqlite.SpringBootSqliteApp     : Started SpringBootSqliteApp in 3.944 seconds (process running for 5.061)

請求初始化接口

$ curl http://127.0.0.1:8080/sqlite/init
init success

可以看到輸出日志成功寫入了 10條數(shù)據(jù),且輸出了 username 值。

2024-02-27T20:01:04.120+08:00 ...SqliteController : init user HUyz
Hibernate: insert into website_user (created_at,password,salt,status,updated_at,username) values (?,?,?,?,?,?)
Hibernate: select last_insert_rowid()
2024-02-27T20:01:04.123+08:00 ...SqliteController : init user ifQU
Hibernate: insert into website_user (created_at,password,salt,status,updated_at,username) values (?,?,?,?,?,?)
Hibernate: select last_insert_rowid()
2024-02-27T20:01:04.126+08:00 ...SqliteController : init user GBPK
Hibernate: insert into website_user (created_at,password,salt,status,updated_at,username) values (?,?,?,?,?,?)
Hibernate: select last_insert_rowid()
2024-02-27T20:01:04.129+08:00 ...SqliteController : init user rytE
Hibernate: insert into website_user (created_at,password,salt,status,updated_at,username) values (?,?,?,?,?,?)
Hibernate: select last_insert_rowid()
2024-02-27T20:01:04.132+08:00 ...SqliteController : init user iATH
Hibernate: insert into website_user (created_at,password,salt,status,updated_at,username) values (?,?,?,?,?,?)
Hibernate: select last_insert_rowid()
2024-02-27T20:01:04.134+08:00 ...SqliteController : init user ZQRW
Hibernate: insert into website_user (created_at,password,salt,status,updated_at,username) values (?,?,?,?,?,?)
Hibernate: select last_insert_rowid()
2024-02-27T20:01:04.137+08:00 ...SqliteController : init user cIPM
Hibernate: insert into website_user (created_at,password,salt,status,updated_at,username) values (?,?,?,?,?,?)
Hibernate: select last_insert_rowid()
2024-02-27T20:01:04.140+08:00 ...SqliteController : init user MemS
Hibernate: insert into website_user (created_at,password,salt,status,updated_at,username) values (?,?,?,?,?,?)
Hibernate: select last_insert_rowid()
2024-02-27T20:01:04.143+08:00 ...SqliteController : init user GEeX
Hibernate: insert into website_user (created_at,password,salt,status,updated_at,username) values (?,?,?,?,?,?)
Hibernate: select last_insert_rowid()
2024-02-27T20:01:04.146+08:00 ...SqliteController : init user ZQrT

請求查詢用戶接口

$ curl http://127.0.0.1:8080/sqlite/find\?username\=ZQrT
WebsiteUser(id=10, username=ZQrT, password=538ea3b5fbacd1f9354a1f367b36135a, salt=RxaivBHlyJCxtOEv, status=active, createdAt=2024-02-27T20:01:04.144, updatedAt=2024-02-27T20:01:04.144)

查詢成功,回顯了查詢到的用戶信息。

請求登錄接口

在初始化數(shù)據(jù)時(shí),密碼統(tǒng)一配置為 123456,下面的測試可以看到使用正確的密碼可以通過校驗(yàn)。

$ curl http://127.0.0.1:8080/sqlite/login\?username\=ZQrT\&password\=123456
login succeeded
$ curl http://127.0.0.1:8080/sqlite/login\?username\=ZQrT\&password\=12345
login failed

SQLite 3 數(shù)據(jù)審查

使用 Sqlite3 命令行工具查看 SQLite 數(shù)據(jù)庫內(nèi)容。

$ ./sqlite3 springboot-sqlite-jpa.db
SQLite version 3.42.0 2023-05-16 12:36:15
Enter ".help" for usage hints.
sqlite> .tables
website_user

sqlite> .mode table
sqlite> select * from website_user;
+----+---------------+----------------------------------+------------------+--------+---------------+----------+
| id |  created_at   |             password             |       salt       | status |  updated_at   | username |
+----+---------------+----------------------------------+------------------+--------+---------------+----------+
| 1  | 1709035264074 | 4b2b68c0df77669540fc0a487d753400 | 1njFP8ykWmlu01Z8 | active | 1709035264074 | HUyz     |
| 2  | 1709035264120 | 7e6444d57f753cfa6c1592a17e68e66e | 9X3El5jQaMhrROSf | active | 1709035264120 | ifQU     |
| 3  | 1709035264124 | 1d24c4ddb351eb56f665adb13708f981 | Jn9IrT6MYqVqzpu8 | active | 1709035264124 | GBPK     |
| 4  | 1709035264126 | 960747cc48aeed71e8ff714deae42e87 | wq8pb1G9pIalGHwP | active | 1709035264126 | rytE     |
| 5  | 1709035264129 | cf1037b95a997a1b1b9d9aa598b9f96b | An0hwV2n9cN4wpOy | active | 1709035264129 | iATH     |
| 6  | 1709035264132 | b68d42108e5046bd25b74cda947e0ffc | EozfDAkpn5Yx4yin | active | 1709035264132 | ZQRW     |
| 7  | 1709035264134 | 78d4841af9a12603204f077b9bf30dcc | 2FRNQ2zWksJHOyX9 | active | 1709035264135 | cIPM     |
| 8  | 1709035264137 | 60b8051ca3379c569a3fb41ed5ff05aa | KpT3IGwWmhlWIUq7 | active | 1709035264137 | MemS     |
| 9  | 1709035264140 | 0ca0a2dce442315c11f5488c0127f905 | RhGOYnNEMYbnWoat | active | 1709035264140 | GEeX     |
| 10 | 1709035264144 | 538ea3b5fbacd1f9354a1f367b36135a | RxaivBHlyJCxtOEv | active | 1709035264144 | ZQrT     |
+----+---------------+----------------------------------+------------------+--------+---------------+----------+
sqlite>

一如既往,文章中代碼存放在 Github.com/niumoo/javaNotes[5].

參考

? https://docs.spring.io/spring-data/jpa/reference/jpa.html

引用鏈接

[1] SQLite 入門教程 (https://www.wdbyte.com/db/sqlite/): https://www.wdbyte.com/db/sqlite/

[2] Spring Data JPA 官網(wǎng):https://spring.io/projects/spring-data-jpa: https://spring.io/projects/spring-data-jpa

[3] Spring Boot 使用 Spring Data JPA: https://www.wdbyte.com/2019/03/springboot/springboot-10-data-jpa

[4] https://start.spring.io/: https://start.spring.io/#!type=maven-project&language=java&platformVersion=3.2.3&packaging=jar&jvmVersion=21&groupId=com.example&artifactId=springboot-sqlite-jpa&name=springboot-sqlite-jpa&description=Demo project for Spring Boot&packageName=com.example.springboot-sqlite-jpa&dependencies=web,lombok,data-jpa

[5] Github.com/niumoo/javaNotes: https://github.com/niumoo/JavaNotes/tree/master/springboot/springboot-sqlite-jpa

責(zé)任編輯:武曉燕 來源: 程序猿阿朗
相關(guān)推薦

2022-02-16 19:42:25

Spring配置開發(fā)

2020-11-20 08:36:59

Jpa數(shù)據(jù)代碼

2024-05-16 11:13:16

Helm工具release

2021-09-16 10:29:05

開發(fā)技能代碼

2009-11-09 12:55:43

WCF事務(wù)

2024-12-18 10:24:59

代理技術(shù)JDK動(dòng)態(tài)代理

2020-03-08 16:45:58

數(shù)據(jù)挖掘學(xué)習(xí)數(shù)據(jù)量

2022-02-17 09:24:11

TypeScript編程語言javaScrip

2021-04-20 13:59:37

云計(jì)算

2023-12-27 08:15:47

Java虛擬線程

2024-01-16 07:46:14

FutureTask接口用法

2024-08-30 08:50:00

2013-06-28 14:30:26

棱鏡計(jì)劃棱鏡棱鏡監(jiān)控項(xiàng)目

2020-06-30 10:45:28

Web開發(fā)工具

2015-10-23 17:47:32

BaaSPaaS移動(dòng)中間件

2020-07-21 07:42:29

數(shù)據(jù)庫信息技術(shù)

2023-12-23 18:04:40

服務(wù)Eureka工具

2009-11-10 16:05:21

VB.NET格式化

2021-12-17 07:47:37

IT風(fēng)險(xiǎn)框架

2024-10-15 09:18:30

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)