Java JDBC学习实战(一): JDBC的基本操作
2014-09-26 10:47
288 查看
一、JDBC常用接口、类介绍
JDBC提供对独立于数据库统一的API,用以执行SQL命令。API常用的类、接口如下:
DriverManager,管理JDBC驱动的服务类,主要通过它获取Connection数据库链接,常用方法如下:
staticsynchronizedConnectiongetConnection(Stringurl,Stringuser,Stringpassword)throwsException;该方法获得url对应的数据库的连接。
Connection常用数据库操作方法:
StatementcreateStatementthrowsSQLException:该方法返回一个Statement对象。
PreparedStatementprepareStatement(Stringsql)throwsSQLException;该方法返回预编译的Statement对象,即将SQL语句提交到数据库进行预编译。
CallableStatementprepareCall(Stringsql)throwsSQLException:该方法返回CallableStatement对象,该对象用于存储过程的调用。
上面的三个方法都是返回执行SQL语句的Statement对象,PreparedStatement、CallableStatement的对象是Statement的子类,
只有获得Statement之后才可以执行SQL语句。
Connection控制事务的方法:
SavepointsetSavepoint():创建一个保存点
SavepointsetSavepoint(Stringname):创建一个带有名称的保存点
voidsetTransactionIsolation(intlevel):设置事务隔离级别
voidrollback():回滚事务
voidrollback(Savepointsavepoint):回滚到指定保存点
voidsetAutoCommit(booleanautoCommit):关闭自动提交,打开事务
voidcommit():提交事务
Statement,用于执行SQL语句的API接口,该对象可以执行DDL、DCL语句,也可以执行DML语句,还可以执行SQL查询语句,当执行查询语句是返回结果集,常用方法如下:
ResultSetexecuteQuery(Stringsql)throwsSQLException:该方法用于执行查询语句,并返回查询结果对应的ResultSet对象,该方法只用于查询语句。
intexecuteUpdate(Stringsql)throwsSQLException:该方法用于执行DML语句,并返回受影响的行数;该方法也可以执行DDL,执行DDL返回0;
booleanexecute(Stringsql)throwsSQLException:该方法可以执行任何SQL语句,如果执行后第一个结果是ResultSet对象,则返回true;如果执行后第一个结果为受影响的行数或没有任何结果,则返回false;
PreparedStatement,预编译的statement对象,PreparedStatement是Statement的子接口,它允许数据库预编译SQL(通常指带参数SQL)语句,以后每次只改变SQL命令参数,避免数据库每次都编译SQL语句,这样性能就比较好。而相对于Statement而言,使用PreparedStatement执行SQL语句时,无需重新传入SQL语句,因为它已经预编译了SQL语句。但是PreparedStatement需要为编译的SQL语句传入参数值,所以它比了如下方法:
voidsetXxx(intindex,value)根据该方法传入的参数值的类型不同,需要使用不同的方法。
传入的值的类型根据传入的SQL语句参数而定。
ResultSet
voidclose()throwsSQLException:释放、关闭ResultSet对象
booleanabsolute(introw):将结果集移动到第几行,如果row是负数,则移动到倒数第几行。如果移动到的记录指针指向一条有效记录,则该方法返回true;
voidbeforeFisrt():将ResultSet的记录指针定位到首行之前,这是ResultSet结果集记录指针的初始状态:记录指针的起始位置位于第一行之前。
booleanfirst():将ResultSet的记录指针定位到首行。如果移动后的记录指针指向一条有效记录,则该方法返回true。
booleanprevious():将ResultSet的记录指针定位到上一行,如果移动后的记录指针指向一条有效记录,则该方法返回true。
booleannext():将ResultSet的记录指针定位到下一行。如果移动后的记录指针指向一条有效记录,则返回true。
booleanlast():将ResultSet的记录指针定位到最后一行。如果移动后的记录指针指向一条有效记录,则返回true。
voidafterLast():将ResultSet的记录指针定位到最后一行之后。
二、JDBC编程步骤
进行jdbc编程步骤大致如下:
1、加载数据库驱动
Class.forName(driverClass)
上面的dirverClass就是数据库驱动类所对应的类路径字符串,根据不同数据库厂商提供的驱动也不同。
2、通过DriverManager获取数据库的链接
DriverManager.getConnection(Stringurl,Stirnguser,Stringpass)
当使用DriverManager来获取链接,需要传入三个参数:分别是数据量的url、用户名、密码。
3、通过Connection对象创建Statement对象,Connection创建Statement的方法如下三个:
createStatement()创建基本的Statement对象。
prepareStatement(Stringsql):根据传入的sql语句创建预编译的Statement对象。
prepareCall(Stringsql):根据传入的sql语句创建CallableStatement对象
4、Statement执行SQL语句,Statement有三大方法来执行SQL语句:
execute:可以执行任何SQL语句,单比较麻烦
executeUpdate:可以执行DML、DDL语句。执行DML返回受影响的SQL语句行数,执行DDL返回0;
executeQuery:只能执行查询语句,执行后返回代表查询结果的ResultSet对象。
5、操作结果集,针对ResultSet
主要移动指针和获得值
next、previous、first、last、beforeFrist、afterLast、absolute等移动指针的方法。
getXxx获得移动指针指向行,特定列、索引的值。使用列名作为获取值的参数可读性好、使用索引作为获取参数性能好。
6、关闭数据库连接资源
三、使用PreparedStatement执行SQL语句
使用PreparedStatement的好处在于他可以预编译SQL语句,提高sql的执行效率,并且,在其中可以使用带占位符(?)参数的SQL语句来代替它:insertintostudent_tablevalues(null,?,?)
实现方式:创建PreparedStatement对象使用Connection的preparedStatement()方法,该方法传入一个字符串,该SQL字符串可以包含占位符。pstmt=conn.prepareStatement("insertintostudent_tablevalues(null,?,1)");
示例:
packagecom.chen.yuan.jdbc;
importjava.io.FileInputStream;
importjava.sql.Connection;
importjava.sql.DriverManager;
importjava.sql.PreparedStatement;
importjava.util.Properties;
publicclassPreparedStatementDemo{
privateStringdriver;
privateStringurl;
privateStringuser;
privateStringpass;
/**
*初始化属性参数
*
*@paramparamFile
*@throwsException
*/
publicvoidinitParam(StringparamFile)throwsException{
Propertiesprops=newProperties();
props.load(newFileInputStream(paramFile));
this.driver=props.getProperty("driver");
this.url=props.getProperty("url");
this.user=props.getProperty("user");
this.pass=props.getProperty("pass");
//加载数据库驱动
Class.forName(driver);
}
/**
*使用PreparedStatement添加数据
*
*@throwsException
*/
publicvoidinsertUsePrepare()throwsException{
longstart=System.currentTimeMillis();
Connectionconn=null;
PreparedStatementpstmt=null;
try{
conn=DriverManager.getConnection(url,user,pass);
pstmt=conn
.prepareStatement("insertintostudent_tablevalues(null,?,1)");
//向其中插入100条数据
for(inti=0;i<100;i++){
pstmt.setString(1,"姓名"+i);
pstmt.executeUpdate();
}
System.out.println("使用PreparedStatement费时:"
+(System.currentTimeMillis()-start));
}catch(Exceptione){
e.printStackTrace();
}finally{
if(pstmt!=null){
pstmt.close();
}
if(conn!=null){
conn.close();
}
}
}
publicstaticvoidmain(String[]args)throwsException{
PreparedStatementDemopstmtdemo=newPreparedStatementDemo();
pstmtdemo.initParam("mysql.ini");
pstmtdemo.insertUsePrepare();
}
}
使用PreparedStatement除了可以提供sql的执行效率外,还防止SQL注入。
我们假设,有如下一段程序,直接使用Statement执行sql,这段程序主要是验证用户名和密码,通过之后,可登陆。
privatebooleanvalidate(StringuserName,StringuserPass)
{
//执行查询的SQL语句
Stringsql="select*fromjdbc_test"
+"wherejdbc_name='"+userName
+"'andjdbc_desc='"+userPass+"'";
System.out.println(sql);
try{
Connectionconn=DriverManager.getConnection(url
,user,pass);
Statementstmt=conn.createStatement();
ResultSetrs=stmt.executeQuery(sql);
//如果查询的ResultSet里有超过一条的记录,则登录成功
if(rs.next())
{
returntrue;
}
}catch(Exceptione)
{
e.printStackTrace();
}
returnfalse;
}如果,我们而已传入userName参数,注入sql语句:
#利用sql注入后生成的sql语句
select*fromjdbc_testwherejdbc_name=''ortrueor''andjdbc_desc='';
看到这条语句我们可以发现,该语句总是可以执行通过的,所以用户可以通过这种sql注入方式侵入一般的系统。
那我们现在看一下PreparedStatement如何来处理这种登录呢:
privatebooleanvalidate(StringuserName,StringuserPass)
{
try{
Connectionconn=DriverManager.getConnection(url
,user,pass);
PreparedStatementpstmt=conn.prepareStatement(
"select*fromjdbc_testwherejdbc_name=?andjdbc_desc=?");
pstmt.setString(1,userName);
pstmt.setString(2,userPass);
ResultSetrs=pstmt.executeQuery())
//如果查询的ResultSet里有超过一条的记录,则登录成功
if(rs.next())
{
returntrue;
}
}
catch(Exceptione)
{
e.printStackTrace();
}
returnfalse;
}
总体看来,PreparedStatement预编译SQL语句,性能更好;无需拼接sql语句,编程更简单;PreparedStatement可以防止依赖注入,安全性好。
四、使用CallableStatement调用存储过程
1)我们首先需要在mysql或oracle数据库中建立存储过程。下面以mysql为例:
delimiter//
createprocedureadd_pro(aint,bint,outsumint)
begin
setsum=a+b;
end;
//关于如何创建存储过程,请参看相关的书籍。
2)jdbc调用存储过程,需要使用CallableStatement,可以使用Connection的prepareCall()方法来创建CallableStatement对象,创建该对象时需要传入调用存储过程的sql语句。调用存储过程的格式:{call过程名(?,?,?.....)},其中?作为存储过程的占位符。例如,下面创建一个调用上述存储过程的CallableStatement对象。
cstmt=conn.prepareCall("{calladd_pro(?,?,?)}");
存储过程有传入参数和传出参数,所谓的传入参数就是Java程序必须为这些参数传入值,可以通过CallableStatement的setXxx()方法为之传入值;所谓传出参数就是Java程序可以通过该参数获取存储过程里值,CallableStatement需要调用registerOutParameter()方法来注册该参数。
cstmt.registerOutParameter(3,Types.INTEGER);
示例;
publicclassCallableStatementTest
{
privateStringdriver;
privateStringurl;
privateStringuser;
privateStringpass;
publicvoidinitParam(StringparamFile)throwsException
{
//使用Properties类来加载属性文件
Propertiesprops=newProperties();
props.load(newFileInputStream(paramFile));
driver=props.getProperty("driver");
url=props.getProperty("url");
user=props.getProperty("user");
pass=props.getProperty("pass");
}
publicvoidcallProcedure()throwsException
{
//加载驱动
Class.forName(driver);
try(
//获取数据库连接
Connectionconn=DriverManager.getConnection(url
,user,pass);
//使用Connection来创建一个CallableStatment对象
CallableStatementcstmt=conn.prepareCall(
"{calladd_pro(?,?,?)}"))
{
cstmt.setInt(1,4);
cstmt.setInt(2,5);
//注册CallableStatement的第三个参数是int类型
cstmt.registerOutParameter(3,Types.INTEGER);
//执行存储过程
cstmt.execute();
//获取,并输出存储过程传出参数的值。
System.out.println("执行结果是:"+cstmt.getInt(3));
}
}
publicstaticvoidmain(String[]args)throwsException
{
CallableStatementTestct=newCallableStatementTest();
ct.initParam("mysql.ini");
ct.callProcedure();
}
}
总结:(节摘自http://www.cnblogs.com/hoojo/archive/2011/06/10/2077643.html)
1、executeUpdate执行DDL、DML语句
2、execute执行SQL语句
3、PrepareStatement执行SQL语句
4、CallableStatement调用存储过程
JDBC提供对独立于数据库统一的API,用以执行SQL命令。API常用的类、接口如下:
DriverManager,管理JDBC驱动的服务类,主要通过它获取Connection数据库链接,常用方法如下:
staticsynchronizedConnectiongetConnection(Stringurl,Stringuser,Stringpassword)throwsException;该方法获得url对应的数据库的连接。
Connection常用数据库操作方法:
StatementcreateStatementthrowsSQLException:该方法返回一个Statement对象。
PreparedStatementprepareStatement(Stringsql)throwsSQLException;该方法返回预编译的Statement对象,即将SQL语句提交到数据库进行预编译。
CallableStatementprepareCall(Stringsql)throwsSQLException:该方法返回CallableStatement对象,该对象用于存储过程的调用。
上面的三个方法都是返回执行SQL语句的Statement对象,PreparedStatement、CallableStatement的对象是Statement的子类,
只有获得Statement之后才可以执行SQL语句。
Connection控制事务的方法:
SavepointsetSavepoint():创建一个保存点
SavepointsetSavepoint(Stringname):创建一个带有名称的保存点
voidsetTransactionIsolation(intlevel):设置事务隔离级别
voidrollback():回滚事务
voidrollback(Savepointsavepoint):回滚到指定保存点
voidsetAutoCommit(booleanautoCommit):关闭自动提交,打开事务
voidcommit():提交事务
Statement,用于执行SQL语句的API接口,该对象可以执行DDL、DCL语句,也可以执行DML语句,还可以执行SQL查询语句,当执行查询语句是返回结果集,常用方法如下:
ResultSetexecuteQuery(Stringsql)throwsSQLException:该方法用于执行查询语句,并返回查询结果对应的ResultSet对象,该方法只用于查询语句。
intexecuteUpdate(Stringsql)throwsSQLException:该方法用于执行DML语句,并返回受影响的行数;该方法也可以执行DDL,执行DDL返回0;
booleanexecute(Stringsql)throwsSQLException:该方法可以执行任何SQL语句,如果执行后第一个结果是ResultSet对象,则返回true;如果执行后第一个结果为受影响的行数或没有任何结果,则返回false;
PreparedStatement,预编译的statement对象,PreparedStatement是Statement的子接口,它允许数据库预编译SQL(通常指带参数SQL)语句,以后每次只改变SQL命令参数,避免数据库每次都编译SQL语句,这样性能就比较好。而相对于Statement而言,使用PreparedStatement执行SQL语句时,无需重新传入SQL语句,因为它已经预编译了SQL语句。但是PreparedStatement需要为编译的SQL语句传入参数值,所以它比了如下方法:
voidsetXxx(intindex,value)根据该方法传入的参数值的类型不同,需要使用不同的方法。
传入的值的类型根据传入的SQL语句参数而定。
ResultSet
voidclose()throwsSQLException:释放、关闭ResultSet对象
booleanabsolute(introw):将结果集移动到第几行,如果row是负数,则移动到倒数第几行。如果移动到的记录指针指向一条有效记录,则该方法返回true;
voidbeforeFisrt():将ResultSet的记录指针定位到首行之前,这是ResultSet结果集记录指针的初始状态:记录指针的起始位置位于第一行之前。
booleanfirst():将ResultSet的记录指针定位到首行。如果移动后的记录指针指向一条有效记录,则该方法返回true。
booleanprevious():将ResultSet的记录指针定位到上一行,如果移动后的记录指针指向一条有效记录,则该方法返回true。
booleannext():将ResultSet的记录指针定位到下一行。如果移动后的记录指针指向一条有效记录,则返回true。
booleanlast():将ResultSet的记录指针定位到最后一行。如果移动后的记录指针指向一条有效记录,则返回true。
voidafterLast():将ResultSet的记录指针定位到最后一行之后。
二、JDBC编程步骤
进行jdbc编程步骤大致如下:
1、加载数据库驱动
Class.forName(driverClass)
上面的dirverClass就是数据库驱动类所对应的类路径字符串,根据不同数据库厂商提供的驱动也不同。
2、通过DriverManager获取数据库的链接
DriverManager.getConnection(Stringurl,Stirnguser,Stringpass)
当使用DriverManager来获取链接,需要传入三个参数:分别是数据量的url、用户名、密码。
3、通过Connection对象创建Statement对象,Connection创建Statement的方法如下三个:
createStatement()创建基本的Statement对象。
prepareStatement(Stringsql):根据传入的sql语句创建预编译的Statement对象。
prepareCall(Stringsql):根据传入的sql语句创建CallableStatement对象
4、Statement执行SQL语句,Statement有三大方法来执行SQL语句:
execute:可以执行任何SQL语句,单比较麻烦
executeUpdate:可以执行DML、DDL语句。执行DML返回受影响的SQL语句行数,执行DDL返回0;
executeQuery:只能执行查询语句,执行后返回代表查询结果的ResultSet对象。
5、操作结果集,针对ResultSet
主要移动指针和获得值
next、previous、first、last、beforeFrist、afterLast、absolute等移动指针的方法。
getXxx获得移动指针指向行,特定列、索引的值。使用列名作为获取值的参数可读性好、使用索引作为获取参数性能好。
6、关闭数据库连接资源
三、使用PreparedStatement执行SQL语句
使用PreparedStatement的好处在于他可以预编译SQL语句,提高sql的执行效率,并且,在其中可以使用带占位符(?)参数的SQL语句来代替它:insertintostudent_tablevalues(null,?,?)
实现方式:创建PreparedStatement对象使用Connection的preparedStatement()方法,该方法传入一个字符串,该SQL字符串可以包含占位符。pstmt=conn.prepareStatement("insertintostudent_tablevalues(null,?,1)");
示例:
使用PreparedStatement除了可以提供sql的执行效率外,还防止SQL注入。
我们假设,有如下一段程序,直接使用Statement执行sql,这段程序主要是验证用户名和密码,通过之后,可登陆。
看到这条语句我们可以发现,该语句总是可以执行通过的,所以用户可以通过这种sql注入方式侵入一般的系统。
那我们现在看一下PreparedStatement如何来处理这种登录呢:
总体看来,PreparedStatement预编译SQL语句,性能更好;无需拼接sql语句,编程更简单;PreparedStatement可以防止依赖注入,安全性好。
四、使用CallableStatement调用存储过程
1)我们首先需要在mysql或oracle数据库中建立存储过程。下面以mysql为例:
2)jdbc调用存储过程,需要使用CallableStatement,可以使用Connection的prepareCall()方法来创建CallableStatement对象,创建该对象时需要传入调用存储过程的sql语句。调用存储过程的格式:{call过程名(?,?,?.....)},其中?作为存储过程的占位符。例如,下面创建一个调用上述存储过程的CallableStatement对象。
cstmt=conn.prepareCall("{calladd_pro(?,?,?)}");
存储过程有传入参数和传出参数,所谓的传入参数就是Java程序必须为这些参数传入值,可以通过CallableStatement的setXxx()方法为之传入值;所谓传出参数就是Java程序可以通过该参数获取存储过程里值,CallableStatement需要调用registerOutParameter()方法来注册该参数。
cstmt.registerOutParameter(3,Types.INTEGER);
示例;
总结:(节摘自
1、executeUpdate执行DDL、DML语句
Statement提供了execute、executeUpdate、executeQuery三种方法执行,下面用executeUpdate来执行DDL、DML语句,
executeUpdate执行DDL返回值是0,执行了DML是返回影响后的记录条数。
2、execute执行SQL语句
当我们知道SQL语句是完成修改语句时,我们就知道使用executeUpdate语句来完成操作;
如果SQL语句是完成查询操作的时候,我们就使用executeQuery来完成。
如果我们不知道SQL语句完成什么操作的时候,就可以使用execute方法来完成。
当我们使用Statement对象的execute方法执行SQL语句后返回的是boolean值,这就说明该语句能否返回ResultSet对象。
那么,如何判断是否是ResultSet对象?方法如下:
getResultSet():获取该Statement执行查询语句返回的ResultSet对象
getUpdateCount():获取该Statement执行修改语句影响的行数
3、PrepareStatement执行SQL语句
对于我们操作数据库的时候,执行某一条SQL语句的时候。只有它的参数不同,而SQL语句相同。
我们可以使用占位符来设置我们的参数信息,PrepareStatement中的占位符是?,用?代替参数的位置。
insertintotablevalues(?,‘abc’,?);
占位符仅仅支持PrepareStatement,而Statement不支持占位符。PrepareStatement是预编译SQL语句的,
然后将占位符替换成参数。而Statement就不能做到。
PrepareStatement对象也有execute、executeUpdate、executeQuery这三个方法,但这三个方法都无需传递参数。
只需用PrepareStatement来设置占位符的参数,通过用setXxxx(index,value)来完成设置参数信息即可。
PrepareStatement的效率要比Statement的效率高。
PrepareStatement设置参数可以不拼接字符串,而Statement设置参数信息的时候需要手动拼接字符串。
拼接字符串容易操作程序错误、可读性降低、维护性升高、程序性能下降。而PrepareStatement直接设置参数
信息就降低了编程的复杂度。并且它可以放在SQL注入。因为它是通过setXxx方法进行设置参数信息,
而Statement是通过拼接字符串,很容易就造成SQL注入。
综上所述,PrepareStatement比Statement有以下优点:
预编译SQL语句,性能更好
无需拼接SQL语句,编程更简单
可以防止SQL语句注入,安全性更好
4、CallableStatement调用存储过程
存储过程的调用可以通过CallableStatement,通过Connection对象的prepareCall方法来创建CallableStatement对象。
然后传入存储过程的SQL语句,即可调用存储过程,格式如下:
{callproc_name(?,?,?)}
上面的?是占位符,表示传递的参数。
存储过程有传入参数、传出参数。传入参数是程程序必须传入的参数,可以通过setXxx方法进行设置参数值。
而传出参数则需要通过程序进行设置,可以用CallableStatement对象的registerOutParameter方法来
注册输出参数,cs.registerOutParameter(3,Types.STRING);
设置完毕后,当调用存储过程后要获取输出参数值,可以通过getXxx方法来完成。
相关文章推荐
- Java JDBC学习实战(一): JDBC的基本操作
- java线程学习1——线程基本概念和操作
- 黑马程序员--Java基础学习之IO流之字节流、字符流、读取写入文件、Copy文件、键盘输入输出、流操作的基本规律
- Java JDBC学习实战(三): 事务管理
- java学习之文件基本操作
- JAVA学习笔记一:数组的基本操作
- java线程学习1——线程基本概念和操作
- Java学习总结14——JDBC操作详解
- Java JDBC学习实战(三): 事务管理
- java学习之文件基本操作
- Java学习笔记2 - 数组的基本操作
- [Java] JDBC 01 初步 , java 连接 数据库的基本六步操作
- LDAP学习笔记<四>jldap实现Java对LDAP的基本操作
- javaweb--jdbc--数据库操作学习笔记
- Java JDBC 操作学习【转帖】
- Java学习笔记——JDBC之与数据库MySQL的连接以及增删改查等操作
- hadoop学习:Java对HDFS的基本操作
- [Java] JDBC 01 初步 , java 连接 数据库的基本六步操作
- Spring4学习笔记-SpringJDBC基本操作(补充)
- JAVA学习第五十一课 — IO流(五)流的操作基本规律