欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

使用docker-compose同时启动MySQL与连接MySQL的java程序

程序员文章站 2024-03-25 13:56:40
...

说明

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-compose同时启动MySQL与连接MySQL的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运行最后可以看到如下结果,说明运行成功:

使用docker-compose同时启动MySQL与连接MySQL的java程序

最后ctrl+c退出,需要停止\删除容器和镜像则继续运行:

$ ./stop.sh
$ ./remove.sh