2018-11-16 10:46

2018-11-19 21:35

前言

  本篇文章记录的是本人在使用Java程序连接另一台电脑(同一局域网)上的Mysql数据库的过程中遇到的各种问题及解决方案。希望能给遇到同样问题的人提供一些帮助。当初本人遇到这些问题的时候,也是在各位大神的博客中找到的答案,本篇博客在某种程度上也算是这几个问题的答案集合吧。

软件环境

  客户端: Windows10  +  Java    [ IP: 192.168.76.10 ]

  数据库服务端: Ubuntu 16.04  +  Mysql 14.14      [  IP: 192.168.76.1 ]

  服务端的Mysql就是用最普通的 apt-get install 命令来安装的。安装完以后没有其它任何设置操作。

客户端使用的Java代码

  1. final String driver = "org.gjt.mm.mysql.Driver";
  2. final String url = "jdbc:mysql://192.168.76.1:3306/mysql";
  3. final String user = "root";
  4. final String password = "123456";
  5. Connection conn = null;
  6. PreparedStatement pstmt = null;
  7. ResultSet rs = null;
  8.  
  9. try{
  10. Class.forName(driver);
  11. conn = DriverManager.getConnection(url,user,password);
  12. String sql = "SELECT * FROM user";
  13. pstmt = conn.prepareStatement(sql);
  14. rs = pstmt.executeQuery();
  15. while(rs.next()){
  16. String h = rs.getString(1);
  17. String u = rs.getString(2);
  18. System.out.println("host:" + h + ",user:" + u);
  19. }
  20. }catch(Exception e){
  21. e.printStackTrace();
  22. }

  数据库服务端确认Mysql正常运行后,便可以尝试运行上面的代码去连接了。此时,便有几率遇到下面一系列问题。

问题一:报“连接超时”错误

  1. com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure
  2.  
  3. The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server.
  4. at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
  5. at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)
  6. at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source)
  7. at java.lang.reflect.Constructor.newInstance(Unknown Source)
  8. at com.mysql.jdbc.Util.handleNewInstance(Util.java:404)
  9. at com.mysql.jdbc.SQLError.createCommunicationsException(SQLError.java:981)
  10. at com.mysql.jdbc.MysqlIO.<init>(MysqlIO.java:339)
  11. at com.mysql.jdbc.ConnectionImpl.coreConnect(ConnectionImpl.java:2253)
  12. at com.mysql.jdbc.ConnectionImpl.connectOneTryOnly(ConnectionImpl.java:2286)
  13. at com.mysql.jdbc.ConnectionImpl.createNewIO(ConnectionImpl.java:2085)
  14. at com.mysql.jdbc.ConnectionImpl.<init>(ConnectionImpl.java:795)
  15. at com.mysql.jdbc.JDBC4Connection.<init>(JDBC4Connection.java:44)
  16. at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
  17. at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)
  18. at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source)
  19. at java.lang.reflect.Constructor.newInstance(Unknown Source)
  20. at com.mysql.jdbc.Util.handleNewInstance(Util.java:404)
  21. at com.mysql.jdbc.ConnectionImpl.getInstance(ConnectionImpl.java:400)
  22. at com.mysql.jdbc.NonRegisteringDriver.connect(NonRegisteringDriver.java:327)
  23. at java.sql.DriverManager.getConnection(Unknown Source)
  24. at java.sql.DriverManager.getConnection(Unknown Source)
  25. at Main.init(Main.java:25)
  26. at Main.main(Main.java:10)
  27. Caused by: java.net.ConnectException: Connection timed out: connect
  28. at java.net.DualStackPlainSocketImpl.connect0(Native Method)
  29. at java.net.DualStackPlainSocketImpl.socketConnect(Unknown Source)
  30. at java.net.AbstractPlainSocketImpl.doConnect(Unknown Source)
  31. at java.net.AbstractPlainSocketImpl.connectToAddress(Unknown Source)
  32. at java.net.AbstractPlainSocketImpl.connect(Unknown Source)
  33. at java.net.PlainSocketImpl.connect(Unknown Source)
  34. at java.net.SocksSocketImpl.connect(Unknown Source)
  35. at java.net.Socket.connect(Unknown Source)
  36. at com.mysql.jdbc.StandardSocketFactory.connect(StandardSocketFactory.java:211)
  37. at com.mysql.jdbc.MysqlIO.<init>(MysqlIO.java:298)
  38. ... 16 more

  这种问题出现的几率比较小,本人也是在一次测试中偶然发现有这个问题的。如果很不幸你遇到了这个问题,那想也不用想,原因肯定是客户端到数据库服务端的网络不通。网络不通的原因就多种多样了,解决办法也因问题根源而异。本文也没办法罗列各种导致网络不通的情况并给出解决办法。只能讲个大概。

  1、确认两台机器是否处于同一局域网段(本文讨论的环境就是基于同一网段的远程访问);

  2、检查客户端防火墙;

  3、检查路由器;

  4、检查数据库服务器防火墙;

  5、检查Mysql服务端程序运行情况及端口监听情况;

  6、检查服务器端防火墙;

  一般问题的答案都包含在上述几个步骤中了。上述步骤6中检查Linux的防火墙除了检查 ufw 以外还一定要检查一下 iptables 。本人遇到这个问题的原因就是因为在 iptables 中配置了禁止外部数据进入Linux的规则。关于 ufw 与 iptables 的配置,大家要根据自己的实际需要来独立配置,同时配置Linux防火墙也比较复杂,这部分知识就不在本文的讨论范围之内了。本人的ubuntu是完全放开 iptables 限制的,并且还把 ufw 卸载掉了。

问题二:报“拒绝连接”错误

  1. com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure
  2.  
  3. The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server.
  4. at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
  5. at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)
  6. at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source)
  7. at java.lang.reflect.Constructor.newInstance(Unknown Source)
  8. at com.mysql.jdbc.Util.handleNewInstance(Util.java:404)
  9. at com.mysql.jdbc.SQLError.createCommunicationsException(SQLError.java:981)
  10. at com.mysql.jdbc.MysqlIO.<init>(MysqlIO.java:339)
  11. at com.mysql.jdbc.ConnectionImpl.coreConnect(ConnectionImpl.java:2253)
  12. at com.mysql.jdbc.ConnectionImpl.connectOneTryOnly(ConnectionImpl.java:2286)
  13. at com.mysql.jdbc.ConnectionImpl.createNewIO(ConnectionImpl.java:2085)
  14. at com.mysql.jdbc.ConnectionImpl.<init>(ConnectionImpl.java:795)
  15. at com.mysql.jdbc.JDBC4Connection.<init>(JDBC4Connection.java:44)
  16. at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
  17. at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)
  18. at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source)
  19. at java.lang.reflect.Constructor.newInstance(Unknown Source)
  20. at com.mysql.jdbc.Util.handleNewInstance(Util.java:404)
  21. at com.mysql.jdbc.ConnectionImpl.getInstance(ConnectionImpl.java:400)
  22. at com.mysql.jdbc.NonRegisteringDriver.connect(NonRegisteringDriver.java:327)
  23. at java.sql.DriverManager.getConnection(Unknown Source)
  24. at java.sql.DriverManager.getConnection(Unknown Source)
  25. at Main.init(Main.java:24)
  26. at Main.main(Main.java:10)
  27. Caused by: java.net.ConnectException: Connection refused: connect
  28. at java.net.DualStackPlainSocketImpl.connect0(Native Method)
  29. at java.net.DualStackPlainSocketImpl.socketConnect(Unknown Source)
  30. at java.net.AbstractPlainSocketImpl.doConnect(Unknown Source)
  31. at java.net.AbstractPlainSocketImpl.connectToAddress(Unknown Source)
  32. at java.net.AbstractPlainSocketImpl.connect(Unknown Source)
  33. at java.net.PlainSocketImpl.connect(Unknown Source)
  34. at java.net.SocksSocketImpl.connect(Unknown Source)
  35. at java.net.Socket.connect(Unknown Source)
  36. at com.mysql.jdbc.StandardSocketFactory.connect(StandardSocketFactory.java:211)
  37. at com.mysql.jdbc.MysqlIO.<init>(MysqlIO.java:298)
  38. ... 16 more

  从这条错误异常中我们知道是Mysql服务拒绝了我们的连接请求,这至少说明我们客户端与服务端是能够成功建立通信的,和网络无关。问题可能就出在Mysql的安全配置上了。我们先来看看服务端Mysql端口的监听情况。

  1. netstat -ntlp | grep 3306

图1  服务端Mysql端口监听情况

  由上图1可知,目前我们的Mysql服务端仅监听来自ubuntu本机3306端口上的数据库请求。这也就是我们从远端尝试连接时报出一个拒绝连接错误的原因。解决的方案也很清晰:取消仅监听本机3306端口的方式,改为监听指定目标网址或者监听全网址。

  我这边发现,可能不同版本的Mysql关于设置监听网址的位置不一样。但都在Mysql程序的安装目录下。所以这里推荐使用grep命令来查找自己的Mysql程序是在哪个文件中设置了绑定IP监听的。

  我这边是通过apt-get命令安装的Mysql,因此,先进到下面目录下

  1. /etc/mysql

  然后搜索哪里有绑定127.0.0.1的网址

  1. grep -nr "127.0.0.1"

图2  Mysql绑定网址的设定

  由上图2,直接去修改mysql.cnf文件即可。

图3  bind-address的描述

  由上图3所示,这个bind-address默认设为监听回环地址的目的是为了兼容与安全。这里我们可管不了这么多,直接将它改成监听我们ubuntu服务器本机的固定IP地址,如上图所示。 这个192.168.76.1是我在自己的路由器上设置过的,固定分配给这台ubuntu机器使用所以才这么写,你们可以将它换成你自己的IP地址。如果不想写死,直接将bind-address属性注释掉即可

  修改完保存后要重启一下Mysql服务。

  1. service mysql restart

图4  重启Mysql服务

  重启完成后可以再查询一下3306端口的监听情况以确定修改成功与否。

图5  再次确认3306端口的监听地址

  此时,我们再运行一下我们的Java程序,不出意外,就能发现先前的“拒绝连接”异常已经没有了。但是,它又报了另一个异常。 ^_^

问题三:报“主机不被允许访问”

  1. java.sql.SQLException: null, message from server: "Host '192.168.76.10' is not allowed to connect to this MySQL server"
  2. at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:957)
  3. at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:896)
  4. at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:885)
  5. at com.mysql.jdbc.MysqlIO.doHandshake(MysqlIO.java:1038)
  6. at com.mysql.jdbc.ConnectionImpl.coreConnect(ConnectionImpl.java:2255)
  7. at com.mysql.jdbc.ConnectionImpl.connectOneTryOnly(ConnectionImpl.java:2286)
  8. at com.mysql.jdbc.ConnectionImpl.createNewIO(ConnectionImpl.java:2085)
  9. at com.mysql.jdbc.ConnectionImpl.<init>(ConnectionImpl.java:795)
  10. at com.mysql.jdbc.JDBC4Connection.<init>(JDBC4Connection.java:44)
  11. at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
  12. at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)
  13. at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source)
  14. at java.lang.reflect.Constructor.newInstance(Unknown Source)
  15. at com.mysql.jdbc.Util.handleNewInstance(Util.java:404)
  16. at com.mysql.jdbc.ConnectionImpl.getInstance(ConnectionImpl.java:400)
  17. at com.mysql.jdbc.NonRegisteringDriver.connect(NonRegisteringDriver.java:327)
  18. at java.sql.DriverManager.getConnection(Unknown Source)
  19. at java.sql.DriverManager.getConnection(Unknown Source)
  20. at Main.init(Main.java:24)
  21. at Main.main(Main.java:10)

  上面的异常信息讲的也够直白。客户端不被允许接入到服务端中去。我们的Mysql服务在默认情况下确实是不接受任何外部主机的访问请求的。这点可以查我们Mysql中的配置数据得知。

  1. 1、进入到mysql控制台。 本人是通过 mysql -u root -p 的方式进入的。
  2.  
  3. 2use mysql
  4.  
  5. 3select*from user;

图6  Mysql中默认的允许接入帐户

  由上图6可知,在本人的Mysql默认配置中,仅三个帐户被允许访问,分别是:1、root; 2、mysql.sys; 3、debian-sys-maint; 并且这三个帐户均绑定为在ubuntu本机上登录才拥有接入权限。

  那么,解决这个外部主机没权限接入数据库的方案一般有三种:1、直接通过update语句修改user表中现有的信息,使仅监听localhost变为监听全网址或指定网址。 2、 通过insert语句在user表中新增项,增加允许访问的帐户及主机域名。  3、通过grant语句新增允许访问的帐户及主机域名。  在这三种方式中,前面两种本人极力不推荐并且鄙视这两种做法。这里仅介绍一下第3种解决方案。

  可以在Mysql控制台上执行下面语句:

  1. GRANT ALL PRIVILEGES ON *.* TO 'root'@'192.168.76.10' IDENTIFIED BY '123456' WITH GRANT OPTION;

  上面的语句表示允许IP为“192.168.76.10”的主机通过“root”帐户以“123456”为密码访问Mysql数据库。

  如果不想写死主机IP,可以改用下面的语句:

  1. GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY '123456' WITH GRANT OPTION;

  如果不想使用密码,可以使用下面的语句:

  1. GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' WITH GRANT OPTION;

  

  执行完上面的语句后,一定不要忘记还要再执行一下刷新配置的语句

  1. FLUSH PRIVILEGES;

  当上面的语句都执行成功以后,可以再查询一下user表中的信息以确认操作是否成功。

图7  确认user表

  上图7中展示了我已经给我的客户端主机开放了权限。现在我们再去跑一下Java程序。

图8  运行成功

  终于成功从远端主机上查询到了服务端上Mysql的数据了。

  

Java连接远程Mysql过程中遇到的各种问题的更多相关文章

  1. java web添加mysql过程中遇到的错误及解决办法

    问题一:遇到提示找不到驱动   com.mysql.jdbc.Driver 起初项目中是导入了mysql-connector-java-5.1.45-bin.jar 包的,但是一直依然报错,最后去官网 ...

  2. Windows环境下,本地Oracle创建dblink连接远程mysql

    前言 我的情况是,本地安装了oracle(安装完成后带有SQL Developer,不需要再安装instantclient),创建dblink去连接远程的mysql.有些朋友可能是 本地使用PL\SQ ...

  3. JDBC Java 程序从 MySQL 数据库中读取数据,并备份到 xml 文档中

    MySQL 版本:Server version: 5.7.17-log MySQL Community Server (GPL) 相关内容:JDBC Java 程序从 MySQL 数据库中读取数据,并 ...

  4. Python使用Mysql过程中一些错误

    Python使用Mysql过程中一些错误 ssh登录远程服务器 ssh ubuntu@xxx.xxx.xx.xx 第一:ubuntu终端中登录Mysql mysql -uroot -p 然后输入密码即 ...

  5. phpmyadmin连接远程mysql

    phpmaadmin连接远程mysql连接远程mysql步骤.保证已经有�phpmyadmin,如果没有,去http://www.phpmyadmin.net/home_page/downloads. ...

  6. 连接远程MySQL数据库项目启动时,不报错但是卡住不继续启动的,

    连接远程MySQL数据库项目启动时,不报错但是卡住不继续启动的, 2018-03-12 17:08:52.532DEBUG[localhost-startStop-1]o.s.beans.factor ...

  7. Java程序向MySql数据库中插入的中文数据变成了问号

    找到mysql的安装目录,修改my.ini文件 (1)如何找到my.ini文件 如果my.ini文件不在MySQL的安装目录下,可能放在隐藏目录,要先去找到ProgramData,(这里要先打开显示隐 ...

  8. 3-Windows-CMD启动mysql服务-连接本地mysql服务-连接远程mysql服务

    转自: https://jingyan.baidu.com/article/84b4f565b77a5660f6da32d4.html 备注: 如果在连接远程mysql服务,无法连接时,可能是远程my ...

  9. JDBC Java 程序从 MySQL 数据库中读取数据,并封装到 Javabean 对象中

    MySQL 版本:Server version: 5.7.17-log MySQL Community Server (GPL) 相关内容:JDBC Java 连接 MySQL 数据库 用于测试的 M ...

随机推荐

  1. CSS变量(自定义属性)实践指南

    本文翻译自:https://www.sitepoint.com/practical-guide-css-variables-custom-properties/ 转载请注明出处:葡萄城官网,葡萄城为开 ...

  2. Truffle 4.0、Geth 1.7.2、TestRPC在私有链上搭建智能合约

    目录 目录 1.什么是 Truffle? 2.适合 Truffle 开发的客户端 3.Truffle的源代码地址 4.如何安装? 4.1.安装 Go-Ethereum 1.7.2 4.2.安装 Tru ...

  3. Camera Binning Mode

    Camera Binning Mode:像素合并模式,将相邻的像素单元电荷通过物理的方法叠加在一起作为一个像素输出信号: 水平方向Binning:  同列相邻行的电荷叠加 垂直方向Binning:   ...

  4. 用SQL语句实现:当A列大于B列时选择A列否则选择B列,当B列大于C列时选择B列否则选择C列。

    数据库中有A B C三列,用SQL语句实现:当A列大于B列时选择A列否则选择B列,当B列大于C列时选择B列否则选择C列. 方法一: select (case when a>b then a el ...

  5. 01背包问题(动态规划)python实现

    01背包问题(动态规划)python实现 在01背包问题中,在选择是否要把一个物品加到背包中.必须把该物品加进去的子问题的解与不取该物品的子问题的解进行比較,这样的方式形成的问题导致了很多重叠子问题, ...

  6. vim美化基本配置

    在home目录中创建一个 .vimrc文件 vim ~/.vimrc 文件基本配置 " 设置当文件被改动时自动载入 set autoread " quickfix模式 autocm ...

  7. SQL 增删改语句

    阅读目录 一:插入数据 二:更新数据 三:删除数据 回到顶部 一:插入数据 把数据插入表中的最简单方法是使用基本的 INSERT 语法.它的要求是需要我们指定表名和插入到新行中的值. 1.1 插入完整 ...

  8. Error:Execution failed for task ':app:processDebugManifest'. Manifest merger failed with multiple errors, see logs

    这个异常在网上一搜会出现很多答案,也可能都对. 我都尝试过但是不符合我这边的要求,问题得不到解决.网上的说法是对的,jar包冲突.不过究竟是哪里冲突没办法判断. 最后尝试了一下在module的中没用的 ...

  9. React-关于react的思考

    声明式开发 减少dom操作,减少代码量 可以与其他框架并存 组件化开发 单向数据流 视图层框架 大型项目需要与其他数据层框架一起使用 函数式编程 方便自动化测试

  10. [Oracle]Sqlplus 中使用 new_value

    通过再sqlplus 中使用 new_value,可以把从表中查询出来的值,放置到 变量中.然后使用变量时,类似与宏定义一样,就可以像使用表中字段一样方便. 这使得sqlplus 的脚本具备和pl/s ...