1、通过JDBC访问数据库
JDBC是Java DataBase Connectivity的缩写,它提供了执行SQL语句、访问关系数据库的方法。JDBC是有Java编程语言编写的类及接口组成,同时它也为程序开发人员提供了一组用于实现对数据库访问的JDBCAPI,并支持SQL语言。利用JDBC可以将Java代码连接到Oracle、DB2、SQLServer、MySQL等数据库,从而实现对数据库中的数据进行操作的目的。
JDBC类似于Microsoft的ODBC,但JDBC是Java操作数据库的方法,而ODBC是使用C语言接口。通过使用JDBC,程序员可以很方便地将SQL语句传给任何一种数据库。也就是说程序员不需要写多个程序分别对应不同的数据库。用JDBC编写的程序能自动将SQL语句传给相应的数据库管理系统(DBMS)。
对于数据库这里就不做详细的说明了,这里只说一下数据库语言及其操作吧。SQL是Structured Query Language的缩写,它是一种介于关系代数与关系盐酸之间的机构化查询语言,是许多关系数据库定义及查询数据的语言。Java是一门过程化语言,而SQL是一门高度非过程化语言。SQL的精华在于不管多么复杂的操作,它只有一句。它只要告诉系统做什么,系统就会照做,而不是告诉系统怎么做。数据库的操作概括成4个字就是赠、删、改、查。
1)、建立表
SQL语言使用CREATE TABLE语句来定义基本表,其一般格式为:
CREATE TABLE 表名(
字段1 字段类型 约束条件,
字段2 字段类型 约束条件,......
);
看一个学生表的建立,在表中定义了学号、姓名、年龄和性别几项列明:
CREATE TABLE student(
ID varchar(10)not null,
Name varchar(10),
Age varchar(3),
Sex varchar(1)
);
系统执行CREATE语句后,就会在数据库中建立一个新表。关于数据类型,每种数据库的数据类型是有一些不一样的,用到哪种数据库以后只要看一眼就知道了。
2)、插入数据
表建立好后,即可插入数据。插入数据的基本格式为:
INSERT INTO 表名(字段1,字段2......)
VALUES(值1,值2....);
如果向每个字段名下都插入数据,其中的字段名就不用写的,将变为:
INSERT INTO 表名
VALUES(值1,值2......);
应用前面建立的学生表,举一个插入数据的例子:
INSERT INTO student(ID ,Name , Sex)
VALUES(‘41009160’ , ‘小武灵灵’ , ‘男’);
上面是一个不知道年龄的学生的信息,再来看一个完整的学生的信息:
INSERT INTO student
VALUES(‘41009161’ , ‘小龙’ , ‘23’,‘男’);
在插入数据时,经常会遇到数据插入不进去的问题,这时一定要检查数据是否违反了建立表时规定的约束条件。如在建立表时规定学号不能为空,而在插入数据时没有插入学号,这时就会报错。
3)、查看数据
插入数据后,经常要看数据是否真的加入数据库,这时就要用到查看数据命令。查询语句为:
SELECT[ALL|DEITINCT] 字段名[字段名列表达式]
FROM 表名
[WHERE 条件表达式]
[GROUP BY 字段名1[HAVING 条件表达式]]
[ORDER BY 字段名2[ASC|DESC]]
查看数据的意思就是根据给出的约束条件在数据库中提取需要的数据。其中[GROUP BY 字段名1[HAVING 条件表达式]]指的是对字段1按条件表达式对数据分组。 [ORDER BY 字段名2 [ASC|DESC]]指的是对字段名3进行升序或降序排序。
如果查询所有数据,还有一个简单的格式:
SELECT * FROM 表名;
如对以前建立的表查询所有数据:
SELECT * FROM student;
有时只关心学号和姓名,即可使用指定字段名的查询语句,如:
SELECT ID , Name FROM student;
还有人想看谁比他的年龄大(假设他的年龄是20),数据库也提供了相应查询方法,这时就要用[WHERE 条件表达式],其查询语句为:
SELECT Name , Age FROMstudent WHERE Age > 20;
还是有人可能想直接看别人的年龄比他小多少,这时就要用到[字段名列表达式],其查询语句如下:
SELECT Name , Age-20 FROM studentWHERE Age > 20;
还有一种很特殊的情况,如果查询年龄为20且学号大于41009100的数据,这时就要用到条件运算符。WHERE子句的全部条件运算符如下表所示:
条件运算符 | 运算符 |
比较运算符 | < , <= , = , != , > , >= , <> |
范围运算符 | BETWEEN AND , NOT BETWEEN AND |
集合运算符 | IN , NOT IN |
字符匹配运算符 | LIKE , NOT LIKE |
空值判断符 | IS NULL , IS NOT NULL |
逻辑运算符 | AND OR NOT |
应用条件运算符后,其查询语句为:
SELECT Name , Age , ID FROMstudent WHERE Age = 20 AND ID>41009160;
3、JDBC编程步骤
JDBC编程的基本步骤是设置数据源、加载JDBC驱动器程序、指定数据库、打开数据库连接、提交查询、处理查询结果等。在讲解编程步骤钱,先看一段代码,一边学习代码,一遍学习变成步骤。
- public class test {
- public static void main(String[] args){
- try {
- //加载驱动程序
- Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
- //打开数据库连接,aaa为数据源名称
- Connection con =DriverManager.getConnection("jdbc:odbc:aaa" , "" ,"");
- //提交查询
- Statement st =con.createStatement();
- //向数据库中插入一条记录
- st.executeUpdate("insert intostudent values('41009160' , '小武灵灵' , '22' , '男'");
- //取得查询结果
- ResultSet rs =st.executeQuery("select * from student");
- //查看结果
- System.out.println("ID/Name/Age/Sex");
- while (rs.next()) {
- String ID =rs.getString("ID");
- String Name =rs.getString("Name");
- String Age =rs.getString("Age");
- String Sex =rs.getString("Sex");
- System.out.println(ID +"/" + Name + "/" + Age + "/" + Sex);
- }
- rs.close();//关闭RsultSet对象
- st.close();//关闭Statement对象
- con.close();//关闭Connection对象
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
public class test { public static void main(String[] args){ try { //加载驱动程序 Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); //打开数据库连接,aaa为数据源名称 Connection con =DriverManager.getConnection("jdbc:odbc:aaa" , "" ,""); //提交查询 Statement st =con.createStatement(); //向数据库中插入一条记录 st.executeUpdate("insert intostudent values('41009160' , '小武灵灵' , '22' , '男'"); //取得查询结果 ResultSet rs =st.executeQuery("select * from student"); //查看结果 System.out.println("ID/Name/Age/Sex"); while (rs.next()) { String ID =rs.getString("ID"); String Name =rs.getString("Name"); String Age =rs.getString("Age"); String Sex =rs.getString("Sex"); System.out.println(ID +"/" + Name + "/" + Age + "/" + Sex); } rs.close();//关闭RsultSet对象 st.close();//关闭Statement对象 con.close();//关闭Connection对象 } catch (Exception e) { e.printStackTrace(); } } }
上面的程序中进行了数据库的连接,使用了数据源,并将数据库建立好,最后将它的数据库名称输出。
1)、创建数据源
JDBC编程时,必须先建立ODBC数据源。操作系统和使用的数据库不同可能会有所不同,但是具体步骤是不会变的。
(1)、Windows桌面 → 开始→ 控制面板 → 管理工具 → 数据源(ODBC),弹出ODBC数据管理器对话框;
(2)、添加 → 创建新数据源对话框 → 根据使用的数据库进行选择,这里以Access为例 → 选择Access选项 → 完成;
(3)、弹出“OBDC MicrosoftAccess安装”对话框,在“数据源名”文本框中根据自己的需要命名,在此输入aaa;
(4)、单击“确定“按钮,可以看到多出一个名为aaa的数据源。
2)、加载驱动程序
可以通过调用方法Class.forName来加载驱动程序。加载驱动程序只需要一行代码就能完成,以JDBC-ODBC桥接、Oracle连接和MySQL连接为例,查看它们的驱动程序:
>JDBC-ODBC桥接:sun.jdbc.odbc.JdbcOdbcDriver;
>Oracle连接:oracle.jdbc.driver.OracleDriver;
>MySQL连接:org.gjt.mm.mysql.Driver.
当使用Oracle和MySQL连接相应的数据源时,要在classpath中加入相应的配置。
3)、指定数据库
JDBC URL提供了一种标志特定的驱动程序,它可以使相应的驱动程序能识别该数据库并与之建立连接。由于JDBC URL要与各种不同的驱动程序一起使用,因此对它的约定也是非常少的。第一,它允许不同的驱动程序使用不同的方案来命名数据库。第二,JDBC URL允许驱动程序编程将一切所需的信息编入其中。这样就可以让要与给定数据库对话的applet打开数据库连接,而不用要求用户去做任何系统管理工作。第三,JDBC URL应允许某种程序的间接性。也就是说JDBC URL可指向逻辑主机或数据库名,而这种逻辑主机或数据库名将由网络命名系统动态地转换为实际的名称。
JDBC URL的标准语法如下所示,它有3部分组成,各部分之间用冒号分隔:
Jdbc:<子协议>:<子名称>
在JDBC编程中,JDBC URL中的协议总是JDBC,JDBC是永远不变的。<子协议>指的是驱动程序名或数据库连接机制的名称。<子名称>是一种标识数据库的方法。这里还是以JDBC-ODBC桥接、Oracle连接和MySQL连接为例,它们分别是:
>jdbc:odbc:数据源名
>jdbc:oracle:thin:@数据库服务器主机名:1521:SID
>jdbc:mysql:://localhost/<数据库名称>
4)、打开数据库连接
Connection对象代表与数据库的连接。连接过程包括所执行的SQL语句和在该连接上所返回的结果。一个应用程序可与单个数据库有一个或多个连接,或者可与许多数据库有连接。打开数据库连接就是用适当的驱动程序与数据管理系统建立一个连接。DriverManager类时JDBC的管理层,作用于用户和驱动程序之间。它跟踪可用的驱动程序,并在数据库和相应驱动程序之间建立连接。加载驱动程序并在DriverManager类中注册后,即可与数据库建立连接。当调用DriverManager.getConnection方法发出连接请求时,DriverManager将验证每个驱动程序,查看它是否可以建立连接。打开用户名为user,密码未password的数据库连接的基本代码为:
Connection>
这段代码看起来很简单,其实包括怎样提供URL这个难点,所以有时会把这段代码分为两段:
String>
Connection>
DriverManager类包含一系列Driver类,它们已通过调用方法DriverManager.registerDriver对自己进行了注册。加载Driver类并在DriverManager类中注册后,它们即可用来与数据库建立连接。当调用DriverManager.getConnection方法发出连接请求时,DriverManager将检查每个驱动程序,查看它是否可以建立连接。
5)、提交查询
与数据源建立连接后,即可向它所关联的数据库发送SQL语句。JDBC对可被发送的SQL语句类型不加任何限制。
Statement对象用于将SQL语句发送到数据库中。有3中Statement对象,它们都作为在给定连接上执行SQL语句的包容器:Statement、PreparedStatement(它从Statement继承而来)和CallableStatement(它从PreparedStatement继承而来)。它们都专门用于发送特定类型的SQL语句:Statement对象用于执行不带参数的简单SQL语句;PreparedStatement对象用于执行带或不带IN参数的预编译SQL语句;CallebelStatement对象用于执行对数据库已存储过程的调用。
提交查询应用Statement对象的代码如下。Statement是Connection接口的一个常用对象,由方法creatStatement创建。Statement独享用于发送SQL语句。提交查询的代码为:
Statement>
6)、取得查询结果
编写了SQL对象后,即可应用它调用相应的方法实现对数据库的查询和修改。并将查询结果放在一个ResultSet类声明的对象中,SQL语句对数据库的查询操作将返回一个ResultSet对象。其代码为:
ResultSet>
查询结果作为一个行的集合,也可以说是一个表存在一个ResultSet对象中。ResultSet包含符合SQL语句中条件的所有行,ResultSet.net()方法用于移动到ResultSet中的下一行,使下一行称为当前行,并返回一个boolean值表示该行是否为最后一行。ResultSet维护指向其当前数据行的光标。光标最初在第一行之前,所以第一次调用next()将把光标置于第一行上。每调用一次next()方法,光标向下移动一行。当光标移至最后一行时next()方法返回false。
ResultSet包含符合SQL语句中条件的所有行,并且它通过一套get()方法提供了队这些行中数据的访问方法。get()提供了获取当前行中某列值的途径。在每行中可按从左到右的次序获取列值。列名或列号可用于标识要从中获取数据的列。get()方法很多,如下表所示:
get方法 | 返回类型 |
getBoolean | Boolean |
getByte | Byte |
getByes | Byte[] |
getDate | Java.sql.Date |
getDouble | Double |
getFloat | Float |
getInt | Int |
getLong | Long |
getObject | Object |
getShort | Short |
getString | Java.lang.String |
getTime | Java.sql.Time |
getTimestamp | Java.sql.Timestamp |
4、使用PreparedStatement进行预编译操作
当一个Statement对象被创建时,它提供了创建SQL查询、执行该查询和检索返回结果的作用。PreparedStatement接口继承自Statement,与Statement相比,PreparedStatement增加了在执行SQL调用之前将输入参数绑定到SQL调用中的能共。它用于执行带或不带输入参数的预编译SQL语句。因为PreparedStatement对象已编译过,所以执行速度要快于Statement对喜爱那个。因此当需要多次调用一条SQL语句时,可以考虑使用PreparedStatement接口。
PreparedStatement接口继承了Statement 所有方法,同时增加了一些方法,还更改了3个很重要的方法,它们是:
>setXXX();
>executeQuery();
>executeUpdate();
其中,setXXX()方法中的XXX指的是该参数对应了类型。例如参数是String类型,则方法为SetString()。SetXXX()方法有两个参数,第一个参数是指要设置参数的位置,第二个参数是指要设置的具体指。例如ps.setInt(1 , 2000);
如果基本数据库和驱动程序在语句提交之后扔保持这些语句的打开状态,则同一个PreparedStatement可执行多次。如果这一点不成立,那么试图通过使用PreparedStatement对象代替Statement对象来提高性能是没有意义的。
下面是使用PreparedStatement的一段代码:
- public class test {
- public static void main(String[] args){
- try {
- //加载驱动程序
- Class.forName("jdbc.odbc.JdbcOdbcDriver");
- //打开数据库连接,aaa为数据源名称
- Connection con =DriverManager.getConnection("jdbc:odbc:aaa", "","");
- //提交查询
- PreparedStatement ps =con.prepareStatement("select * from student where Age>?");
- ps.setString(1, "23");
- ResultSet rs = ps.executeQuery();
- //查看结果
- System.out.println("ID/Name/Age/Sex");
- while (rs.next()) {
- String ID = rs.getString(1);
- String Name = rs.getString(2);
- String Age = rs.getString(3);
- String Sex = rs.getString(4);
- System.out.println(ID +"/" + Name + "/" + Age + "/" + Sex);
- }
- rs.close();
- ps.close();
- con.close();
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
public class test { public static void main(String[] args){ try { //加载驱动程序 Class.forName("jdbc.odbc.JdbcOdbcDriver"); //打开数据库连接,aaa为数据源名称 Connection con =DriverManager.getConnection("jdbc:odbc:aaa", "",""); //提交查询 PreparedStatement ps =con.prepareStatement("select * from student where Age>?"); ps.setString(1, "23"); ResultSet rs = ps.executeQuery(); //查看结果 System.out.println("ID/Name/Age/Sex"); while (rs.next()) { String ID = rs.getString(1); String Name = rs.getString(2); String Age = rs.getString(3); String Sex = rs.getString(4); System.out.println(ID +"/" + Name + "/" + Age + "/" + Sex); } rs.close(); ps.close(); con.close(); } catch (Exception e) { e.printStackTrace(); } } }
5、元数据
元数据用于描述数据库或一部分数据库的数据,它是关于数据的数据。元数据被用于动态地调节数据库的内容和结果集。它分为两类:关于数据库的和关于结果集的。
1)、数据库的DatabaseMetaData元数据
DatabaseMetaData对象能够提供关于特定数据库的结果的信息。DatabaseMetaData对象通过数据库的连接获得,方法如下:
DatabaseMetaData>
DatabaseMetaData对象提供的方法很多,这些方法可以通过对返回结果的类型分为4类,它们分别是返回字符串、整数、布尔值和ResultSet的方法。例如下面的方法返回一个ResultSet:
getTables(String catalog ,String checmaPattern , String tableNamePattern , String types[]);
2)结果集的ResultSetMetaData元数据
ResultSetMetaData是关于结果集的元数据。它可以通过getMetaData()方法从ResultSet获得元数据:
ResultSetMetaData>
ResultSetMetaData的方法也很多,通过getColumnCount()方法来进行举例说明,它被用于返回ResultSet对象中的列数:
- public class test {
- public static void main(String[] args){
- try {
- Class.forName("jdbc.odbc.JdbcOdbcDriver");
- Connection con =DriverManager.getConnection("jdbc:odbc:aaa" , "" ,"");
- //定义DatabaseMetaData对象
- DatabaseMetaData dmd =con.getMetaData();
- //检索可在给定类别中使用的表的描述
- ResultSet rs = dmd.getTables(null,null, null, new String[]{"table"});
- //定义ResultSetMetaData对象
- ResultSetMetaData rsmd =rs.getMetaData();
- //返回次ResultSet对象中的列数
- int cols = rsmd.getColumnCount();
- for (int i = 0; i < cols; i++) {
- //获取指定咧的名称
- System.out.print(rsmd.getColumnName(i) + "\t");
- }
- System.out.println("");
- while (rs.next()) {
- for (int i = 0; i < cols;i++) {
- System.out.println(rs.getString(i) + "\t");
- }
- System.out.println("");
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
public class test { public static void main(String[] args){ try { Class.forName("jdbc.odbc.JdbcOdbcDriver"); Connection con =DriverManager.getConnection("jdbc:odbc:aaa" , "" ,""); //定义DatabaseMetaData对象 DatabaseMetaData dmd =con.getMetaData(); //检索可在给定类别中使用的表的描述 ResultSet rs = dmd.getTables(null,null, null, new String[]{"table"}); //定义ResultSetMetaData对象 ResultSetMetaData rsmd =rs.getMetaData(); //返回次ResultSet对象中的列数 int cols = rsmd.getColumnCount(); for (int i = 0; i < cols; i++) { //获取指定咧的名称 System.out.print(rsmd.getColumnName(i) + "\t"); } System.out.println(""); while (rs.next()) { for (int i = 0; i < cols;i++) { System.out.println(rs.getString(i) + "\t"); } System.out.println(""); } } catch (Exception e) { e.printStackTrace(); } } }
6、结果集处理
在前面的实例中,都是假设结果集是只读的。对结果集的处理可分为可滚动的和可更新的。可滚动是指显示的结果集的游标所在行既可以向前移又可以向后移动,也可以移动到指定的特定行。可更新是指允许客户程序对结果集中的数据进行修改。
1)、可滚动结果集
JDBC驱动程序是否支持可滚动的结果集是由DatabaseMetaData对象决定的。DatabaseMetaData接口中定义了一个supportsResultSetType(inttype)方法,它的返回结果为boolean型,其作用是用于检查此数据库是否支持给定的结果集类型。在实际的程序开发中,并不用DatabaseMetaData进行开发,而是用Statement直接指定,如下面的程序代码:
Statement>
其中type有3种类型
>TYPE_FORWARD_ONLY:结果集游标只能向前移动
>TYPE_SCROLL_INSENSITIVE:可滚动,对数据变化不敏感
>TYPE_SCROLL_SENSITIVE:可滚动,对数据变化敏感
对结果集进行操作就是对结果集的游标进行操作,其中定义了很多种方法:
>absolute(int row):把游标移至给定的行
>afterLast():把游标移至最后一行后面
>beforeFirst():把游标移至第一行前面
>isAfterLast():判断游标是否在最后一行后面
>isBeforeFirst():判断游标是否在第一行前面
>first():把游标移动到第一行
>last():把游标移动到最后一行
>isFirst():判断游标是否在第一行
>isLast():判断游标是否在最后一行
>previous():把游标移动到所在行的前一行
>next():把游标移动到所在行的后一行
>relative(intt):把游标相对移动几行
>getRow():获取当前行数
下面是对某些方法的使用:
- public class test {
- public static void main(String[] args){
- try {
- Class.forName("jdbc.odbc.JdbcOdbcDriver");
- Connection con =DriverManager.getConnection("jdbc:odbc:aaa", "","");
- Statement st =con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY);
- ResultSet rs =st.executeQuery("select * from student");
- //查看结果
- rs.absolute(2);
- System.out.println(rs.getString(1));
- rs.previous();
- System.out.println(rs.getString(1));
- rs.first();
- System.out.println(rs.getString(1));
- rs.relative(3);
- System.out.println(rs.getString(1));
- System.out.println(rs.getRow() +"");
- rs.close();
- st.close();
- con.close();
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
public class test { public static void main(String[] args){ try { Class.forName("jdbc.odbc.JdbcOdbcDriver"); Connection con =DriverManager.getConnection("jdbc:odbc:aaa", "",""); Statement st =con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY); ResultSet rs =st.executeQuery("select * from student"); //查看结果 rs.absolute(2); System.out.println(rs.getString(1)); rs.previous(); System.out.println(rs.getString(1)); rs.first(); System.out.println(rs.getString(1)); rs.relative(3); System.out.println(rs.getString(1)); System.out.println(rs.getRow() +""); rs.close(); st.close(); con.close(); } catch (Exception e) { e.printStackTrace(); } } }
2)、可更新结果集
在ResultSet类中是用getConcurrency方法来确定结果集是否为可更新的。ResultSet接口中有很多的更新方法,列举如下:
>updateBoolean():用布尔类型的值更新指定的列
>updateByte():用字节值更新指定的列
>updateBytes():用字节数组值更新指定的列
>updateCharacterStream():用字符流的值更新指定的列
>updateDate():用date值更新指定的列
>updateDouble():用double类型的值更新指定的列
>updateFloat():用float类型的值更新指定的列
>updateInt():用int类型的值更新指定的列
>updateLong():用long类型的值更新指定的列
>updateNull():给可为null的列指定null值
>updateObject():用object值更新指定的列
>updateRow():用resultset对象的新内容更新
>updateShort():用short类型的值更新指定的列
>updateString():用字符串类型的值更新指定的列
>updateTime():用time值更新指定的列
可更新结果集的程序和可滚动的结果集程序很相似,但是可更新的结果集圆没有可滚动结果集重要,这里不再给出可更新结果集的代码。