1. 程式人生 > >使用docker-compose同時啟動MySQL與連線MySQL的java程式

使用docker-compose同時啟動MySQL與連線MySQL的java程式

說明

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