沧海一粟

天下事有难易乎?为之,则难者亦易矣;不为,则易者亦难矣。

0%

jdk javac 使用笔记

最近有一个需求,需要测试一下新数据库(mysql优化版)某个表的写入速度和查询速度,需要从我们的测试环境数据库查数据,插入到新的测试环境的新数据库。
本地连不上测试的数据库
有很多应用服务器,但是所有的服务器不能连外网,只能访问公司内网。
测试环境的应用可以连测试的数据库
想写个python脚本,但是服务器上python是2.7的,而且很多包没有。
想了想,应用服务器部署了java程序,java的包都有,想写一个java脚本来测试。(没错是java脚本)

测试环境数据库 db_test_old 192.168.1.10
新测试环境新数据库 db_test_new 192.168.2.11
测试环境应用 test-java 192.168.3.12

在idea里写完脚本,运行没问题,然后在 terminal 运行,被啪啪的打脸

(1) 想象中运行java文件的样子

(1.1) 查看jdk版本

1
2
3
4
5
[wkq@VM_77_25_centos ~]$ java -version
java version "1.8.0_172"
Java(TM) SE Runtime Environment (build 1.8.0_172-b11)
Java HotSpot(TM) 64-Bit Server VM (build 25.172-b11, mixed mode)
[wkq@VM_77_25_centos ~]$

(1.2) 新建一个HelloWord.java文件测试

1
2
3
[wkq@VM_77_25_centos java_test]$ pwd
/home/wkq/workspaces/java_test
vi HelloWorld.java
1
2
3
4
5
public class HelloWorld{
public static void main(String[] args){
System.out.println("Hello, World!");
}
}

(1.3) 编译HelloWorld.java

1
2
3
[wkq@VM_77_25_centos java_test]$ javac HelloWorld.java

[wkq@VM_77_25_centos java_test]$

(1.4) 运行HelloWorld

1
2
3
4
5
6
7
8
9
10
[wkq@VM_77_25_centos java_test]$ pwd
/home/wkq/workspaces/java_test
[wkq@VM_77_25_centos java_test]$ ll
total 8
-rw-rw-r-- 1 wkq wkq 427 May 17 18:48 HelloWorld.class
-rw-rw-r-- 1 wkq wkq 112 May 17 18:47 HelloWorld.java
[wkq@VM_77_25_centos java_test]$
[wkq@VM_77_25_centos java_test]$ java HelloWorld
Hello, World!
[wkq@VM_77_25_centos java_test]$

没问题,很完美

(1.5) 被打脸的一幕

1
2
3
[wkq@VM_77_25_centos java_test]$ java HelloWorld.class
Error: Could not find or load main class HelloWorld.class
[wkq@VM_77_25_centos java_test]$

竟然不能运行 class文件
被打脸后才明白,java的参数,传入的是main函数所在的类的名字,而不是class文件;java会根据类名自动去找class文件。


(2) 复盘

(2.1) 查看jdk版本

1
2
3
4
5
[wkq@VM_77_25_centos ~]$ java -version
java version "1.8.0_172"
Java(TM) SE Runtime Environment (build 1.8.0_172-b11)
Java HotSpot(TM) 64-Bit Server VM (build 25.172-b11, mixed mode)
[wkq@VM_77_25_centos ~]$

(2.2) 新建MysqlLoadDataTest.java

1
vi MySqlLoadDataTest.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
package cn.wkq.java.test;

import java.sql.*;
import java.util.*;

/**
* MySqlLoadDataTest
*
* @author: weikeqin.cn@gmail.com
* @date: 2020-05-13 20:06
**/
public class MySqlLoadDataTest {


/**
* @param args
*/
public static void main(String[] args) {
MySqlLoadDataTest t = new MySqlLoadDataTest();
t.loadData();
System.out.println("执行完了。");
}


/**
*
*/
public void loadData() {

int batchSize = 100;
//
String driverClassName = "com.mysql.jdbc.Driver";

try {
Class.forName(driverClassName);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}

// 省略其它逻辑

}

}

(2.3) 编译

1
2
3
4
[wkq@VM_77_25_centos java_test]$ pwd
/home/wkq/workspaces/java_test
[wkq@VM_77_25_centos java_test]$ javac -encoding "utf-8" MySqlLoadDataTest.java
[wkq@VM_77_25_centos java_test]$

(2.4) 运行

1
2
3
4
5
6
[wkq@VM_77_25_centos java_test]$ java MySqlLoadDataTest
Error: Could not find or load main class MySqlLoadDataTest
[wkq@VM_77_25_centos java_test]$
[wkq@VM_77_25_centos java_test]$ java cn.wkq.java.test.MySqlLoadDataTest
Error: Could not find or load main class cn.wkq.java.test.MySqlLoadDataTest
[wkq@VM_77_25_centos java_test]$

(2.5) 注释掉第一行包名重新运行

如果把 文件的第一行注释掉,重新编译运行会出现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[wkq@VM_77_25_centos java_test]$ vi MySqlLoadDataTest.java
[wkq@VM_77_25_centos java_test]$
[wkq@VM_77_25_centos java_test]$ javac -encoding "utf-8" MySqlLoadDataTest.java
[wkq@VM_77_25_centos java_test]$
[wkq@VM_77_25_centos java_test]$ java MySqlLoadDataTest
java.lang.ClassNotFoundException: com.mysql.jdbc.Driver
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:349)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:264)
at MySqlLoadDataTest.loadData(MySqlLoadDataTest.java:35)
at MySqlLoadDataTest.main(MySqlLoadDataTest.java:20)
?????
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
[wkq@VM_77_25_centos java_test]$ pwd
/home/wkq/workspaces/java_test
[wkq@VM_77_25_centos java_test]$ cd /home/wkq/lib/
[wkq@VM_77_25_centos lib]$ wget "https://repo1.maven.org/maven2/mysql/mysql-connector-java/5.1.47/mysql-connector-java-5.1.47.jar"
--2020-05-17 21:59:08-- https://repo1.maven.org/maven2/mysql/mysql-connector-java/5.1.47/mysql-connector-java-5.1.47.jar
Resolving repo1.maven.org (repo1.maven.org)... 151.101.24.209
Connecting to repo1.maven.org (repo1.maven.org)|151.101.24.209|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 1007502 (984K) [application/java-archive]
Saving to: 'mysql-connector-java-5.1.47.jar'

100%[=====================================================================================>] 1,007,502 10.1KB/s in 85s

2020-05-17 22:00:34 (11.6 KB/s) - 'mysql-connector-java-5.1.47.jar' saved [1007502/1007502]

[wkq@VM_77_25_centos lib]$
[wkq@VM_77_25_centos lib]$ ll
total 988
-rw-rw-r-- 1 wkq wkq 1007502 Aug 7 2018 mysql-connector-java-5.1.47.jar
[wkq@VM_77_25_centos lib]$ pwd
/home/wkq/lib
[wkq@VM_77_25_centos java_test]$ java -Dfile.encoding=UTF-8 -classpath /home/wkq/lib/mysql-connector-java-5.1.47.jar:/home/wkq/workspaces/java_test MySqlLoadDataTest
执行完了。
[wkq@VM_77_25_centos java_test]$

在注释了第一行包路径后,重新编译
指定了classpath后就可以运行成功。
但是现在还有一个问题,测试的时候可以写一个java文件,但是实际开发的时候肯定不能不带包名

(2.6) 不注释第一行包名,把MySqlLoadDataTest.class换个目录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
[wkq@VM_77_25_centos java_test]$ ll
total 16
-rw-rw-r-- 1 wkq wkq 427 May 17 18:48 HelloWorld.class
-rw-rw-r-- 1 wkq wkq 112 May 17 18:47 HelloWorld.java
-rw-rw-r-- 1 wkq wkq 752 May 17 22:17 MySqlLoadDataTest.java
drwxrwxr-x 3 wkq wkq 4096 May 17 22:17 cn
[wkq@VM_77_25_centos java_test]$ pwd
/home/wkq/workspaces/java_test
[wkq@VM_77_25_centos java_test]$ java cn.wkq.java.test.MySqlLoadDataTest
java.lang.ClassNotFoundException: com.mysql.jdbc.Driver
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:349)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:264)
at cn.wkq.java.test.MySqlLoadDataTest.loadData(MySqlLoadDataTest.java:35)
at cn.wkq.java.test.MySqlLoadDataTest.main(MySqlLoadDataTest.java:20)
?????
[wkq@VM_77_25_centos java_test]$
[wkq@VM_77_25_centos java_test]$ java -Dfile.encoding=UTF-8 -classpath /home/wkq/lib/mysql-connector-java-5.1.47.jar cn.wkq.java.test.MySqlLoadDataTest
Error: Could not find or load main class cn.wkq.java.test.MySqlLoadDataTest
[wkq@VM_77_25_centos java_test]$
[wkq@VM_77_25_centos java_test]$ java -Dfile.encoding=UTF-8 -classpath /home/wkq/lib/mysql-connector-java-5.1.47.jar:/home/wkq/workspaces/java_test cn.wkq.java.test.MySqlLoadDataTest
执行完了。
[wkq@VM_77_25_centos java_test]$
```

> 可以看到,运行成功了,果然是加了包名以后,编译的main方法放到了对应目录下。
> 终于用教训理解了全限定类名
> 用教训理解了 Java 会根据包名对应出目录结构,并从class path搜索该目录去找class文件。 (默认是当前目录,如果运行时不在当前目录需要指定 classpath)


## (2.7) 不注释第一行包名,不换目录

> 正常情况下,我们写完java代码,直接编译后就可以运行,不可能再对每个文件创建目录。所以得换个办法。

```log
[wkq@VM_77_25_centos java_test]$ rm -rf cn/
[wkq@VM_77_25_centos java_test]$
[wkq@VM_77_25_centos java_test]$ javac -Dfile.encoding=UTF-8 -d MySqlLoadDataTest.java
javac: invalid flag: -Dfile.encoding=UTF-8
Usage: javac <options> <source files>
use -help for a list of possible options
[wkq@VM_77_25_centos java_test]$ javac -Dfile.encoding=UTF-8 -d . MySqlLoadDataTest.java
javac: invalid flag: -Dfile.encoding=UTF-8
Usage: javac <options> <source files>
use -help for a list of possible options
[wkq@VM_77_25_centos java_test]$ javac -encoding "utf-8" -d . MySqlLoadDataTest.java
[wkq@VM_77_25_centos java_test]$ ll
total 16
-rw-rw-r-- 1 wkq wkq 427 May 17 18:48 HelloWorld.class
-rw-rw-r-- 1 wkq wkq 112 May 17 18:47 HelloWorld.java
-rw-rw-r-- 1 wkq wkq 752 May 17 22:17 MySqlLoadDataTest.java
drwxrwxr-x 3 wkq wkq 4096 May 17 22:29 cn
[wkq@VM_77_25_centos java_test]$
[wkq@VM_77_25_centos java_test]$ java -Dfile.encoding=UTF-8 -classpath /home/wkq/lib/mysql-connector-java-5.1.47.jar:/home/wkq/workspaces/java_test cn.wkq.java.test.MySqlLoadDataTest
执行完了。
[wkq@VM_77_25_centos java_test]$

果然可以运行

编译java文件到指定目录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[wkq@VM_77_25_centos java_test]$ javac -encoding "utf-8" -d /home/wkq/workspaces/test_target/ MySqlLoadDataTest.java
[wkq@VM_77_25_centos java_test]$
[wkq@VM_77_25_centos java_test]$ ll
total 16
-rw-rw-r-- 1 wkq wkq 427 May 17 18:48 HelloWorld.class
-rw-rw-r-- 1 wkq wkq 112 May 17 18:47 HelloWorld.java
-rw-rw-r-- 1 wkq wkq 752 May 17 22:17 MySqlLoadDataTest.java
drwxrwxr-x 3 wkq wkq 4096 May 17 22:29 cn
[wkq@VM_77_25_centos java_test]$ cd /home/wkq/workspaces/test_target/
[wkq@VM_77_25_centos test_target]$ ll
total 4
drwxrwxr-x 3 wkq wkq 4096 May 17 22:32 cn
[wkq@VM_77_25_centos test_target]$
[wkq@VM_77_25_centos test_target]$ java -Dfile.encoding=UTF-8 -classpath /home/wkq/lib/mysql-connector-java-5.1.47.jar:/home/wkq/workspaces/java_test cn.wkq.java.test.MySqlLoadDataTest
执行完了。
[wkq@VM_77_25_centos test_target]$

开发工具idea是怎么编译代码的

1
javac -d target src/cn/wkq/java/test/*.java
1
/home/wkq/software/jdk1.8.0_172/bin/javac -encoding "utf-8" -d /home/wkq/workspaces/java_test/target/ /home/wkq/workspaces/java_test/src/*.java

jdk目录 /home/wkq/software/jdk1.8.0_172/bin/
java代码目录 /home/wkq/workspaces/java_test/src/
编译后存放目录 /home/wkq/workspaces/java_test/target/

开发工具idea是怎么运行代码的

1
/home/wkq/software/jdk1.8.0_172/bin/java -Dfile.encoding=UTF-8 -classpath /home/wkq/lib/mysql-connector-java-5.1.47.jar:/home/wkq/workspaces/java_test cn.wkq.java.test.MySqlLoadDataTest

jdk目录 /home/wkq/software/jdk1.8.0_172/bin/
指定 classpath目录 -classpath /home/wkq/lib/mysql-connector-java-5.1.47.jar:/home/wkq/workspaces/java_test
运行main方法 cn.wkq.java.test.MySqlLoadDataTest

javac命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
[wkq@VM_77_25_centos ~]$ /home/wkq/software/jdk1.8.0_172/bin/javac
Usage: javac <options> <source files>
where possible options include:
-g Generate all debugging info
-g:none Generate no debugging info
-g:{lines,vars,source} Generate only some debugging info
-nowarn Generate no warnings
-verbose Output messages about what the compiler is doing
-deprecation Output source locations where deprecated APIs are used
-classpath <path> Specify where to find user class files and annotation processors
-cp <path> Specify where to find user class files and annotation processors
-sourcepath <path> Specify where to find input source files
-bootclasspath <path> Override location of bootstrap class files
-extdirs <dirs> Override location of installed extensions
-endorseddirs <dirs> Override location of endorsed standards path
-proc:{none,only} Control whether annotation processing and/or compilation is done.
-processor <class1>[,<class2>,<class3>...] Names of the annotation processors to run; bypasses default discovery process
-processorpath <path> Specify where to find annotation processors
-parameters Generate metadata for reflection on method parameters
-d <directory> Specify where to place generated class files
-s <directory> Specify where to place generated source files
-h <directory> Specify where to place generated native header files
-implicit:{none,class} Specify whether or not to generate class files for implicitly referenced files
-encoding <encoding> Specify character encoding used by source files
-source <release> Provide source compatibility with specified release
-target <release> Generate class files for specific VM version
-profile <profile> Check that API used is available in the specified profile
-version Version information
-help Print a synopsis of standard options
-Akey[=value] Options to pass to annotation processors
-X Print a synopsis of nonstandard options
-J<flag> Pass <flag> directly to the runtime system
-Werror Terminate compilation if warnings occur
@<filename> Read options and filenames from file

[wkq@VM_77_25_centos ~]$

java命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
[wkq@VM_77_25_centos ~]$ /home/wkq/software/jdk1.8.0_172/bin/java
Usage: java [-options] class [args...]
(to execute a class)
or java [-options] -jar jarfile [args...]
(to execute a jar file)
where options include:
-d32 use a 32-bit data model if available
-d64 use a 64-bit data model if available
-server to select the "server" VM
The default VM is server.

-cp <class search path of directories and zip/jar files>
-classpath <class search path of directories and zip/jar files>
A : separated list of directories, JAR archives,
and ZIP archives to search for class files.
-D<name>=<value>
set a system property
-verbose:[class|gc|jni]
enable verbose output
-version print product version and exit
-version:<value>
Warning: this feature is deprecated and will be removed
in a future release.
require the specified version to run
-showversion print product version and continue
-jre-restrict-search | -no-jre-restrict-search
Warning: this feature is deprecated and will be removed
in a future release.
include/exclude user private JREs in the version search
-? -help print this help message
-X print help on non-standard options
-ea[:<packagename>...|:<classname>]
-enableassertions[:<packagename>...|:<classname>]
enable assertions with specified granularity
-da[:<packagename>...|:<classname>]
-disableassertions[:<packagename>...|:<classname>]
disable assertions with specified granularity
-esa | -enablesystemassertions
enable system assertions
-dsa | -disablesystemassertions
disable system assertions
-agentlib:<libname>[=<options>]
load native agent library <libname>, e.g. -agentlib:hprof
see also, -agentlib:jdwp=help and -agentlib:hprof=help
-agentpath:<pathname>[=<options>]
load native agent library by full pathname
-javaagent:<jarpath>[=<options>]
load Java programming language agent, see java.lang.instrument
-splash:<imagepath>
show splash screen with specified image
See http://www.oracle.com/technetwork/java/javase/documentation/index.html for more details.
[wkq@VM_77_25_centos ~]$

References

[1] javac
[2] 第1期:抛开IDE,了解一下javac如何编译