如果您需要转载本书内容, 请与本站联系! Email: wlsmon@qq.com.

企业的开发离不开数据库的操作,用Java如何访问数据库这也是一个难点,当时我读书的时候初学Java,试了好多次才成功的向数据库中插入了数据。那么本节内容就讲解如何在普通项目中用JDBC访问数据库,使用的数据库是MySQL 5.0,用别的数据库或者Derby也可以完成这个练习,只是建表语句略微不同,可以参考第四章的内容用新建表格向导来完成。

</p>

本章内容参考视频:http://www.blogjava.net/beansoft/archive/2007/09/26/148267.html MyEclipse 6 实战开发讲解视频入门 1 安装运行 Mysql, MySQL-Front 管理, JDBCHelloWorld 开发

</p>

5.1系统需求 </p>

</span></h2>

本节内容需要安装MySQL数据库,请参考MySQL 5数据库服务器下载,安装和运行(可选)一节内容来安装并启动MySQL数据库以及获得对应的JDBC驱动jar文件。

也可以直接用 MyEclipse Derby数据库完成这个练习。

</p>

5.2创建数据库表格 </p>

</span></h2>

对于多数的项目来说,基本上前期的工作就是进行需求分析,分析的结果一是功能模块,二可能就是实体或者对象,实体最终就会映射到数据库设计中去。所以这里先从创建数据库开始。

首先需要创建一个学生表,建表的SQL如下所示:

</p>

CREATE TABLE Student (

</p>

  id int NOT NULL auto_increment,

</p>

  username varchar(200) NOT NULL,

</p>

  password varchar(20) NOT NULL,

</p>

  age int,

</p>

  PRIMARY KEY  (id)

</p>

) ENGINE=MyISAM DEFAULT CHARSET=GBK

</p>

注意:这个是MySQL数据库的建表语句。这个表有一个自增的ID列作为主键,还有用户名,密码和年龄三个列,最后一句ENGINE=MyISAM DEFAULT CHARSET=GBK指定了表的默认字符集是GBK中文字符,这一句是MySQL特有的语法。请参考第四章的内容在MyEclipse Database Explorer透视图的DB Browser视图中打开mysql5 这个连接,展开并选中test数据库,然后参考编辑和执行SQL代码段一节的内容打开SQL编辑器,将上述代码粘贴进去,然后点击运行按钮clip_image001来创建这个表。

</p>

如果要用 Derby 数据库做这个练习,对应的建表语句是:

</p>

CREATE TABLE Student (

</p>

  id int NOT NULL generated always as identity,

</p>

  username varchar(200) NOT NULL,

</p>

  password varchar(20) NOT NULL,

</p>

  age int,

</p>

  PRIMARY KEY  (id)

</p>

)

</p>

</p>

需要指出的是,并非所有数据库都支持自增类型的主键,而且不同的数据库实现主键生成的关键字也是没有统一规定的,例如Oracle使用一个叫sequence的概念来生成主键。 那么通用的不带主键生成器的建表语句如下所示:

</p>

CREATE TABLE Student (

</p>

  id int NOT NULL,

</p>

  username varchar(200) NOT NULL,

</p>

  password varchar(20) NOT NULL,

</p>

  age int,

</p>

  PRIMARY KEY  (id)

</p>

)

</p>

</p>

MyEclipse建表的操作过程如下图所示:

</p>

       clip_image003

</p>

5.1 MyEclipse Database Browser创建表格

</p>

。当然对于MySQL数据库来说,也可以用MySQL-FrontNavicat等工具来方便的建表,所以本节的内容也是可能的操作方式之一。

</p>

5.3创建Java项目 </p>

</span></h2>

       请参考使用Eclipse/MyEclipse来编写,编译并运行Java程序一节来创建一个名为JDBCHelloWorldJava项目。

首先确保已经打开了MyEclipse Java Enterprise透视图,然后从菜单栏选择 File > New > Java Project,接着会打开 New Java Project 向导对话框,在Project name 中输入JDBCHelloWorld,点击Finish按钮关闭对话框,这样一个Java项目就建立完毕了。稍等片刻会弹出一个切换透视图的对话框,为了避免造成更多的麻烦,我们一般选择No按钮就可以了。

</p>

5.4添加JDBC驱动到Build Path </p>

</span></h2>

       要连接数据库必须要将JDBC驱动类库加入到项目的Build Path中,详情可以参考复制项目中的文件快速加入、删除jar包到Build Path一节的内容。不同的数据库的JDBC驱动类库文件是不一样的。首先需要找到对应的驱动,MySQL的可以从官方网站下载,而MyEclipse Derby的则位于Windows当前用户的配置文件目录下面,例如C:\Documents and Settings\BeanSoft\.myeclipse\libs\derby_10.2.2.0\ derbyclient.jar。在Windows的文件浏览器中选中文件并复制到剪贴板(选择菜单编辑>复制,或者在文件上点击右键选择菜单复制,或者按下组合键Ctrl + C),然后点击任务栏切换到MyEclipse的窗口,在Package Explorer视图中选中刚刚创建的JDBCHelloWorld项目,接着可以进行粘贴操作,点击菜单 Edit > Paste 或者在JDBCHelloWorld项目节点的上下文菜单中选择 Paste,或者按下快捷键 Ctrl + V,这时候驱动程序的JAR文件例如mysql-connector-java-3.1.11-bin.jar就复制并添加到了当前项目中。点击一下来选中这个jar文件,然后单击鼠标右键,选择菜单Build Path > Add to Build Path 就可以将这个jar文件加入Build Path中,如下图所示:

clip_image005

</p>

5.2 将驱动jar文件加入Build Path

</p>

5.5编写JDBC访问类 </p>

</span></h2>

       至此开发环境已经准备好了,所缺的就是写Java程序来访问数据库了。

接着选择菜单File > New >Class然后(New Java Class)新建类的对话框就出现了,参考图2.4,接着Name输入框中输入JDBCHelloWorld,点击完成。接着将编辑器里面的代码修改成如下所示:

</p>

/*

</p>

 * JDBCHelloWorld.java

</p>

 * 版权所有 2008 刘长炯(BeanSoft@126.com)

</p>

 * Blog: http://www.blogjava.net/beansoft/

</p>

 * 本代码协议: GPL

</p>

 */

</p>

import java.sql.*;

</p>

 

</p>

/**

</p>

 * 第一个 JDBC HelloWorld 程序, 数据库访问 MySQL.

</p>

 *

</p>

 * @author BeanSoft@126.com

</p>

 * @version 0.4 20080617

</p>

 */

</p>

public class JDBCHelloWorld {

</p>

 

</p>

    public static void main(String[] args) {

</p>

       // 1. 注册驱动

</p>

       try {

</p>

           Class.forName("com.mysql.jdbc.Driver");

</p>

       } catch (ClassNotFoundException e) {

</p>

           // TODO Auto-generated catch block

</p>

           e.printStackTrace();

</p>

       }// Mysql 的驱动

</p>

 

</p>

       // 先定义变量,后使用和关闭

</p>

       Connection conn = null;// 数据库连接

</p>

       Statement stmt = null;// 数据库表达式

</p>

       ResultSet rs = null;// 结果集

</p>

 

</p>

       try {

</p>

           // 2. 获取数据库的连接

</p>

           conn = java.sql.DriverManager

</p>

                  .getConnection(

</p>

                         "jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=GBK",

</p>

                         "root", null);// root是用户名,密码为空

</p>

 

</p>

           // 3. 获取表达式

</p>

           stmt = conn.createStatement();

</p>

 

</p>

           // 执行插入数据的 SQL

</p>

           int row = stmt

</p>

                  .executeUpdate("insert into Student(username, password, age) values(‘张三‘, ‘1234’, 20)");

</p>

           System.out.println("插入了 " + row);

</p>

           // 4. 执行 SQL

</p>

           rs = stmt.executeQuery("select * from Student");

</p>

 

</p>

           // 5. 显示结果集里面的数据

</p>

           while (rs.next()) {

</p>

              System.out.println("编号=" + rs.getInt(1));

</p>

              System.out.println("学生姓名=" + rs.getString("username"));

</p>

              System.out.println("密码=" + rs.getString("password"));

</p>

              System.out.println("年龄=" + rs.getString("age"));

</p>

           }

</p>

 

</p>

           // 执行删除数据的 SQL, 被删除的记录的ID7

</p>

           row = stmt.executeUpdate("delete from student where id = 7");

</p>

           System.out.println("删除了 " + row);

</p>

       } catch (SQLException e) {

</p>

           e.printStackTrace();

</p>

       } finally {

</p>

           // 6. 释放资源,建议放在finally语句中确保都被关闭掉了

</p>

           try {

</p>

              rs.close();

</p>

           } catch (SQLException e) {

</p>

           }

</p>

           try {

</p>

              stmt.close();

</p>

           } catch (SQLException e) {

</p>

           }

</p>

           try {

</p>

              conn.close();

</p>

           } catch (SQLException e) {

</p>

           }

</p>

       }

</p>

 

</p>

    }

</p>

 

</p>

}

</p>

 

</p>

jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=GBK这个是连接到MySQL数据库的JDBC URL,关于这段代码中的?useUnicode=true&characterEncoding=GBK是说以支持国际字符集(Unicode)的方式并以GBK中文字符集连接到数据库,如果安装时候选择的数据库的默认字符集是UTF-8,那么这个地方把GBK 换称UTF-8就可以了。当然更快的办法是你将这段代码直接复制,然后在MyEclipse中点击菜单Edit > Paste就可以生成这个类文件了。当你的代码编写完毕后,MyEclipse会自动将代码编译成类文件。

</p>

接下来就可以运行写好的类了,选择菜单 Run > Run 或者按下快捷键 Ctrl+F11,就可以看到Eclipse会自动调用Java解释器,然后在Console视图中输出:

</p>

插入了 1

</p>

编号=1

</p>

学生姓名=spring hibernate 标注事务测试

</p>

密码=密码

</p>

年龄=200

</p>

省略其它多行数据

</p>

编号=11 </p>

</b>

</p>

学生姓名=张三 </p>

</b>

</p>

密码=1234 </p>

</b>

</p>

年龄=20 </p>

</b>

</p>

删除了 1

</p>

 

</p> </td> </tr> </tbody> </table>

这个程序就执行成功了,粗体部分为刚刚插入的数据。再执行一次将会输出两行数据:

</p>

编号=11

</p>

学生姓名=张三

</p>

密码=1234

</p>

年龄=20

</p>

编号=12

</p>

学生姓名=张三

</p>

密码=1234

</p>

年龄=20

</p>

 

</p>

。可以看到ID是自动生成的。

</p>

如果要连接到Derby数据库,这段程序稍作修改即可,参考红色字体:

</p>

 

</p>

/*

</p>

  * JDBCHelloWorld.java

</p>

  * 版权所有 2007 刘长炯(BeanSoft@126.com)

</p>

  * Blog: http://www.blogjava.net/beansoft/

</p>

  * 本代码协议: GPL

</p>

  */

</p>

import java.sql.SQLException;

</p>

/**

</p>

 * 第一个 JDBC HelloWorld 程序, 数据库访问 MySQL.

</p>

 * @author BeanSoft@126.com

</p>

 * @version 0.3 20071212

</p>

 */

</p>

public class JDBCHelloWorld {

</p>

 

</p>

 

</p>

    public static void main(String[] args) {

</p>

       // 1. 注册驱动

</p>

       try {

</p>

           Class.forName("org.apache.derby.jdbc.ClientDriver");

</p>

       } catch (ClassNotFoundException e) {

</p>

           // TODO Auto-generated catch block

</p>

           e.printStackTrace();

</p>

       }

</p>

       ……

</p>

      

</p>

       try {

</p>

           // 2. 获取数据库的连接

</p>

           conn = java.sql.DriverManager.getConnection(

</p>

                  "jdbc:derby://localhost:1527/myeclipse", "classiccars", "classiccars");

</p>

          

</p>

           ……

</p>

 

</p>

5.6小结 </p>

</span></h2>

       本节内容讨论了如何使用MyEclipse开发用JDBC访问数据库的Java类,基本上包括安装数据库,建表,创建项目,加入驱动类,创建类,运行代码(相当于测试)这几个步骤。因为实际工作中很多公司因为项目周期长的原因,因此纯JDBC方式的数据库访问代码可能会经常看到。

注意:本节内容并不能代替您来学习JDBC,请阅读书籍等来获取更多信息。关于JDBC分页,PreparedStatement等高级内容可以从Google搜索。在第八章的JSPHelloWorld项目中,我们用到了PreparedStatement

</p>

5.7参考资料 </p>

</span></h2>

5.7.1 网页 </p>

</span></h3>

http://www.blogjava.net/beansoft/archive/2007/10/23/155318.html 基于_JDBC_2.0_驱动的分页代码实现 </p>

</span>

</p>

http://www.blogjava.net/beansoft/archive/2007/07/10/129354.html 学习 SQL 语法的好资料: Transact-SQL 参考 </p>

</span>

</p>

       这个资料是我上大学时候一直看到现在的,既可以作为学习资料,更可以作为开发时候的速查手册。具体来说就是安装了 SQL Server 2000 后里面自带的帮助文档的一部分。此文件位于光盘的参考资料目录下,文件名是Transact SQL参考.zip,解压缩后双击TSQLREF.CHM即可阅读;同一个目录下还有文件MySQL5_chinese.chm,内容是MySQL 5.1参考手册。

</p>

http://dev.mysql.com/doc/refman/5.1/zh/index.html MySQL 5.1参考手册中文版,MySQL官方翻译版本

</p>

5.7.2 JDBC 要点 </p>

</span></h3>

       下文为方便理解本章内容所整理的JDBC要点,需要指出的是,这一节内容不能代替专业的JDBC教材或者参考资料。

JDBC 要点

</p>

 

</p>

1. 用接口的方式将数据库分成两部分. 一部分是对开发人员提供的编程接口, java.sql.*;第二部分是给各大厂商, 给他们是驱动接口(java.sql.Driver).

</p>

DriverManager.getConnection(String url, String username, String password).

</p>

java.sql.Connection ==> 实现类, 不是接口.

</p>

class OracleConnection implements java.sql.Connection

</p>

createStatement() -> OracleStatement implements java.sql.Statement

</p>

 

</p>

提供者/调用者 => 工厂模式 => 透明的开发和调用

</p>

 

</p>

2. 一般的 JDBC 项目(增删查改)

</p>

增删改: 能改数据

</p>

INSERT INTO TABLE_NAME [(1, 2, …)] VALUES(1, 2, …)

</p>

DELETE TABLE_NAME [WHERE 条件子句]

</p>

       列名 = AND 列名 LIKE ‘beijing%’ OR 1 = 2

</p>

UPDATE TABLE_NAME SET 1 = 1 , 2 = 2, … [WHERE 条件子句]

</p>

 

</p>

查就算是查询

</p>

SELECT *, 或者用列名 FROM [1 别名1, 2 别名1] [WHERE 条件子句]

</p>

       两个表的查询: 1.id = 2.id 或者 别名1.id = 别名2.id

</p>

select c.roomName from student s, classroom c where s.id = c.student_id

</p>

 

</p>

       1) 把驱动程序加入到 classpath;

</p>

       2)

</p>

       // 加载驱动程序

</p>

       // 方式 a

</p>

       new com.mysql.jdbc.Driver();

</p>

       // 方式 b 动态类加载

</p>

       try {

</p>

              Class.forName("com.mysql.jdbc.Driver");

</p>

       } catch(Exception e) {

</p>

       }

</p>

 

</p>

       // 打开数据库连接

</p>

       try {

</p>

              String url = "jdbc:mysql://localhost:3306/test";

</p>

              String username = "root";

</p>

              String password = "";// 空密码可以写成 "" 或者 null

</p>

              Connection conn = DriverManager.getConnection(url, username, password);

</p>

 

</p>

              // 数据改动用 executeUpdate(String sql)

</p>

              Statement stmt = conn.createStatement();

</p>

              // Statement stm = con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);//获得可更新和可滚动的结果集

</p>

              String sql = "insert into student values(1, ‘student1’)";

</p>

 

</p>

              int rows = stmt.executeUpdate(sql);// 返回改动的数据的行数

</p>

             

</p>

              // 读取数据 executeQuery(String sql)

</p>

              sql = "select * from student";

</p>

             

</p>

              ResultSet rs = stmt.executeQuery(sql);

</p>

 

</p>

              // rs = null;

</p>

 

</p>

              while(rs != null && rs.next()) {

</p>

                     // 取数据可以根据下标或者列名

</p>

                     String studentname = rs.getString(2);// 下标从1开始

</p>

                     int id = rs.getInt("id");// 根据列名获取

</p>

 

</p>

                     byte[] bytes = rs.getBytes("face");// 读取二进制

</p>

              }

</p>

 

</p>

              // 释放资源

</p>

              rs.close();

</p>

              stmt.close();

</p>

              conn.close();

</p>

       } catch(Exception e) {

</p>

       }

</p>

 

</p>

       代码的问题在于如果中间出现异常, 那么连接资源就不能释放, 解决办法是把变量声明放在 try-catch 语句之外; 第二把资源释放给放进 finally 里面.

</p>

 

</p>

              // 打开数据库连接

</p>

       // 声明用到的资源

</p>

       Connection conn = null;

</p>

       Statement stmt = null;

</p>

       ResultSet rs = null;

</p>

       try {

</p>

              String url = "jdbc:oracle:thin:@hostname:1521:tarena";

</p>

              String username = "openlab";

</p>

              String password = "";// 空密码可以写成 "" 或者 null

</p>

              conn = DriverManager.getConnection(url, username, password);

</p>

 

</p>

              // 数据改动用 executeUpdate(String sql)

</p>

              stmt = conn.createStatement();

</p>

              // Statement stm = con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);

</p>

              String sql = "insert into student values(1, ‘student1’)";

</p>

 

</p>

              int rows = stmt.executeUpdate(sql);// 返回改动的数据的行数

</p>

             

</p>

              // 读取数据 executeQuery(String sql)

</p>

              sql = "select * from student";

</p>

             

</p>

              rs = stmt.executeQuery(sql);

</p>

 

</p>

              // rs = null;

</p>

 

</p>

              while(rs != null && rs.next()) {

</p>

                     // 取数据可以根据下标或者列名

</p>

                     String studentname = rs.getString(2);// 下标从1开始

</p>

                     int id = rs.getInt("id");// 根据列名获取

</p>

 

</p>

                     byte[] bytes = rs.getBytes("face");// 读取二进制

</p>

              }

</p>

 

</p>

 

</p>

       } catch(SQLException e) {

</p>

              throw new 数据处理失败异常();

</p>

              // throw SQLExeption

</p>

       } finally {

</p>

                     // 释放资源

</p>

              try {

</p>

                     rs.close();

</p>

              } catch(Exeption ex) {

</p>

                    

</p>

              }

</p>

 

</p>

              try {

</p>

                     stmt.close();

</p>

              } catch(Exeption ex) {

</p>

                    

</p>

              }

</p>

 

</p>

              try {

</p>

                     conn.close();

</p>

              } catch(Exeption ex) {

</p>

                    

</p>

              }

</p>

             

</p>

              // 简化成

</p>

              // close(rs, stmt, conn);

</p>

             

</p>

       }

</p>

 

</p>

       close(ResultSet rs, Statement stmt, Connection conn) {

</p>

                     // 释放资源

</p>

              try {

</p>

                     rs.close();

</p>

              } catch(Exeption ex) {

</p>

                    

</p>

              }

</p>

 

</p>

              try {

</p>

                     stmt.close();

</p>

              } catch(Exeption ex) {

</p>

                    

</p>

              }

</p>

 

</p>

              try {

</p>

                     conn.close();

</p>

              } catch(Exeption ex) {

</p>

                    

</p>

              }

</p>

       }

</p>

3. 获取结果集中有多少字段及其类型,可以用rs.getMetaData()来获取 ResultSetMetaData对象,很多框架就是用这种办法再加上反射来进行自动的属性填充操作的,例如Hibernate

</p>

    ResultSetMetaData可用于获取关于 ResultSet 对象中列的类型和属性信息的对象。以下代码片段创建 ResultSet 对象 rs,创建 ResultSetMetaData 对象 rsmd,并使用 rsmd 查找 rs 有多少列,以及 rs 中的第一列是否可以在 WHERE 子句中使用。

</p>

 

</p>

 

</p>

     ResultSet rs = stmt.executeQuery("SELECT a, b, c FROM TABLE2");

</p>

     ResultSetMetaData rsmd = rs.getMetaData();

</p>

     int numberOfColumns = rsmd.getColumnCount();

</p>

     boolean b = rsmd.isSearchable(1);

</p>

 

</p>

4. PreparedStatement 的用法

</p>

       PreparedStatement 继承自 Statement, 所有的 Statement 能进行的操作这里都可以用.

</p>

       1) 执行速度优化(预编译)

</p>

       2) 简化 SQL 编写

</p>

String sql = "select * from user where username = ?";

</p>

       3) 增加安全性

</p>

              SQL 注入攻击

</p>

              String sql = "select * from user where username = ‘" + username + "’";

</p>

              username 输入 1′ = ‘1’ or username = ‘张三

</p>

select * from user where username = ‘1’ = ‘1’ or username = ‘张三

</p>

 

</p>

避免方法: a) 过滤用户输入的特殊字符 ” = ‘

</p>

username.replaceAll("’", "”");

</p>

       b) PreparedStatement.setString(下标, username) 自动转换输入的字符串为合法的 SQL 的格式

</p>

用法:

</p>

// 1. 打开

</p>

       PreparedStatement pstmt = conn.createPreparedStatement("select * from user where username = ? and regdate = ?");

</p>

// 2. 设置要处理的数据

</p>

       pstmt.setString(1, "张三");

</p>

       java.util.Date now = new java.util.Date();

</p>

       pstmt.setDatetime(2, new java.sql.Date(now.getTime()) );// 设置日期

</p>

// 3. 执行查询或者更新

</p>

       ResultSet rs = pstmt.executeQuery();//

</p>

       rs = pstmt.executeQuery("select * ..:");//

</p>

       int rows = pstmt.executeUpdate();// 更新

</p>

 

</p>

3. CallableStatement  用来调用存储过程(了解)

</p>

JDBC 中调用已储存过程的语法如下所示。注意,方括号表示其间的内容是可选项;方括号本身并不是语法的组成部份。

</p>

{call 过程名[(?, ?, …)]}

</p>

 

</p>

返回结果参数的过程的语法为:

</p>

 

</p>

{? = call 过程名[(?, ?, …)]}

</p>

 

</p>

不带参数的已储存过程的语法类似:

</p>

 

</p>

{call 过程名}

</p>

 

</p>

示例代码:

</p>

 

</p>

 String procedure="{call Operator_login(?,?,?)}";

</p>

    //注册存储过程

</p>

    CallableStatement callStmt=conn.prepareCall(procedure);

</p>

    //注册存储过程输出参数的类型

</p>

    callStmt.registerOutParameter(3,java.sql.Types.INTEGER);

</p>

    //提供输入参数的值

</p>

    callStmt.setString(1,this.operatorID);

</p>

    callStmt.setString(2,this.password);

</p>

    //执行存储过程

</p>

    callStmt.execute();

</p>

    //返回输出参数

</p>

    login_state=callStmt.getInt(3);

</p>

 

</p>

 

</p>

CallableStatement cs = conn.prepareCall("{call ec_get_cust_terms(?)}");

</p>

cs.setInt(1, custNo);

</p>

rs = cs.executeQuery();

转载请注明:WebLogic Android 博客 » MyEclipse 6 Java 开发中文教程独家连载 – 第五章 开发JDBC应用