全民學後端快餐教程(2) - 連接數據庫

全民學後端快餐教程(2) - 連接數據庫

上一節我們介紹瞭如何像寫一個普通Java程序一樣去寫Web應用,現在我們已經可以通過@Controller註解來獲取路由,並且返回字符串給瀏覽器顯示。
跟客戶端打通了之後,下面最重要的任務就是能夠訪問數據庫。我們就以MySQL數據庫被Oracle收購後fork出來的Mariadb爲例,說明連接數據庫的方法。

安裝配置Mariadb

看了下阿里雲ECS最新的Ubuntu鏡像已經升級到了18.04 LTS,我們就以此版本爲基礎說明。

安裝Mariadb

安裝Mariadb很簡單,用下面命令就可以了:

apt install mariadb-server

連接到Mariadb

通過mysql連接Mariadb服務:

mysql -u root

然後我們執行下show databases看看都有些什麼庫:

MariaDB [(none)]> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
+--------------------+
3 rows in set (0.00 sec)

創建使用數據庫

連接正常,於是我們開始幹活,建立我們要用的數據庫。
使用create database命令可以創建數據庫,命令如下:

MariaDB [(none)]> create database prefix;
Query OK, 1 row affected (0.00 sec)

然後我們切換到prefix數據庫,通過use命令:

MariaDB [(none)]> use prefix;
Database changed

建表

下面我們創建一張表。這張表叫做issue表,用於保存做代碼掃描時發現的問題,主要字段是代碼所在的文件名,行號,還有發現問題的內容字符串。
SQL語句如下:

CREATE TABLE issue(
    id integer(16) not null auto_increment,
    filename varchar(256) not null,
    linenum integer(16) not null,
    issuestring varchar(256) not null,
    primary key(id)
);

運行結果如下:

MariaDB [prefix]> CREATE TABLE issue(
    ->     id integer(16) not null auto_increment,
    ->     filename varchar(256) not null,
    ->     linenum integer(16) not null,
    ->     issuestring varchar(256) not null,
    ->     primary key(id)
    -> );
Query OK, 0 rows affected (0.02 sec)

我們插入一條記錄測試下:

MariaDB [prefix]> insert into issue (filename,linenum, issuestring) values ('test.java',1,'No @author');
Query OK, 1 row affected (0.00 sec)

再select一下看看剛纔插入的結果:

MariaDB [prefix]> select * from issue;
+----+-----------+---------+-------------+
| id | filename  | linenum | issuestring |
+----+-----------+---------+-------------+
|  1 | test.java |       1 | No @author  |
+----+-----------+---------+-------------+
1 row in set (0.00 sec)

創建用戶

直接使用root用戶訪問數據庫是件風險很高的事情。我們創建有隻讀權限的用戶來訪問數據庫就好了。

我們通過create user命令來創建用戶,例如就叫prefix:

create user 'prefix'@'localhost' identified by 'AliOS123';

下面我們給這個用戶授予select, insert, update, delete的權限:

grant select,update,delete on *.* to 'prefix'@'localhost';

創建是否成功,我們測試一下,使用prefix用戶來登錄mysql:

mysql -u prefix -p

密碼使用剛纔設置的AliOS123。

我們試驗下是否可以使用prefix數據庫,並且可以選擇issue表的內容:

MariaDB [(none)]> use prefix;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
MariaDB [prefix]> select * from issue;
+----+-----------+---------+-------------+
| id | filename  | linenum | issuestring |
+----+-----------+---------+-------------+
|  1 | test.java |       1 | No @author  |
+----+-----------+---------+-------------+
1 row in set (0.00 sec)

使用JDBC Template訪問數據庫

數據庫配置

訪問數據庫,首先我們需要進行一些配置。配置文件我們放在src/main/resources目錄下,名字叫application.properties,寫庫名,用戶名,密碼這三項就好:

spring.datasource.url=jdbc:mysql://localhost:3306/prefix
spring.datasource.username=prefix
spring.datasource.password=AliOS123

引入JDBC和MySQL的庫依賴

我們還是修改pom.xml引入對JDBC和MySQL的庫的依賴:

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>

現在的完整pom.xml是這樣的:

<?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>cn.alios.system.service.prefix</groupId>
    <artifactId>Prefix</artifactId>
    <version>1.0.0-SNAPSHOT</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.2.RELEASE</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

POJO類

下面我們開始寫Java代碼。首先爲了保存數據庫中讀來的值,我們需要定義一個Java對象。這個對象不繼承任何複雜對象,不實現任何接口,所以一般稱爲POJO(Plain Ordinary Java Object)對象。

我們的Issue類,只要id, filename, linenum, issuestring四個屬性就好:

    private Long id;
    private String filename;
    private Long lineNum;
    private String issueString;

完整的類是再加上自動生成的getter和setter方法:

package cn.alios.system.service.prefix.pojo;

public class Issue {
    private Long id;
    private String filename;
    private Long lineNum;
    private String issueString;

    public Long getId() {
        return id;
    }

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

    public String getFilename() {
        return filename;
    }

    public void setFilename(String filename) {
        this.filename = filename;
    }

    public Long getLineNum() {
        return lineNum;
    }

    public void setLineNum(Long lineNum) {
        this.lineNum = lineNum;
    }

    public String getIssueString() {
        return issueString;
    }

    public void setIssueString(String issueString) {
        this.issueString = issueString;
    }

}

服務類

有個POJO類保存結果之後,我們來寫一個根據id來查詢的簡單功能。這個名字可以叫做getIssueById,我們就簡稱getIssue吧:

package cn.alios.system.service.prefix.service;

import cn.alios.system.service.prefix.pojo.Issue;

public interface JdbcTemplateIssueService {

    public Issue getIssue(Long id);
}

如何實現這個功能呢?這時候JDBCTemplate最省事,直接寫SQL語句,調用JDBCTemplate的queryForObject函數,如下:

    @Override
    public Issue getIssue(Long id) {
        String sql = "select id, filename, linenum, issuestring from issue where id = ?;";
        Object[] params = new Object[]{id};
        Issue issue = jdbcTemplate.queryForObject(sql, params, getIssueMapper());
        return issue;
    }

getIssueMapper負責將字段跟Issue對象的各個字段關聯起來:

    //映射關係
    private RowMapper<Issue> getIssueMapper() {
        RowMapper<Issue> issueRowMapper = (ResultSet rs, int rownum) -> {
            Issue issue = new Issue();
            issue.setId(rs.getLong("id"));
            issue.setFilename(rs.getString("filename"));
            issue.setLineNum(rs.getLong("linenum"));
            issue.setIssueString(rs.getString("issuestring"));
            return issue;
        };
        return issueRowMapper;
    }

下面是完整的Service類。其中的@Autowired註解是Spring Boot會爲我們自動注入JdbcTemplate對象。

package cn.alios.system.service.prefix.service;

import cn.alios.system.service.prefix.pojo.Issue;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Service;

import java.sql.ResultSet;

@Service
public class JdbcTemplateIssueServiceImpl implements JdbcTemplateIssueService {
    @Autowired
    private JdbcTemplate jdbcTemplate = null;

    /*
    表結構:
    +----+-----------+---------+-------------+
    | id | filename  | linenum | issuestring |
    +----+-----------+---------+-------------+
     */

    //映射關係
    private RowMapper<Issue> getIssueMapper() {
        RowMapper<Issue> issueRowMapper = (ResultSet rs, int rownum) -> {
            Issue issue = new Issue();
            issue.setId(rs.getLong("id"));
            issue.setFilename(rs.getString("filename"));
            issue.setLineNum(rs.getLong("linenum"));
            issue.setIssueString(rs.getString("issuestring"));
            return issue;
        };
        return issueRowMapper;
    }

    @Override
    public Issue getIssue(Long id) {
        String sql = "select id, filename, linenum, issuestring from issue where id = ?;";
        Object[] params = new Object[]{id};
        Issue issue = jdbcTemplate.queryForObject(sql, params, getIssueMapper());
        return issue;
    }
}

將Service注入給Controller

JdbcTemplate是Spring容器幫我們注入的,現在我們再用@Autowired把Service注入給Controller,然後Controller就可以調用Service來查詢數據庫了:

package cn.alios.system.service.prefix.controller;

import cn.alios.system.service.prefix.pojo.Issue;
import cn.alios.system.service.prefix.service.JdbcTemplateIssueServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
@RequestMapping("/test")
public class TestController {
    @Autowired
    JdbcTemplateIssueServiceImpl jdbcTemplateIssueService = null;

    @RequestMapping("/")
    @ResponseBody
    public String test() {
        Issue issue = jdbcTemplateIssueService.getIssue((long) 1);
        if (issue != null) {
            return issue.getFilename() + "," + issue.getIssueString();
        } else {
            return "Test Controller!";
        }
    }
}

到這裏,一次對於數據庫的完整訪問流程就走通了。

我們試驗一下效果:

mvn package
java -jar target/Prefix-1.0.0-SNAPSHOT.jar

然後在瀏覽器中查看:http://127.0.01:8080/test/
輸出值爲:test.java,No @author

小結

使用JdbcTemplate編程,主要靠直接寫SQL語句,然後調用JdbcTemplate的接口去執行SQL語句,並處理返回值。

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