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版本

[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文件测试

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

(1.3) 编译HelloWorld.java

[wkq@VM_77_25_centos java_test]$ javac HelloWorld.java

[wkq@VM_77_25_centos java_test]$

(1.4) 运行HelloWorld

[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) 被打脸的一幕

[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版本

[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

vi MySqlLoadDataTest.java
package cn.wkq.java.test;

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

/**
 * MySqlLoadDataTest
 *
 * @author: 
 * @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) 编译

[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) 运行

[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) 注释掉第一行包名重新运行

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

[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)
?????
[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换个目录

[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文件到指定目录

[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是怎么编译代码的

javac -d target src/cn/wkq/java/test/*.java
/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是怎么运行代码的

/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命令

[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命令

[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如何编译