使用docker-compose同時啟動MySQL與連線MySQL的java程式
阿新 • • 發佈:2019-01-03
說明
docker-compose 是一個使用者定義和執行多個容器的 Docker 應用程式。在 docker-compose 中你可以使用 YAML 檔案來配置你的應用服務。然後,只需要一個簡單的命令,就可以建立並啟動你配置的所有服務。
難點
使用docker-compose啟動MySQL與java程式後,java程式並不會一直等待MySQL將所需的初始化SQL檔案執行完成,所以Java程式在執行過程中就會報錯說連不上MySQL,就算你使用docker-compose中的depends_on來使java程式容器依賴於mysql容器也是一樣沒有用的,docker-compose只會判斷容器是否啟動成功(你可以當成是MySQL容器剛剛開機成功,還未執行SQL檔案就跳到執行Java程式容器了)
快速開始
首先給出專案結構圖:
docker-mysql的配置我們沿用上一篇部落格的配置詳細戳-->Docker-mysql啟動時自動執行SQL
為了使java程式能適應變化,我們將MySQL的連線配置寫入docker-compose檔案中:
docker-compose.yml
version: "2" services: mymysql: image: mymysql:test container_name: mymysql ports: - "3306:3306" command: [ '--character-set-server=utf8mb4', '--collation-server=utf8mb4_unicode_ci' ] environment: MYSQL_ROOT_PASSWORD: "root" javatest: image: test1jar:test container_name: javatest1 depends_on: - mymysql environment: IP: "192.168.99.100" PORT: "3306" DRIVERCLASSNAME: "com.mysql.jdbc.Driver" DBNAME: "persontest" URL: "jdbc:mysql://192.168.99.100:3306/persontest?useSSL=false" USERNAME: "root" PASSWORD: "root"
將原來的src目錄刪除,新建一個model命名為Java1,更新一下pom.xml新增jdbc包,編寫一個bean類,編寫App.java(這裡直接用JDBC操作):
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"> <parent> <artifactId>dockermysql</artifactId> <groupId>cn.yunlingfly</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>Java1</artifactId> <name>Java1</name> <!-- FIXME change it to the project's website --> <url>http://www.example.com</url> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <configuration> <classesDirectory>target/classes/</classesDirectory> <archive> <manifest> <!-- 主函式的入口 --> <mainClass>cn.yunlingfly.App</mainClass> <!-- 打包時 MANIFEST.MF檔案不記錄的時間戳版本 --> <useUniqueVersions>false</useUniqueVersions> <addClasspath>true</addClasspath> <classpathPrefix>lib/</classpathPrefix> </manifest> <manifestEntries> <Class-Path>.</Class-Path> </manifestEntries> </archive> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>2.3</version> <executions> <execution> <phase>package</phase> <goals> <goal>shade</goal> </goals> <configuration> <transformers> <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> <mainClass>cn.yunlingfly.App</mainClass> </transformer> </transformers> <filters> <!-- 過濾器,去除jar衝突問題 --> <filter> <artifact>*:*</artifact> <excludes> <exclude>META-INF/*.SF</exclude> <exclude>META-INF/*.DSA</exclude> <exclude>META-INF/*.RSA</exclude> </excludes> </filter> </filters> </configuration> </execution> </executions> </plugin> </plugins> </build> </project>
Person.java
package cn.yunlingfly;
public class Person {
private Integer id;
private String username;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
}
App.java
package cn.yunlingfly;
import com.alibaba.fastjson.JSON;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
/**
* Hello world!
*/
public class App extends Thread {
private final static String DRIVER = System.getenv("DRIVERCLASSNAME");
private final static String URL = System.getenv("URL");
private final static String USERNAME = System.getenv("USERNAME");
private final static String PASSWORD = System.getenv("PASSWORD");
public static void main(String[] args) {
Thread app = new App();
app.run();
}
private Connection getConn() {
Connection conn = null;
try {
Class.forName(DRIVER);
conn = DriverManager.getConnection(URL, USERNAME, PASSWORD);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
return conn;
}
@Override
public void run() {
System.out.println("[INFO]try connect...");
int i = createConnection();
if (i <= 36) {
System.out.println("Successful connection...");
selectAll();
} else {
System.out.println("Failed to connect");
}
}
// 檢查是否成功連線MySQL,嘗試1min,不成功則報錯
public int createConnection() {
boolean flag = true;
Connection connection = null;
try {
Class.forName(DRIVER);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
int i = 0;
while (flag) {
if (i > 36) break; // 超過36次迴圈(3分鐘)則退出程式
System.out.println("try connect");
try {
connection = DriverManager.getConnection(URL, USERNAME, PASSWORD);
flag = false;
} catch (Exception e) {
i++;
flag = true;
try {
sleep(5000); // 休息5s
} catch (Exception e1) {
e1.printStackTrace();
}
}
}
return i;
}
private void selectAll() {
Connection conn = getConn();
String sql = "SELECT id,username FROM userinfo";
Statement st;
List<Person> list = new ArrayList<>();
try {
st=conn.createStatement();
ResultSet rs = st.executeQuery(sql);
System.out.println("============================");
while (rs.next()) {
Person p = new Person();
int id = rs.getInt("id");
String username = rs.getString("username");
p.setId(id);
p.setUsername(username);
list.add(p);
}
System.out.println(JSON.toJSONString(list)); //輸出成JSON格式
System.out.println("============================");
} catch (SQLException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}
編寫Java程式的Dockerfile:
Dockerfile
# 這個是構建Java環境的dockerfile
FROM registry.saas.hand-china.com/hap-cloud/base:latest
WORKDIR /
# 將系統編碼設定為c.utf-8,預設的POSIX不支援中文
ENV LANG C.UTF-8
ENV LANGUAGE C.UTF-8
ENV LC_ALL C.UTF-8
# 將子專案打包的jar包拷貝到專案根目錄
COPY target/Java1-1.0-SNAPSHOT.jar /test1.jar
# 設定容器啟動時執行的命令,-Dfile.encoding=utf-8
CMD ["java", "-jar", "test1.jar"]
執行結果
1 開啟git bash,進入專案根目錄,輸入
$ ./build.sh
$ ./start.sh
start.sh執行最後可以看到如下結果,說明執行成功:
最後ctrl+c退出,需要停止\刪除容器和映象則繼續執行:
$ ./stop.sh
$ ./remove.sh