使用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
上一篇: Mac下Docker安装
下一篇: CentOS7安装配置Docker-CE