失乐园

技术之路

BlogJava 联系 聚合 管理
  19 Posts :: 44 Stories :: 40 Comments :: 0 Trackbacks
  常见问题和解决方案

  对于MySQL Connector/J用户,会遇到一些常见的共同问题。在本节中,介绍了它们的症状和相应的解决方法。 关于更进一步的信息,请参见“支持”一节。

  问题:

  当我尝试用MySQL Connector/J连接到数据库时,遇到下述异常:

  SQLException: Server configuration denies access to data source

  SQLState: 08001

  VendorError: 0

  出现了什么问题? 使用MySQL命令行客户端时,连接良好。

  回答:

  MySQL Connector/J必须使用TCP/IP套接字来连接MySQL,原因在于Java不支持Unix Domain套接字。因此,当MySQL Connector/J连接到MySQL时,MySQL服务器的安全管理器将使用其授权表判断是否允许连接。必须添加授权才能允许该操作。下面给出了一个执行该操作的示例(但并非最安全的)。

  从mysql命令行客户端以能够授权的用户身份登录,并发出下述命令:

  GRANT ALL PRIVILEGES ON [dbname].* to

  '[user]'@'[hostname]' identified by

  '[password]'

  用你的数据库名称替换[dbname],用用户名替换[user],用MySQL Connector/J将连接的主机替换[hostname],并用打算使用的密码替换[password]。注意,对于从本地主机进行连接的主机名部分,RedHat Linux将失败。在这种情况下,对于[hostname]值,需要使用“localhost.localdomain”。随后,发出FLUSH PRIVILEGES命令。

  注释:

  除非添加了“--host”标志,并为主机使用了不同于“localhost”的其他设置,否则将无法使用mysql命令行客户端测试连通性。如果使用了特殊的主机名“localhost”,mysql命令行客户端将使用Unix域套接字。如果正在测试与“localhost”的连通性,请使用 “127.0.0.1”作为主机名。

  警告

  如果你不了解“GRANT”命令是干什么的,或不了解该命令的工作方式,在尝试更改权限之前,请阅读MySQL手册中的 一般安全事宜以及MySQL访问权限体系一节。

  如果在MySQL中不恰当地更改了权限和许可,可能会使服务器不会具有最佳的安全性能。

  问题:

  我的应用程序抛出SQLException“无恰当的驱动程序”。为什么会出现该情况?

  回答:

  出现了两种情况之一。或是1驱动程序未位于你的CLASSPATH中(请参见前面的“安装部分”),或是URL格式不正确(请参见用MySQL Connector/J开发应用程序)。

  问题:

  当我试图在Java程序或应用程序中使用MySQL Connector/J时,遇到类似下面的异常:

  SQLException: 无法连接到host:3306上的MySQL服务器。

  在你尝试连接的机器/端口上是否有正在运行的MySQL服务器?

  (java.security.AccessControlException)

  SQLState: 08S01

  VendorError: 0

  回答:

  或许是因为你正在运行Applet,你的MySQL服务器是采用“--skip-networking”选项集安装的;或许是因为MySQL服务器位于防火墙之后。

  Applet仅能使网络连接返回运行Web服务器的机器,该Web服务器提供了用于Applet的.class文件。这意味着,要想使其工作, MySQL 必须运行在相同的机器上(或必须使某类端口重定向)。这还意味着,你无法通过你的本地文件系统来测试Java程序,你必须将它们放在Web服务器上。

  MySQL Connector/J仅能使用TCP/IP与MySQL进行通信,这是因为Java不支持Unix域套接字。如果MySQL是用“--skip-networking”标志启动的,或采用了防火墙,TCP/IP与MySQL的通信可能会受到影响。

  如果MySQL是用“--skip-networking”选项集启动的(例如MySQL服务器的Debian Linux包即用于该目的),需要在文件/etc/mysql/my.cnf或/etc/my.cnf中将其注释掉。当然,my.cnf文件也可能位于 MySQl服务器的“data”目录下或其他地方(取决于系统中MySQL的编译方式)。MySQL AB创建的二进制文件总会在查找/etc/my.cnf和[datadir]/my.cnf。如果为MySQL服务器部署了防火墙,需要对防火墙进行配置,允许从运行Java代码的主机在MySQL监听的端口上(默认为3306)建立与 MySQL服务器的TCP/IP连接。

  问题:

  I我的小服务程序/应用程序白天工作良好,但在晚上却停止工作。

  回答:

  不工作时间超过8小时后,MySQL关闭了连接。你或许需要使用能处理失效连接的连接池,或使用“autoReconnect”参数(请参见用MySQL Connector/J开发应用程序)。

  此外,你应在应用程序中俘获 SQLException并处理它们,而不是在应用程序退出前一直传播它们,这是1个好的编程习惯。在查询处理过程中遇到网络连通性方面的问题时, MySQL Connector/J会将SQLState(参见APIDOCS中的java.sql.SQLException.getSQLState())设置为 “08S01”。随后,应用程序代码将尝试再次连接到MySQL。

  在下面的示例(simplistic)中,给出了能够处理这类异常的代码:

  重试逻辑的事务示例

  public void doBusinessOp() throws SQLException {
   Connection conn = null;
   Statement stmt = null;
   ResultSet rs = null;

   //
   // How many times do you want to retry the transaction
   // (or at least _getting_ a connection)?
   //
   int retryCount = 5;

   boolean transactionCompleted = false;

   do {
    try {
     conn = getConnection(); // assume getting this from a
     // javax.sql.DataSource, or the
     // java.sql.DriverManager

     conn.setAutoCommit(false);

     //
     // Okay, at this point, the 'retry-ability' of the
     // transaction really depends on your application logic,
     // whether or not you're using autocommit (in this case
     // not), and whether you're using transacational storage
     // engines
     //
     // For this example, we'll assume that it's _not_ safe
     // to retry the entire transaction, so we set retry count
     // to 0 at this point
     //
     // If you were using exclusively transaction-safe tables,
     // or your application could recover from a connection going
     // bad in the middle of an operation, then you would not
     // touch 'retryCount' here, and just let the loop repeat
     // until retryCount == 0.
     //
     retryCount = 0;

     stmt = conn.createStatement();

     String query = "SELECT foo FROM bar ORDER BY baz";

     rs = stmt.executeQuery(query);

     while (rs.next()) {
     }

     rs.close();
     rs = null;

     stmt.close();
     stmt = null;

     conn.commit();
     conn.close();
     conn = null;

     transactionCompleted = true;
    } catch (SQLException sqlEx) {

     //
     // The two SQL states that are 'retry-able' are 08S01
     // for a communications error, and 41000 for deadlock.
     //
     // Only retry if the error was due to a stale connection,
     // communications problem or deadlock
     //

     String sqlState = sqlEx.getSQLState();

     if ("08S01".equals(sqlState) || "41000".equals(sqlState)) {
      retryCount--;
     } else {
      retryCount = 0;
     }
     } finally {
      if (rs != null) {
       try {
        rs.close();
       } catch (SQLException sqlEx) {
        // You'd probably want to log this . . .
       }
      }

      if (stmt != null) {
       try {
        stmt.close();
       } catch (SQLException sqlEx) {
        // You'd probably want to log this as well . . .
       }
      }

      if (conn != null) {
       try {
        //
        // If we got here, and conn is not null, the
        // transaction should be rolled back, as not
        // all work has been done

        try {
         conn.rollback();
        } finally {
         conn.close();
        }
        } catch (SQLException sqlEx) {
         //
         // If we got an exception here, something
         // pretty serious is going on, so we better
         // pass it up the stack, rather than just
         // logging it. . .

         throw sqlEx;
        }
       }
      }
     } while (!transactionCompleted && (retryCount > 0));
    }

  问题:

  我正尝试使用JDBC-2.0可更新结果集,但遇到异常,说我的结果集不可更新。

  回答:

  由于MySQL没有行ID,MySQL Connector/J仅能更新来自查询且位于有至少一个主键的表上的结果集,查询必须选择所有的主键,而且查询即能作用在1个表上(即不存在联合)。在JDBC规范中给出了这方面的介绍。
posted on 2008-07-27 20:22 狄浩 阅读(703) 评论(0)  编辑  收藏

只有注册用户登录后才能发表评论。


网站导航: