最近在Azure上以應(yīng)用服務(wù)(App Service)的方式部署了一個(gè)Spring Boot應(yīng)用,數(shù)據(jù)庫選擇了MySQL on Azure,這是一個(gè)PaaS級別的服務(wù),其底層仍是虛擬機(jī),但對應(yīng)實(shí)例由Azure托管。本文記錄部署過程,以及過程中遇到的問題和解決方法。
部署過程
在開發(fā)環(huán)境中連接的是本機(jī)數(shù)據(jù)庫,工作正常。數(shù)據(jù)庫的配置寫在applicaion.properties文件里:
spring.datasource.url=jdbc:mysql://localhost:3306/wefamily?user=dbuser&password=123456
spring.jpa.hibernate.ddl-auto=update
文件的第二行表示自動(dòng)創(chuàng)建和更新數(shù)據(jù)庫表。
部署到Azure上以后,數(shù)據(jù)庫連接參數(shù)改為通過環(huán)境變量指定。Spring Boot擁有強(qiáng)大的配置管理功能,環(huán)境變量的優(yōu)先級要高于application.properties,會(huì)自動(dòng)覆蓋相關(guān)設(shè)置。
設(shè)置環(huán)境變量有兩種方法,一是使用Azure CLI,在命令行中執(zhí)行:
az webapp config appsettings set --settings SPRING_DATASOURCE_URL="jdbc:mysql://dbinstance.mysql.database.azure.com:3306/wefamilydb" --resource-group wefamily_resource_group --name wefamily-api
az webapp config appsettings set --settings SPRING_DATASOURCE_USERNAME=dbinstance%dbuser --resource-group wefamily_resource_group --name wefamily-api
az webapp config appsettings set --settings SPRING_DATASOURCE_PASSWORD=123456 --resource-group wefamily_resource_group --name wefamily-api
二是使用portal,在應(yīng)用服務(wù)的“應(yīng)用程序設(shè)置”中手動(dòng)添加和修改:

配置好以后,應(yīng)用無法正常訪問,報(bào)500錯(cuò)誤(The request timed out.)。
問題解決
通過FTP連接到部署目錄,下載eventLog.xml查看:

<Event>
<System>
<Provider Name="HttpPlatformHandler"/>
<EventID>1000</EventID>
<Level>1</Level>
<Task>0</Task>
<Keywords>Keywords</Keywords>
<TimeCreated SystemTime="2018-07-14T10:04:05Z"/>
<EventRecordID>35185953</EventRecordID>
<Channel>Application</Channel>
<Computer>RD0017FA007A37</Computer>
<Security/>
</System>
<EventData>
<Data>Process '5588' failed to start. Port = 21453, Error Code = '-2147023829'.</Data>
</EventData>
</Event>
原因是應(yīng)用的進(jìn)程沒能正常啟動(dòng)。
嘗試在本地連接Azure數(shù)據(jù)庫,為了不修改代碼,寫了一個(gè)腳本:
#!/bin/sh
export SPRING_DATASOURCE_URL="jdbc:mysql://dbinstance.mysqldb.chinacloudapi.cn:3306/wefamilydb"
export SPRING_DATASOURCE_USERNAME=dbinstance%dbuser
export SPRING_DATASOURCE_PASSWORD=123456
mvn spring-boot:run
發(fā)現(xiàn)應(yīng)用同樣不能啟動(dòng),報(bào)錯(cuò)內(nèi)容為:
2018-07-19 11:28:14.546 WARN 1942 --- [ main] o.h.t.s.i.ExceptionHandlerLoggedImpl : GenerationTarget encountered exception accepting command : Error executing DDL via JDBC Statement
org.hibernate.tool.schema.spi.CommandAcceptanceException: Error executing DDL via JDBC Statement
...
Caused by: java.sql.SQLException: Got error 1 from storage engine
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:965) ~[mysql-connector-java-5.1.46.jar:5.1.46]
運(yùn)行官方的TodoList示例作對比,發(fā)現(xiàn)這個(gè)工程可以正常連接Azure上的數(shù)據(jù)庫。
在網(wǎng)上搜索Error executing DDL via JDBC Statement錯(cuò)誤,發(fā)現(xiàn)此問題多與數(shù)據(jù)庫方言有關(guān);同時(shí)結(jié)合Got error 1 from storage engine,判斷問題可能與存儲(chǔ)引擎有關(guān)。
登錄開發(fā)環(huán)境的MySQL,用show table status from dbname檢查數(shù)據(jù)庫表的存儲(chǔ)引擎,發(fā)現(xiàn)自己的應(yīng)用是MyISAM,而TodoList應(yīng)用是InnoDB,再對比代碼,兩者最大的差別是Spring Boot版本不同,前者是2.0.3,后者是1.5.3。將TodoList應(yīng)用的Spring Boot升級到2.0.3,在本地創(chuàng)建出來的數(shù)據(jù)庫表果然變成了MyISAM引擎,同時(shí)也無法連接Azure上的數(shù)據(jù)庫了。
檢查文檔Azure Database for MySQL 中的限制,確認(rèn)MySQL on Azure不支持MyISAM:

在application.properties中添加配置,使用InnoDB引擎:
spring.jpa.database-platform=org.hibernate.dialect.MySQL57InnoDBDialect
問題得以解決,應(yīng)用可以在本地連接到Azure數(shù)據(jù)庫,部署到云上以后也能正常訪問了。
參考資料
- Azure MySQL數(shù)據(jù)庫_數(shù)據(jù)庫托管服務(wù) - Azure云計(jì)算
- MySQL Database on Azure快速入門指南 | Azure Docs
- Announcing MySQL in-app for Web Apps (Windows) | Azure App Service Team Blog
- Build a Java and MySQL web app in Azure | Microsoft Docs
- 【spring boot】spring boot 2.0 項(xiàng)目中使用mysql驅(qū)動(dòng)啟動(dòng)創(chuàng)建的mysql數(shù)據(jù)表,引擎是MyISAM,如何修改啟動(dòng)時(shí)創(chuàng)建數(shù)據(jù)表引擎為InnoDB - Angel擠一擠 - 博客園