向大家介绍的是Java中的JDBC技术,这一技术对每个Java程序员来说都是非常关键的。因此必须很好的掌握内容。下面来看一下学习任务。 1.1 知识掌握任务 学习应掌握以下知识点: 1.了解什么是数据库。 2.掌握数据库的特点及分类。 3.掌握JDBC的含义以及为什么要在项目中加载数据库驱动。 4.掌握数据库中常用的类与接口。 5.掌握各种数据库操作。 6.学习使用预处理语句。 1.2 实例开发任务 学习内容后,需要根据所学知识开发应用程序,真正达到学以致用的效果。下面为读者制定了实例开发任务。 1、实现在窗体中显示查询结果 例如将教师表tb_teacher中,编号为1的教师信息显示到窗体中,如图1所示。
图1 将查询结果显示在窗体中
2、修改用户工资信息
例如有一张员工信息表tb_emp,该表保存了员工信息与属性。本实例要求读者将Java部门的员工工资增加500,来鼓励Java部门员工的突出贡献。如图2所示的数据库中数据变化效果。
图2 修改员工表中数据
了解数据库基础知识: 数据库对软件开发人员来说,至关重要,可以说没有一个软件是可以离开数据库而独立存在的,因此内容是程序员必须很好掌握的内容,下面先向大家介绍相关的数据库基础知识。 1.1 生活中的数据库 数据库顾名思义就是存储了大量的数据,数据库在生活中也是到处可见,例如电话薄就是存储了电话信息的数据库,在影视剧中经常会看到拿着账本的先生,这个账本就是一个典型的数据库。但早期的这些以手写的形式形成的数据库,有一个严重的弊病,就是查找数据不方便,如果对数据进行了修改的不方便。因此在信息高速发展的时代,出现了很多专门用于存储数据的软件,也就是所说的数据库。 如今数据库发展到现在已经相当成熟了。从原来的Sybase数据库,发展到今天的SQL Server、MySQL、Oracle数据库等高级数据库。 1.2 了解数据库的特点及分类 数据库是依照数据模型组织起来,并存放二级存储器中的数据集合。数据库是一种存储结构,允许使用各种格式输入、处理和检索数据。数据库具有以下特点: 1)实现数据共享。数据共享包含所有用户可同时存取数据库中的数据,也包括用户可以用各种方式通过接口使用数据库,并提供数据共享。 2)减少数据的冗余度。同文件系统相比,由于数据库实现了数据共享,从而避免了用户各自建立应用文件。减少了大量重复数据,减少了数据冗余,维护了数据的一致性。 3)数据的独立性。数据的独立性包括数据库中数据库的逻辑结构和应用程序相互独立,也包括数据物理结构的变化不影响数据的逻辑结构。 4)数据实现集中控制。文件管理方式中,数据处于一种分散的状态,不同的用户或同一用户在不同处理中其文件之间毫无关系。利用数据库可对数据进行集中控制和管理,并通过数据模型表示各种数据的组织以及数据间的联系。 5)数据一致性和可维护性,以确保数据的安全性和可靠性。主要包括:①安全性控制:以防止数据丢失、错误更新和越权使用;②完整性控制:保证数据的正确性、有效性和相容性;③并发控制:使在同一时间周期内,允许对数据实现多路存取,又能防止用户之间的不正常交互作用;④故障的发现和恢复。 数据库系统一般基于某种数据模型,可以分为层次性、网状线、面向对象型与关系型数据库: 6)层次型数据库:层次模型数据库类似于树结构,是一组通过链接而相互联系在一起的记录。层次模型的特点是记录之间的联系是通过指针实现的。由于层次模型层次顺序严格而且复杂。这样导致对数据的各项操作都很困难。层次模型数据库如图1所示。
图1 层次数据库 图2 网状数据库 7)网状型数据库:网络模型是使用网络结构表示实体类型、实体间联系的数据模型。网络模型容易实现多对多的联系。但需要编写应用程序时,程序员必须熟悉数据库的逻辑结构。如图2所示。 8)对象模型数据库:建立在面前对象模型基础上。 9)关系数据库:关系数据库是目前最流行的数据库,是基于关系模型建立的数据库,关系模型是由一系列表格组成。后面会详细的讲解它。
Java操作数据库必须学习JDBC技术
JDBC是一种有关数据库连接的工具,通过JDBC技术程序员可以使用Java开发基于数据库的应用程序,在遵循Java语言规则的同时,可以使用标准的SQL语句访问任何数据库,下面先带领大家认识一下JDBC技术。 1.1 新的起点——JDBC技术 JDBC是JavaDataBase Connectivity的简写,主要是将Java程序与数据库建立连接,并通过Java程序操作数据,在JDBC技术问世之前,各家数据库厂商执行各自的一套API,使得开发人员访问数据库非常困难,特别是在更换数据库时,需要修改大量代码,十分不方便。JDBC的发布获得了巨大的成功,很快就成为了Java访问数据库的标准,并且获得了几乎所有数据库厂商的支持。 JDBC是一种底层API,在访问数据库时需要在业务逻辑中直接嵌入SQL语句,由于SQL语句是面向关系的,依赖于关系模型,所以JDBC传承了简单直接的优点,特别是对于小型应用程序十分方便。需要注意的是,JDBC不能直接访问数据库,必须依赖于数据库厂商提供的JDBC驱动程序,JDBC完成了以下三步工作。 (1)同数据库建立连接。 (2)向数据库发送SQL语句。 (3)处理从数据库返回的结果。 1.2 为什么要在项目中添加数据库驱动 要使用JDBC技术操作数据库,首先要向项目中添加数据库驱动,怎么来理解数据库驱动呢?就如有的机器安装摄像头时,需要安装摄像头的驱动;有的机器安装U盘就要装相应的U盘驱动,这样你的机器才能识别相应的设备。数据库的驱动类似与摄像头的驱动或者U盘的驱动,当你的机器上安装了相应的数据库后,需要安装相应的数据库驱动后机器才能识别这种数据库(如MySQL、SQLServer)。 Sun公司提供了JDBC技术,用于与数据库建立联系,但需要注意的是只是提供了接口,由数据库提供商实现这些接口,就是所谓的数据库驱动。由于不同的数据库厂商实现JDBC接口不同,因此就产生了不同的数据库驱动包。数据库驱动包里包含了一些类,他们负责与数据库建立连接,把一些SQL传到数据库里边去。例如Java程序实现与SQL Server2000数据库建立连接,需要在程序中加载驱动包“msbase.jar、mssqlserver.jar、msutil.jar”或“jtds.jar”,与MySQL数据库建立连接需要在程序加载驱动包“mysql-connectot-java.jar”等。
认识JDBC中不可缺少的类与接口 1.1 管理数据库驱动类DriverManager DriverManager类负责管理JDBC驱动程序的基本服务,是JDBC的管理层,作用于用户和驱动程序之间,负责跟踪可用的驱动程序,并在数据库和驱动程序之间建立连接;另外,DriverManager类也处理诸如驱动程序登录时间限制及登录和跟踪消息的显示等工作。成功加载数据库驱动并在DriverManager类中注册后,DriverManager类即可用来建立数据库连接。DriverManager类的常用方法如表1所示。 表1DriverManager类的常用方法
方法 |
功能描述 |
getConnection(String url , String user , String password) |
指定3个入口参数,依次是连接数据库的URL、用户名、密码,来获取与数据库的连接 |
setLoginTimeout() |
获取驱动程序试图登录到某一数据库时可以等待的最长时间,以秒为单位。 |
println(String message) |
将一条消息打印到当前JDBC日志流中。 |
1.2 数据库连接接口Connection Connection接口代表与特定数据库的连接,在连接的上下文中可以执行SQL语句并返回结果,还可以通过getMetaData()方法获得由数据库提供的相关信息,例如数据表、存储过程和连接功能等信息。Connection实例就像在应用程序与数据库之间开通了一条渠道,如图2所示。
图2 Conntction实例
Connection接口提供的常用方法如表2所示。 表2 Connection接口提供的常用方法
方 法 名 称 |
功 能 描 述 |
createStatement() |
创建并返回一个Statement实例,通常在执行无参的SQL语句时创建该实例 |
prepareStatement() |
创建并返回一个PreparedStatement实例,通常在执行包含参数的SQL语句时创建该实例,并对SQL语句进行了预编译处理 |
prepareCall() |
创建并返回一个CallableStatement实例,通常在调用数据库存储过程时创建该实例 |
setAutoCommit() |
设置当前Connection实例的自动提交模式。默认为true,即自动将更改同步到数据库中;如果设为false,需要通过执行commit()或rollback()方法手动将更改同步到数据库中 |
getAutoCommit() |
查看当前的Connection实例是否处于自动提交模式,如果是则返回true,否则返回false |
setSavepoint() |
在当前事务中创建并返回一个Savepoint实例,前提条件是当前的Connection实例不能处于自动提交模式,否则将抛出异常 |
releaseSavepoint() |
从当前事务中移除指定的Savepoint实例 |
setReadOnly() |
设置当前Connection实例的读取模式,默认为非只读模式。不能在事务当中执行该操作,否则将抛出异常。有一个boolean型的入口参数,设为true则表示开启只读模式,设为false则表示关闭只读模式 |
isReadOnly() |
查看当前的Connection实例是否为只读模式,如果是则返回true,否则返回false |
isClosed() |
查看当前的Connection实例是否被关闭,如果被关闭则返回true,否则返回false |
commit() |
将从上一次提交或回滚以来进行的所有更改同步到数据库,并释放Connection实例当前拥有的所有数据库锁定 |
rollback() |
取消当前事务中的所有更改,并释放当前Connection实例拥有的所有数据库锁定。该方法只能在非自动提交模式下使用,如果在自动提交模式下执行该方法,将抛出异常。有一个入口参数为Savepoint实例的重载方法,用来取消Savepoint实例之后的所有更改,并释放对应的数据库琐定 |
close() |
立即释放Connection实例占用的数据库和JDBC资源,即关闭数据库连接 |
1.3 发送SQL语句接口Statement Statement接口用来执行静态的SQL语句,并返回执行结果。例如,对于insert、update和delete语句,调用executeUpdate(Stringsql)方法,而select语句则调用executeQuery(Stringsql)方法,并返回一个永远不能为null的ResultSet实例。 Statement接口提供的常用方法如表3所示。
表3 Statement接口提供的常用方法
方 法 名 称 |
功 能 描 述 |
executeQuery(String sql) |
执行指定的静态SELECT语句,并返回一个永远不能为null的ResultSet实例 |
executeUpdate(String sql) |
执行指定的静态INSERT、UPDATE或DELETE语句,并返回一个int型数值,为同步更新记录的条数 |
clearBatch() |
清除位于Batch中的所有SQL语句。如果驱动程序不支持批量处理将抛出异常 |
addBatch(String sql) |
将指定的SQL命令添加到Batch中。String型入口参数通常为静态的INSERT或UPDATE语句。如果驱动程序不支持批量处理将抛出异常 |
executeBatch() |
执行Batch中的所有SQL语句,如果全部执行成功,则返回由更新计数组成的数组,数组元素的排序与SQL语句的添加顺序对应。数组元素有以下几种情况:①大于或等于零的数:说明SQL语句执行成功,为影响数据库中行数的更新计数;②-2:说明SQL语句执行成功,但未得到受影响的行数③-3:说明SQL语句执行失败,仅当执行失败后继续执行后面的SQL语句时出现。如果驱动程序不支持批量、或者未能成功执行Batch中的SQL语句之一,将抛出异常 |
close() |
立即释放Statement实例占用的数据库和JDBC资源 |
1.4 可执行动态SQL的接口PreparedStatement
PreparedStatement接口继承并扩展了Statement接口,用来执行动态的SQL语句,即包含参数的SQL语句。通过PreparedStatement实例执行的动态SQL语句,将被预编译并保存到PreparedStatement实例中,从而可以反复并且高效地执行该SQL语句。可以通过Connection类的preparedStatement()方法获取PreparedStatement实例PreparedStatement接口的常用方法如表4所示。 表4 PreparedStatement接口提供的常用方法
方 法 名 称 |
功 能 描 述 |
executeQuery() |
执行前面包含参数的动态SELECT语句,并返回一个永远不能为null的ResultSet实例 |
executeUpdate() |
执行前面包含参数的动态INSERT、UPDATE或DELETE语句,并返回一个int型数值,为同步更新记录的条数 |
setInt(int i, int x) |
为指定参数设置int型值,对应参数的SQL类型为INTEGER |
setLong(int i, long x) |
为指定参数设置long型值,对应参数的SQL类型为BIGINT |
setFloat(int i, float x) |
为指定参数设置float型值,对应参数的SQL类型为FLOAT |
setDouble(int i, double x) |
为指定参数设置double型值,对应参数的SQL类型为DOUBLE |
setString(int i, String x) |
为指定参数设置String型值,对应参数的SQL类型为VARCHAR或LONGVARCHAR |
setBoolean(int i, boolean x) |
为指定参数设置boolean型值,对应参数的SQL类型为BIT |
setDate(int i, Date x) |
为指定参数设置java.sql.Date型值,对应参数的SQL类型为DATE |
setObject(int i, Object x) |
用来设置各种类型的参数,JDBC规范定义了从Object类型到SQL类型的标准映射关系,在向数据库发送时将被转换为相应的SQL类型 |
setNull(int i, int sqlType) |
将指定参数设置为SQL中的NULL。该方法的第二个入口参数用来设置参数的SQL类型,并且必须设置,具体值从java.sql.Types类中定义的静态常量中选择 |
clearParameters() |
清除当前所有参数的值 |
说明:通过setXXX()方法为SQL语句中的参数赋值时,建议利用与参数类型匹配的方法,也可以利用setObject()方法为各种类型的参数赋值。setXXX()方法的第一个入口参数为预赋值参数的索引位置,从1开始;第二个入口参数为参数的值,类型因方法而定。 1.5 查询结果集接口ResultSet ResultSet接口类似于一张数据表,用来暂时存放从数据库查询操作所获得的结果集。ResultSet实例具有指向当前数据行的指针。指针开始的位置在查询结果集第一条记录的前面。要获取查询结果集中的全部数据,可通过next()方法将指针向下移。如果存在下一行返回true,否则返回false,可以依次作为判断依据,使用while循环来迭代ResultSet结果集。 ResultSet接口提供了从当前行检索不同类型列值的getXXX()方法,该方法有两种重载形式,分别提供了通过列的索引编号和列的名称检索列值。除此之外,该接口还提供了updateXXX()方法可通过列的索引编号和列的名称来更新当行行的指定列。ResultSet接口的常用方法如表5所示。
表5 ResultSet接口提供的常用方法
方法 |
功能描述 |
getInt() |
以int形式获取此ResultSet对象的当前行中指定列值。如果列值为NULL,则返回值是0 |
getFloat() |
以float形式获取此ResultSet对象的当前行的指定列值。如列值是NULL,则返回值是0 |
getDate() |
以Data形式获取ResultSet对象的当前行的指定列值。如列值是NULL,则返回值是null |
getBoolean() |
以boolean形式获取ResultSet对象的当前行的指定列值。如列值是NULL,则返回null |
getString() |
以String形式获取ResultSet对象的当前行的指定列值。如列值是NULL,则返回null |
getObject() |
以Object形式获取ResultSet对象的当前行的指定列值。如列值是NULL,则返回null |
first() |
将指针移到当前记录的第一行 |
last() |
将指针移到当前记录的最后一行 |
next() |
将指针向下移一行 |
beforeFirst() |
将指针移到集合的开头(第一行位置) |
afterLast() |
将指针移到集合的尾部(最后一行位置) |
absolute(int index) |
将指针移到ResultSet给定编号的行 |
isFrist() |
判断指针是否位于当前ResultSet集合的第一行。如果是返回true,否则返回false |
isLast() |
判断指针是否位于当前ResultSet集合的最后一行。如果是返回true,否则返回false |
updateInt() |
用int值更新指定列 |
updateFloat() |
用float值更新指定列 |
updateLong() |
用指定的long值更新指定列 |
updateString() |
用指定的String值更新指定列 |
updateObject() |
用Object值更新指定列 |
updateNull() |
将指定的列值修改为NULL |
深入了解数据库操作知识 1.1 操作数据库的执行步骤 如果需要访问数据库,首先要加载数据库驱动程序,不过只需在第一次访问数据库时加载一次,然后每次访问数据库时创建一个Connection实例,获取数据库连接,之后就可以向数据库发送SQL语句,来操作数据。最后在完成数据库操作时,释放与数据库的连接。
1、加载数据库驱动
加载数据库驱动,可以使用Class类的静态方法forName(),具体语法如下:
Class.forName(StringdriverManager)
参数说明: driverManager:要加载的数据库驱动,加载成功,会将加载的驱动类注册给DriverManager。如果加载失败,则会抛出ClassNotFoundException异常。 例如:try {
Class.forName("net.sourceforge.jtds.jdbc.Driver");
} catch(ClassNotFoundException e) {
e.printStackTrace();
}
上面的代码是加载连接SQL Server2000数据库驱动jtds。 技巧:通常将负责加载驱动的代码放在static块中,好处是只有static块所在的类第一次被加载时加载数据库驱动,即第一次访问数据库时,避免重复加载驱动程序,浪费计算机资源。 2、创建数据库连接 在前面的内容中已经向大家介绍到了数据库管理类DriverManager,该类负责建立与管理数据库连接。通过DriverManager类的静态方法getConnection(String url, String user, String password)可以建立数据库连接。 具体语法如下: Connection conn = DriverManager.getConnection(Stringurl,String user,String passWord); 参数说明: url:指定连接数据库的url。 user:指定连接数据库的用户。 passWord:指定连接数据库的密码。 例001 创建数据库连接 在项目中创建GetConn类,该类在静态块中实现加载数据库驱动,并创建getConn()方法,该方法返回值为数据库连接对象Connection。
public class GetConn {
Connection conn = null;
static {
try {
Class.forName("net.sourceforge.jtds.jdbc.Driver"); // 加载数据库驱动
System.out.println("数据库驱动加载成功!");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public Connection getConn() {
String url = "jdbc:jtds:sqlserver://localhost:1433;
DatabaseName=db_database15"; // 连接数据库URL
String userName = "sa"; // 连接数据库的用户名
String passWord = ""; // 连接数据库密码
try {
conn = DriverManager.getConnection(url, userName,
passWord); //获取数据库连接
if (conn != null) {
System.out.println("数据库连接成功!");
}
} catch (SQLException e) {
e.printStackTrace();
}
return conn; //返回Connection对象
}
public static void main(String[] args) {
GetConn getConn = new GetConn();//创建GetConn对象
Connection conn = getConn.getConn();
}
}
本实例的运行结果如图1所示。
图1 本实例的运行结果 说明:本书采用的是使用数据库驱动包jtds连接数据库,当然还可以使用其他的驱动包,例如“msbase.jar、mssqlserver.jar、msutil.jar”驱动包,只需要替换Class类forName()方法的参数,替换为:com.microsoft.jdbc.sqlserver.SQLServerDriver;将DriverManager类的getConnection()方法指定连接数据库的URL替换为:“jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=db_database15”,就可完成与数据库的连接。 3、执行SQL语句 建立数据库连接的目的是与数据库进行通信,实现方式为执行SQL语句,但是通过Connection实例并不能执行SQL语句,还需要Connection接口的createStatement()方法获取Statement对象。 例如:创建Statement对象state。 Statement statement = con.createStatement(); 上段代码中的con为Connection实例。 Statement实例只能执行静态的SQL语句,若要执行动态的SQL语句需要使用PreparedStatement实例。 如要实现数据的修改、插入、删除操作,可通过Statement接口的executeUpdate()方法,要实现从数据库中查询数据可通过Statement接口的executeQuery()方法。 4、获取查询结果集 通过Statement接口的executeUpdate()方法实现向数据库中添加、删除、修改数据,该方法的返回值为int型数值,代表影响数据库记录的条数;而使用executeQuery()方法实行查询操作,将返回一个ResultSet型的结果集,其中不仅包含所有满足查询条件的记录,还包含相应数据表的相关信息,例如每一列的名称、类型和列的数量等。 例如,从tb_teacher表中查询所有记录总数,代码如下: ResultSet res = statement.executeQuery("select* from tb_teacher"); ResultSet类似与一张数据表,要获取数据表中指定的列值,要通过ResultSet实例的getXXX()方法获取。通过getXXX()方法可通过指定列的序号和名称来获取数据。 例如循环遍历查询结果集res,代码如下: while(res.next()){ intid = res.getInt(1); Stringname = res.getString("name"); intage = res.getInt(4); Stringsex = res.getString("sex"); Stringsalary = res.getString(5); } 上段代码中的语句“res.getString("name")”,其中name就是数据表中的列名,此时如果该列是数据表中的第2列,如图2所示。
图2 结果集中的数据结构 5、关闭连接 在建立Connection、Statement和ResultSet实例时,均需占用一定的数据库和JDBC资源,所以每次访问数据库结束后,应该及时销毁这些实例,释放它们占用的所有资源,方法是通过各个实例的close()方法,并且在关闭时建议按照如下的顺序: resultSet.close(); statement.close(); connection.close();
编程锦囊:关闭连接 建议按上面的顺序关闭的原因在于Connection是一个接口,close()方法的实现方式可能多种多样。如果是通过DriverManager类的getConnection()方法得到的Connection实例,在调用close()方法关闭Connection实例时会同时关闭Statement实例和ResultSet实例。但是通常情况下需要采用数据库连接池,在调用通过连接池得到的Connection实例的close()方法时,Connection实例可能并没有被释放,而是被放回到了连接池中,又被其他连接调用,在这种情况下如果不手动关闭Statement实例和ResultSet实例,它们在Connection中可能会越来越多,虽然JVM的垃圾回收机制会定时清理缓存,但是如果清理的不及时,当数据库连接达到一定数量时,将严重影响数据库和计算机的运行速度,甚至导致软件或系统瘫痪。总之,应尽可能多的使用const关键字(Use constwhenever you need)。
1.2 向数据库中添加数据 在标准SQL语句中insert语句是插入语句,通过Statement接口的executeUpdate()方法可执行插入操作。 insert语句的语法格式为: INSERT INTO 表名[(字段名1,字段名2…)] VALUES(属性值1,属性值2, …) 例如:向数据表tb_emp(包含字段id,name,sex,department)插入数据,代码如下: insert into tb_emp values(2,’lili’,’女’,’销售部’); 例002 向数据库中添加数据 在项目中创建InsertTeacher类,该类实现向tb_teacher表中插入数据。
public class InsertTeacher {
Connection conn = null;
… …//篇幅有限省略了加载数据库的代码
public Connection getConn() {
String url = "jdbc:jtds:sqlserver://localhost:1433;
DatabaseName=db_database15"; // 连接数据库URL
String userName = "sa"; // 连接数据库的用户名
String passWord = ""; // 连接数据库密码
try {
conn = DriverManager.getConnection(url, userName,
passWord); //获取数据库连接
if (conn != null) {
System.out.println("数据库连接成功!");
}
} catch (SQLException e) {
e.printStackTrace();
}
return conn; //返回Connection对象
}
public static void main(String[] args) {
InsertTeacher iteacher = new InsertTeacher(); //创建本类对象
Connection conn = iteacher.getConn(); //调用获取数据库连接方法
String sql = "insert into tb_teacher
values('葛雷','男','32','5000')";//定义向数据库
try {
Statement statement = conn.createStatement();
statement.executeUpdate(sql);//执行插入的sql语句
} catch (SQLException e) {
e.printStackTrace();
}
}
}
说明:笔者在tb_teacher表中的主键id设置了自增属性,因此在使用insert语句向数据库添加值时,没有指定id的值仍然可以实现向数据库中添加信息。 运行本实例,数据表中的数据变化如图3所示。
图3 数据表中数据变化
1.3 删除数据库中的数据 在SQL语句中delete语句用于删除数据,通过使用JDBC技术实现向数据库中发送delete语句可实现删除数据。 delete语句的的语法格式如下: DELETE FROM 数据表名 where 条件表达式 例如:将tb_emp表中编号为1024的员工信息删除。代码如下: delete from tb_emp where id = 1024; 使用Statement对象的executeUpdate()方法可实现向数据库中发送删除语句。 例003 删除数据库中的数据 在项目中创建DeleteTeacher类,在该类中实现将tb_teacher表中的编号为4的教师信息删除。
public class DeleteTeacher {
Connection conn = null;
… …// 由于篇幅有限省略了加载数据库驱动的代码
public Connection getConn() {
String url = "jdbc:jtds:sqlserver://localhost:1433;
DatabaseName=db_database15"; // 连接数据库URL
String userName = "sa"; // 连接数据库的用户名
String passWord = ""; // 连接数据库密码
try {
conn = DriverManager.getConnection(
url, userName, passWord); // 获取数据库连接
if (conn != null) {
System.out.println("数据库连接成功!");
}
} catch (SQLException e) {
e.printStackTrace();
}
return conn; // 返回Connection对象
}
public static void main(String[] args) {
DeleteTeacher deleteTeacher = new DeleteTeacher();
// 调用获取数据库连接方法
Connection conn = deleteTeacher.getConn();
// 定义删除编号为4的教师信息的SQL语句
String sql = "delete from tb_teacher where id = 4";
try {
//创建Statement对象
Statement statement = conn.createStatement();
statement.executeUpdate(sql);//执行删除SQL语句
} catch (SQLException e) {
e.printStackTrace();
}
}
}
说明:如果delete语句没有通过where语句指定删除记录的添加,则会将数据表中的记录全部删除。图4 运行本实例的数据变化
注意:通过DELETE语句删除数据表中全部数据,与通过“DROP TABLE”命令删除表的不同点是,DELETE语句删除表中数据,但是保留表,而“DROP TABLE”命令则会将整张表删除。 1.4 修改数据库中数据 在标准SQL语句中,update语句表示更新数据表中记录,JDBC技术通过向数据库发送update语句可实现修改数据操作。 update语句的具体语法格式如下: UPDATE 数据表名 SET 字段名 = 新的字段值 WHERE 条件表达式 例如:将员工tb_emp表中的编号为2的员工姓名修改为“葛雷”,代码如下: update tb_emp set name = ‘葛雷’ where id = 2; 通过Statement实例的executeUpdate()方法可实现通过Java程序向数据库发送修改SQL语句。 例004 修改数据库中的数据 在项目中创建UpdateTeacher类,在该类中实现将tb_teacher表中的编号为2的教师姓名修改为“陈雨”。
public class UpdateTeacher {
Connection conn = null;
… …// 篇幅有限,省略了加载数据库驱动的代码
public Connection getConn() {
String url = "jdbc:jtds:sqlserver://localhost:1433;
DatabaseName=db_database15"; // 连接数据库URL
String userName = "sa"; // 连接数据库的用户名
String passWord = ""; // 连接数据库密码
try {
conn = DriverManager.getConnection(
url, userName, passWord); // 获取数据库连接
if (conn != null) {
System.out.println("数据库连接成功!");
}
} catch (SQLException e) {
e.printStackTrace();
}
return conn; // 返回Connection对象
}
public static void main(String[] args) {
UpdateTeacher updateTeacher = new UpdateTeacher();
Connection conn = updateTeacher.getConn(); //获取数据库连接
String sql = "update tb_teacher set name = '陈雨'
where id = 2"; //定义修改信息的SQL语句
try {
Statement statement = conn.createStatement();
statement.executeUpdate(sql);//执行修改SQL语句
} catch (SQLException e) {
e.printStackTrace();
}
}
}
运行本实例,数据库中数据表变化如图5所示。
图5 数据表中数据变化 1.5 从数据库中查询数据 与对数据表中的数据进行插入、删除、修改操作相比,实现对数据表的查询操作要相对复杂一些,因为查询的结果集保存在ResultSet对象中,需要通过遍历该对象获取查询结果集,在SQL语句中select语句表示查询语句。 select语句的具体语法格式如下: SELECT 所选字段列表 FROM 数据表名 WHERE 条件表达式 GROUP BY 字段名 HAVING 条件表达式(指定分组的条件) ORDER BY 字段名[ASC|DESC] 例如:从员工表tb_emp中所有男员工的姓名、年龄,并按年龄升序排序SQL语句如下: select name,age formtb_emp where sex = ‘男’ order by age; 查询是数据操作中,较重要的部分,下面以顺序查询、模糊查询为例向大家分别做介绍。 1、顺序查询 顺序查询是指应用select语句将数据表中满足条件的记录检索出来。 例005 顺序查询数据库中的数据 在项目中创建SelectTeacher类,该类中实现从教师表tb_teacher中查询出编号不等于1的教师信息,并将其显示在控制台中
public class SelectTeacher {
… …//篇幅有限省略了,加载数据库驱动的代码
public Connection getConn() {
Connection conn = null;
String url = "jdbc:jtds:sqlserver://localhost:1433;
DatabaseName=db_database15"; //定义连接数据库的url
String userName = "sa"; //连接数据库的用户名
String passWord = ""; //连接数据库的密码
try {
conn = DriverManager.getConnection(
url, userName, passWord); //获取数据库连接
} catch (SQLException e) {
e.printStackTrace();
}
return conn; //返回Connection实例
}
public static void main(String[] args) {
SelectTeacher selectTeacher = new SelectTeacher();
Connection conn = selectTeacher.getConn();
//定义查询的SQL语句
String sql = "select * from tb_teacher where id != 1";
Statement statement;
try {
statement = conn.createStatement(); //创建Statement实例
ResultSet rest = statement.executeQuery(sql); //执行SQL语句
while (rest.next()) { //循环遍历查询结果集
//依次获取查询
int id = rest.getInt(1);
String name = rest.getString(2);
String sex = rest.getString(3);
int age = rest.getInt(4);
System.out.print("教师编号为:" + id+" ");
System.out.print("教师姓名为:" + name+" ");
System.out.print("年龄为:" + age+" ");
System.out.print("性别为:" + sex+" ");
System.out.println("工资是:" + salary+" ");
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
运行本实例之前,先来看一下数据表tb_teacher中的数据,如图6所示。
图6 tb_teacher表中的数据 运行本示例,在控制台上显示查询结果,如图7所示。
2、模糊查询 模糊查询是一种很重要的查询方式,SQL语句中提供了LIKE操作符进行模糊查询,可使用“%”来代替0个或多个字符,使用下划线“_”来代替一个字符。例如,查询姓张的同学信息,SQL语句如下。 select * from tb_stu where name like ‘张%’ 例006 模糊查询数据库中的数据 在项目中创建SelectUseLike类,该类中实现从教师表tb_teacher中姓陈的教师信息。
public class SelectUseLike {
… …// 篇幅有限省略了加载数据库驱动的代码
public Connection getConn() {
Connection conn = null;
String url = "jdbc:jtds:sqlserver://localhost:1433;
DatabaseName=db_database15"; // 定义连接数据库的url
String userName = "sa"; // 连接数据库的用户名
String passWord = ""; // 连接数据库的密码
try {
conn = DriverManager.getConnection(
url, userName, passWord); // 获取数据库连接
} catch (SQLException e) {
e.printStackTrace();
}
return conn; // 返回Connection实例
}
public static void main(String[] args) {
SelectUseLike selectLike = new SelectUseLike();
Connection conn = selectLike.getConn(); // 获取数据库连接
try { // 创建Statement实例
Statement statement = conn.createStatement();
String sql = "select * from tb_teacher
where name like '陈%'"; // 定义模糊查询语句
ResultSet rest = statement.executeQuery(sql); // 执行SQL语句
while (rest.next()) { // 循环遍历查询结果集
// 依次获取查询
int id = rest.getInt(1);
String name = rest.getString(2);
String sex = rest.getString(3);
int age = rest.getInt(4);
String salary = rest.getString(5);
System.out.print("教师编号为:" + id + " ");
System.out.print("教师姓名为:" + name + " ");
System.out.print("年龄为:" + age + " ");
System.out.print("性别为:" + sex + " ");
System.out.println("工资是:" + salary + " ");
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
运行本实例之前,先来看一下教师表中的数据信息,如图8所示。
图8 教师表中的数据 运行本实例会将姓陈的教师信息,显示在控制台上,运行结果如图9所示。
图9 本实例的运行结果
1.6 使用预处理语句的好处有哪些 在前面介绍的查询语句中,有一个安全性问题需要注意,例如,在应用用户名和密码查询用户信息时,可以设置两个参数,之后通过参数传递,实现查询满足条件的记录,可定义如下的SQL语句: String sql = "select * from tb_user wherename='"+name+"' and password ="+password+'"; 这样的SQL语句定义完成后,可以满足系统的需要,但是有一个需要注意,此时如果将参数name设置为“‘apple’ or ‘a’ = ‘a’”,将参数password设置为“‘12’ or 1= 1”。这样,该SQL语句则被定义为: String sql = "select * from tb_stu wherename='apple’ or ‘a’ = ‘a’ and password =‘12’ or 1= 1); 这样SQL语句是正确的,可以访问数据库。这样就不能保证数据的安全性。解决这个问题,可以使用预处理语句。这事预处理语句的第一个优点。 使用预处理语句的第二个优点是,可以提高数据查询速度。因为向数据库发送一个SQL语句,数据库中的SQL解释器负责把SQL语句生成底层的内部命令,然后执行该命令。完成相关的数据操作。如果不断地向数据库提交SQL语句肯定会增加数据库中SQL解释器的负担。影响执行的速度。而预处理语句是对SQL语句进行编译预处理,生成数据库底层的内部命令,并将该命令封装在PreparedStatement对象中。通过调用该对象的相应方法执行底层数据库命令。这样应用程序能针对连接的数据库,实现将SQL语句解释为数据库底层的内部命令,然后让数据库执行这个命令,这样可以减轻数据库的负担,提高了访问数据库的速度。 java.sql包中的PreparedStatement接口,为大家提供了使用预处理语句的功能。下面为大家介绍如何定义预处理语句。 对SQL进行预处理时,可以通过使用通配符“?”来代替任何的字段值。例如: String sql = "select * from tb_teacher whereid = ?"; 在执行预处理语句之前,必须调用相应的方法来设置通配符所表示的值,例如: PreparedStatement pstatment =connection.prepareStatement(sql); pstatment.setInt(1, 1); 设置完成通配符的值之后,调用PreparedStatement实例的executeQuery()方法执行预处理语句。 ResultSet rest = pstatment.executeQuery(); 例007 通过预处理语句实现向教师表中添加信息 在项目中创建PreparDemo类,该类中创建insertTeacher()方法,通过预处理语句实现向教师表tb_teacher中添加信息。 (1)在insertTeacher()方法中,有一个与数据表tb_teacher中对应的教师对象Teacher为参数,该对象中包含的属性与数据表中的字段一一对应,并包含了属性的setXXX()与getXXX()方法。代码如下:
public class Teacher {
private int id; // 定义与数据表对应的id属性
private String name; // 定义与数据表对应的name属性
private String sex; // 定义与数据表对应的sex属性
private int age; // 定义与数据表对应的age属性
private String salary;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
… …// 篇幅有限,省略了其他属性的setXXX()与getXXX()方法
}
(2)在PreparDemo类中,首先需要编写加载数据库驱动,与获取数据库连接代码,读者可参考前面内容,这里不在赘述。下面来看一下insertTeacher()方法中代码如下:
public void insertTeacher(Teacher teacher){
PreparDemo demo = new PreparDemo(); //创建本类对象
Connection connection = demo.getConn(); //获取数据库连接
//定义向数据库中插入信息的预处理语句
String sql = "insert into tb_teacher values(?,?,?,?)";
try {
PreparedStatement prepstement = connection.
prepareStatement(sql);//获取PreparedStatement实例
//设置预处理语句的通配符值
prepstement.setString(1, teacher.getName());
prepstement.setString(2, teacher.getSex());
prepstement.setInt(3, teacher.getAge());
prepstement.setString(4, teacher.getSalary());
prepstement.executeUpdate(); //执行预处理语句
} catch (SQLException e) {
e.printStackTrace();
}
}
(3)在类的主方法中,创建与数据表对应的教师对象,并设置其属性值,之后调用PreparDemo类的添加数据方法,代码如下:
public static void main(String[] args) {
PreparDemo demo = new PreparDemo();
Teacher teacher = new Teacher(); //创建与数据表对象的JavaBean对象
teacher.setName("梁静"); //设置对象name属性值
teacher.setAge(28);
teacher.setSalary("3000");
teacher.setSex("女");
demo.insertTeacher(teacher); //调用添加数据方法
}
运行本实例,数据表中数据变化如图10所示。
图10 本实例的运行结果