全民學後端快餐教程(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語句,并處理傳回值。