第三讲数据库查询.docx
- 文档编号:24613311
- 上传时间:2023-05-29
- 格式:DOCX
- 页数:29
- 大小:193.97KB
第三讲数据库查询.docx
《第三讲数据库查询.docx》由会员分享,可在线阅读,更多相关《第三讲数据库查询.docx(29页珍藏版)》请在冰豆网上搜索。
第三讲数据库查询
目录
第1章JDBC编程2
1.JDBC基础概念2
2.JDBC驱动:
5
3.JDBCURL:
5
4.取得连结对象,执行SQL6
5.ResultSet:
结果集的提取6
6.使用预编译SQL7
7.批处理执行SQL8
8.事务管理深入9
9.数据库连结池应用13
10.元数据查询14
总结和任务:
16
补充一ORM映射原理17
补充二数据库访问模块设计18
第1章JDBC编程
目标:
1.掌握jdbc编程技术;
2.理解事务的概念;
3.使用数据库完成项目应用;
1.1JDBC基础概念
JDK提供了一组API,让我们可以在java程序中连结到网络上的数据库,并执行SQL语句返回执行结果,这组API的应用我们通常称作JDBC技术;相关的API都在包java.sql.*下面。
关键要理解的是:
JDBC提供了一组统一的API调用接口,以便我们可以连结、并操作库中的数据---我们只是学习了一组新的API的用法而己。
JDBC常用在二层,或三层(N层)结构应用程序中,如下图示:
二层结构三层结构
应用程序可能会面对不同的数据库,为了在应用中提供统一的调用,java.sql.*包中为应用程序提供的不是具体的类,而是数据库操作定义的接口;以下是sql包中定义的常用接口:
接口定义
说明
ResultSet
代表执行查询sql的结果集对象
ResultSetMetaData
数据库元数据对象
Statement
用于执行一条sql语句的声明对象,执行后可以返回ResulSet对象
PreparedStatement
用于执行预编译sql语句的声明对象,执行后可以返回ResulSet对象
CallableStatement
用于执行数据库存储过程声明对象,执行后可以返回ResulSet对象
Connection
一个Connection对象代表程序与数据库的一个连结,用与创建Statement对象。
Connection对象,则是由java.sql.DriverManager类的静态方法getConnection(…)得到,一但应用程序中得取一个Connection对象,即应用程序与数据库创建立了连结。
随后,我们就可以通过操作Connection对象,创建Statement对象以执行sql语句,或从执行结果返回的ResultSet中取得查询结果;这个过程也可以如下图示:
简单的示例,从数据库中查询出数据并打印到命令中,然后再来讲解其中的技术要点,我们将把数据库中如下表结构打印到命令行:
代码:
importjava.sql.Connection;
importjava.sql.DriverManager;
publicclassConn2Oracle{
//程序入口主方法
publicstaticvoidmain(String[]args)throwsException{
connDB();
}
/**
*1.连结到数据库,2.执行一条查询语句3.打印出查询结果
*/
privatestaticvoidconnDB(){
try{
//装载对应数据库的驱动类
Class.forName("oracle.jdbc.driver.OracleDriver").newInstance();
//数据库连结串
StringdbURL="jdbc:
oracle:
thin:
@localhost:
1521:
oar9i";
//创建连结,传入连结串,帐号,密码
Connectionconn=DriverManager.getConnection(dbURL,"root123","123456");
Stringsql="selectid,userid,contentfrompost";
java.sql.Statementstmt=conn.createStatement();
//执行sql,得到结果集
java.sql.ResultSetrs=stmt.executeQuery(sql);
System.out.println("IDUSERID内容");
//遍历结果集中第一行,打印出数据
while(rs.next()){
//取出每行中每一列
intid=rs.getInt
(1);
intuserID=rs.getInt
(2);
Stringcontent=rs.getString(3);
System.out.println(id+"|"+userID+"|"+content);
}
}catch(Exceptione){
System.out.println("数据库连接失败!
"+e);
e.printStackTrace();
}
}
}
EC控制台输出结果如下:
注意,如上程序要执行成功,除了数据库相关参数正确外,还必须将oracle_Homeora92\jdbc\lib\classes12.jar包加入到项目类库中---这个类库者是实际的Oracle数据库的JDBC实现,如果没加入这个类库,可能会报“找不到驱动”错误信息:
如果是mysqlDB,驱动名应写成(驱动jar包要从www.mysql.org上下载):
com.mysql.jdbc.Driver
数据库连结串的格式就应是:
jdbc:
mysql:
//localhost:
3306/netjavabbs
接下来,我们详细讲解其中每个步骤。
1.2JDBC驱动
在创建Connection对象前,必须使用Class.forName(“驱动类名”).newInstance()方法在JVM中生成指定数据库驱动对象。
如上例中语句,就是将我们加入的Oracle驱动包中的类oracle.jdbc.driver.OracleDriver装载进JVM。
//装载对应数据库的驱动类
Class.forName("oracle.jdbc.driver.OracleDriver").newInstance();
Class.forName("ClassName")返回的是一个Class对象,调用Class对象的newInstance()方法将使用这个Class对象创建类的具体对象,---相当于newClassName()调用。
因此上句代码也可以替换为:
oracle.jdbc.driver.OracleDriverod=neworacle.jdbc.driver.OracleDriver();
但写成Class.forName…方式,应用程序会获得较大的灵活性:
通过一个字符串,在运行时再确定装载的具体对象,这就是java语言动态性的体现,后面我们将会深入的讲解这一点。
注意,由与我们连结的是Oracle数据库,所以此处装载的是Oracle驱动包中的类,即classes12.jar中的oracle.jdbc.driver.OracleDriver.class。
对于某一种数据库,这个驱动类一般是固定的,但不同的数据库,则是不一样的;例如mySql中驱动类的名字就是其驱动包中的com.mysql.jdbc.Driver.class类。
在连结某一数据库前,必须装载正确的驱动类,并将其类库加入到classpath中,具体数据库的JDBC包及驱动类名,都可在其官方网站下载。
1.3JDBCURL
连结一个数据库时,必须指定数据库的URL,如本例中:
//数据库连结串
StringdbURL="jdbc:
oracle:
thin:
@localhost:
1521:
oar9i";
数据库URL首先代表的是一种通讯协议,即JDBC协议,一般是以jdbc:
开头,后面的写法,因不同的数据库相异,但一般都少不了数据库IP,端口,数据库名字三项。
例如,MYSQL连结串的格式是:
jdbc:
mysql:
//ip地址:
端口号/数据库名字
要正确连结数据库,URL的格式必须附合相应数据库的规则,其它参数,如IP,端口号,也必须是目标DB的正确参数。
1.4取得连结对象,执行SQL
最后一步就是取得代表应用程序与数据库连结通讯的Connection对象。
即语句:
//创建连结,传入连结串,帐号,密码
Connectionconn=DriverManager.getConnection(dbURL,"root123","123456");
一但这句语句执行成功,则数据库连结创建成功。
注意,DriverManager.getConnection()方法还有其它几个重载的方法,但其功能都是一样的。
连结对象创建成功后,即可通过连结对象创建statement对象,以执行SQL语句。
我们可将要执行的SQL语句分为两类,一类为需要返回结果表的select语句;一类为执行insert、update、delete操作的语句,因用程序只需要这类语句返回操作所生效的行数即可;对于这两种SQL操作,Statement在执行时可采用不同的方法,如是select语句,则使用executeQuery(sql)方法返回一个ResultSet对象,其中包含查询到的数据;如是另外三种,则使用executeUpdate(sql)方法,返回一个int型值,代表语句所影响的行数,如下代码示例:
Statementstmt=conn.createStatement();
StringdeleteSQL="deletefrompostwhereid=2";
intt=stmt.executeUpdate(sql);
1.5ResultSet:
结果集的提取
上面我们说,如果执行的是一个select语句,则返回一个ResultSet对象,代表查询到结果的表数据,我们可以通过如下方式,将ResultSet中的数据取出,注意从ResultSet中取出数据与结果表格中的对应关系:
Stringsql="selectid,userid,contentfrompost";
//执行sql,得到结果集
ResultSetrs=stmt.executeQuery(sql);
System.out.println("IDUSERID内容");
//遍历结果集中第一行,打印出数据
while(rs.next()){
//取出每行中每一列
intid=rs.getInt
(1);
intuserID=rs.getInt
(2);
Stringcontent=rs.getString(3);
…
每次while操作,相当与在表格中下向滚动一行;而rs.get<数据类型>方法需要的参数则是这行的哪一列的数据。
下表说明get<数据类型>方法返回的DB数据与java类型三者间的映射:
Table2-1:
SQLDataTypes,JavaTypes,andDefaultgetXXX()Methods
SQLDataType
JavaType
getXXX()Method
CHAR
String
getString()
VARCHAR
String
getString()
LONGVARCHAR
String
getString()
NUMERIC
java.math.BigDecimal
getBigDecimal()
DECIMAL
java.math.BigDecimal
getBigDecimal()
BIT
Boolean(boolean)
getBoolean()
TINYINT
Integer(byte)
getByte()
SMALLINT
Integer(short)
getShort()
INTEGER
Integer(int)
getInt()
BIGINT
Long(long)
getLong()
REAL
Float(float)
getFloat()
FLOAT
Double(double)
getDouble()
DOUBLE
Double(double)
getDouble()
BINARY
byte[]
getBytes()
VARBINARY
byte[]
getBytes()
LONGVARBINARY
byte[]
getBytes()
DATE
java.sql.Date
getDate()
TIME
java.sql.Time
getTime()
TIMESTAMP
java.sql.Timestamp
getTimestamp()
BLOB
java.sql.Blob
getBlob()
CLOB
java.sql.Clob
getClob()
1.6使用预编译SQL
数据库处理SQL语句时,需要一个预编译过程,数据库可以把一些格式固定的SQL编译后,存入在其内存池中,再次执行时即直接使用,不再执行预编译过程,这样可以有效提高数据库操作效率;我们可以通过预编译对象实现,如下代码示例:
/**
*使用预编译sql对象
*/
privatestaticvoidprepareInsert(){
try{
//sql中各个?
号为占位符
Stringsql="insertintouserinfo(id,username,userpwd,flag,email)"
+"values(SEQ_USERINFO_ID.nextval,?
?
?
?
)";
Connectionconn=getConnection();
//生成预编译对象
PreparedStatementpstmt=conn.prepareStatement(sql);
for(inti=0;i<5;i++){
//设置参数
pstmt.setString(1,"用户"+i);
pstmt.setString(2,"密码"+i);
pstmt.setInt(3,i/2);
pstmt.setString(4,i+"hybmw@");
//执行sql
pstmt.executeUpdate();
}
}catch(Exceptione){
System.out.println("数据库连接失败!
"+e);
e.printStackTrace();
}
}
注意,使用PreparedStatement执行的预编译sql中,如需有参数传入,可以便用?
做为占位符,生成PreparedStatement对象pstmt后,可以调用pstmt的set<数据类型>(占位索引,值)的方法设定,注意,这个占位索引的个数与序号必须与sql中?
的位置相匹配。
如下,重复设置了第二个占位符的值,而没有设第三个占位符的值,就会出错:
1.7批处理执行SQL
在前面的示例中,都是每次执行一条sql,对与大批量数据操作,这是低效的;但不论Statement提供了一个addBatch(Stringsql)的方法将sql加入批处理;PreparedStatement对象的addBatch()方法直接将预编译的sql加入批处理,最后可通过executeBatch()方法一次性执行所有sql。
注意,这里executeBatch()方法返回为一个int[],数组的第i个元素的值代表加入批处理的第i条sql所影响的行数。
如下示例:
/**
*sql批处理
*/
privatestaticvoidbatchInsert(){
try{
Stringsql="insertintouserinfo(id,username,userpwd,flag,email)"
+"values(SEQ_USERINFO_ID.nextval,?
?
?
?
)";
Connectionconn=getConnection();
//生成预编译对象
PreparedStatementpstmt=conn.prepareStatement(sql);
for(inti=0;i<5;i++){
//设置参数
pstmt.setString(1,"用户"+i);
pstmt.setString(2,"密码"+i);
pstmt.setInt(3,i/2);
pstmt.setString(4,i+"hybmw@");
//加为批处理
pstmt.addBatch();
}
//执行批处理
int[]resutt=pstmt.executeBatch();
}catch(Exceptione){
System.out.println("数据库连接失败!
"+e);
e.printStackTrace();
}
}
1.8元数据查询
元数据,可以理解为数据的数据,如数据库版本号、表的列数,列名,某列数据类型等,JDBC中可以得到两种元数据类型,一种是通过Connection对象的getMetaData()方法得到DatabaseMetaData对象用来取得数据库的相关信息;另一种是通过ResultSet对象的getMetaData()方法得得结果集的元数据ResultSetMetaData对象用来取得结果集,如列个数等相关信息。
如下代码示例,我们在命令行输出了数据库名字,版本号,及要查询的表结果。
/**
*根据元数据,输出表结构
*@paramtableName:
要输出的表名字
*/
privatestaticvoidtestMetaData(StringtableName){
try{
Connectionconn=getConnection();
//取得数据库的元数据对象
DatabaseMetaDatadmd=conn.getMetaData();
StringdbName=dmd.getDatabaseProductName();
StringdbVersion=dmd.getDatabaseProductVersion();
System.out.println("数据库是:
"+dbName+""+dbVersion);
System.out.println("\r\n"+tableName+"表显示如下:
");
Stringsql="select*from"+tableName+"orderbyiddesc";
PreparedStatementpstmt=conn.prepareStatement(sql);
ResultSetrs=pstmt.executeQuery();
//得到结果集的元数据对象
ResultSetMetaDatarmd=rs.getMetaData();
//结果集有几列
intcolumCount=rmd.getColumnCount();
//打印出每一列的标题
for(inti=1;i<=columCount;i++){
System.out.print(rmd.getColumnName(i)+"\t");
}
System.out.println();
while(rs.next()){
//取出每一列的值
for(inti=1;i<=columCount;i++){
//都做为字符串取出
System.out.print(rs.getString(i)+"\t");
}
System.out.println();
}
//打印出每一列的数据类型
for(inti=1;i<=columCount;i++){
System.out.print(rmd.getColumnTypeName(i)+"\t");
}
}catch(Exceptione){
System.out.println("数据库连接失败!
"+e);
e.printStackTrace();
}
}
在这个方法调用时传入userInfo为表名字,输出结果如下:
1.9数据库连结池应用
如同我们前面讲的的线程池,假设某个多线程应用程序要频繁执行sql,而其中某个sql执行花费时间很长,就有必要在程序中建立多个数据库连结,由每个线程或每条sql使用独立的Connection对象。
同样的,Connection的建立较之线程更为费时,不但要建立底层的TCP/IP链路,还要通过复杂的数据库安全认证计算,这就有必要采用“连结池”技术。
数据库连结池有很多开源的实现,这里我们采用apache社区的DBCP项目实现(http:
//commons.apache.org/dbcp/),我们只需要创建这个包中mons.dbcp.BasicDataSource类的一个对象即可,这就是连结池的实现,BasicDataSource实现了java.sql.DataSource接口的类,通过它的getConnection()方法可以从池中取出空闲的连结,用完毕后,再调用connection对象的close()方法将连结对象放回池中,而不是关闭底层jdbc的tcp/ip连结!
示例代码如下:
importjavax.sql.DataSource;
importjava.sql.Connection;
importjava.sql.PreparedStatement;
importjava.sql.SQLException;
importmons.dbcp.BasicDataSource;
/**
*示例apache的DBCP项目用法
*http:
//commons.apache.org/dbcp/
*@auther:
*/
publicclassBasicDataSourceExample{
//程序主方法
publicstaticvoidmain(String[]args)throwsException{
testQuery();
}
//测试使用连结池中的连结执行sql
pu
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 第三 数据库 查询