4JDBC学习笔记.docx
- 文档编号:5453537
- 上传时间:2022-12-16
- 格式:DOCX
- 页数:25
- 大小:55.18KB
4JDBC学习笔记.docx
《4JDBC学习笔记.docx》由会员分享,可在线阅读,更多相关《4JDBC学习笔记.docx(25页珍藏版)》请在冰豆网上搜索。
4JDBC学习笔记
JDBC学习笔记
Java相关课程系列笔记之四
目录
一、JDBC概述1
1.1什么是JDBC1
1.2什么是驱动1
1.3SQLlite1
1.4如何使用Java连接某种数据库1
1.5连接数据库并操作1
1.6连接数据库时常见的错误1
二、JDBC核心API2
2.1Connection2
2.2Statement2
2.3ResultSet2
2.4DriverManager2
2.5UUID3
2.6案例:
使用JDBC连接数据库,并操作SQL语句3
2.7案例:
通过JDBC创建表4
2.8案例:
使用JDBC向表中插入数据4
2.9遍历Student_chang表5
三、JDBC核心API:
PreparedStatement6
3.1Statement的缺点6
3.2PreparedStatement的优点6
3.3PreparedStatement的常用方法6
3.4案例详见第五章StudentDAO类6
四、Connection封装7
五、DAO8
5.1持久类封装8
5.2DAO层8
5.3Properties类8
5.4案例:
注册系统8
六、批处理12
6.1批处理的优点12
6.2JDBC批处理API12
6.3案例:
详见8.4案例step712
七、事务处理13
7.1事务特性ACID13
7.2JDBC中对事务的支持(API)13
八、DAO事务封装14
8.1ThreadLocal原理14
8.2原理图14
8.3ThreadLocal核心API14
8.4案例:
登录系统(使用ThreadLocal实现连接共享)14
九、分页查询17
9.1分页查询的基本原理17
9.2为何使用分页查询17
9.3Oracle分页查询SQL语句17
9.4MySQL分页查询SQL语句17
9.5“假”分页17
9.6案例:
分页查询18
1、JDBC概述
1.1什么是JDBC
1)Java的设计者希望使用相同的方式访问不同的数据库。
2)JDBC是Java用于统一连接数据库并操作数据库的一组通用接口定义(即通过一系列接口定义了访问数据库的通用API)。
3)JDBC是连接数据库的规范,不同的数据库厂商若想让Java语言可以对其操作,就需要实现一组类,这组类需要实现Java提供的这组用于连接数据库的接口,并实现其中定义的相关方法。
那么不同的数据库厂商根据各自数据库的特点,去提供对JDBC的实现(实现类包),那么这组类就是该数据库的驱动包了。
4)原理图:
1.2什么是驱动
简单的说就是让软件知道如何去操作硬件。
1.3SQLlite
是轻量级的数据库,常用于嵌入式。
1.4如何使用Java连接某种数据库
需要两个部分:
1)使用JDBC连接数据库(导入某数据库的.jar包)。
2)提供对该数据库的驱动包(使用静态方法Class.forName注册驱动)。
1.5连接数据库并操作
1)打开与数据库的连接(使用DriverManager.getConnection获取连接)。
2)执行SQL语句(使用Statement或者PreparedStatement)。
3)得到结果。
1.6连接数据库时常见的错误
1)报错ClassNotFoundException则有两种情况:
①驱动包没导入。
②Class.forName()中的字符串拼写有误。
2)报错portnumber,应注意:
①连接数据库时输入数据库路径时没有添加端口号。
②Oracle数据库的完整写法应为:
jdbc:
oracle:
thin:
@IP地址:
端口号:
数据库名
◆注意事项:
Oracle数据库默认端口号1521。
MySql数据库默认端口号为3306。
2、
JDBC核心API
2.1Connection
接口,需导入java.sql.Connnection包,与特定数据库进行连接(会话)。
2.2Statement
接口,需导入java.sql.Statement包,用于执行静态SQL语句并返回它所生成结果的对象。
1)ResultSetexecuteQuery(Stringsql)throwsSQLException方法:
执行给定的SQL语句(通常为静态SQLSELECT语句),该语句返回单个ResultSet对象。
2)booleanexecute(Stringsql)throwsSQLException方法:
执行给定的SQL语句,该语句可能返回多个结果。
如果第一个结果为ResultSet对象,则返回true;如果其为更新计数或者不存在任何结果,则返回false。
详细介绍请看2.6案例注释。
3)intexecuteUpdate(Stringsql)throwsSQLException方法:
执行给定SQL语句,该语句可能为INSERT、UPDATE、DELETE(DML语句),或者不返回任何内容的DDL语句。
返回值:
①对于数据操作语句(DML语句),返回行计数。
②对于DDL语句,返回0。
4)booleanexecute(Stringsql)方法:
返回结果为true、false,常用与执行表级操作的SQL语句,如建表、删表等,创建表若失败实际上是会直接抛出异常的。
false:
为建表成功的标志。
5)exectue()方法:
原则上可以执行任意SQL语句。
返回true:
若执行结果为一个结果集(ResultSet)。
返回false:
为其他信息(如影响表数据总条数等)。
所以我们通常不会使用execute去执行查询语句。
6)intexecuteUpdate(Stringsql)throwsSQLException方法:
返回值int,返回值为当前执行的SQL语句影响了数据库数据的总条数;该方法常用与执行insert、update、delete语句。
7)在底层一定会用到网络Socket和流,但我们不用关心使用字符还是字节接收,都由Statement做了。
2.3ResultSet
接口,表示数据库结果集的数据表(很像一个集合),通常通过执行查询数据库的语句生成。
1)ResultSet特点:
按行遍历,按字段取值。
2)它的next()方法包含了是否有下一条记录的hasnext()方法。
3)按字段取值时,getString(int)方法中的int,代表结果集的第几列,
◆注意事项:
这里的int从1开始,和Java对索引的习惯不同。
2.4DriverManager
它是管理一组JDBC驱动程序的类。
1)ConnectiongetConnection(Stringurl,Stringuser,Stringpassword)方法:
静态方法,建立与给定数据库URL的连接(DriverManager试图从已注册的JDBC驱动程序集中选择一个适当的驱动程序)。
2)DriverManager如何知道某种数据库已注册的?
例如:
oracle.jdbc.driver.OracleDriver类在Class.forName()的时候被载入JVM;
而OracleDriver是JDBC中Driver的子类,它被要求在静态初始化的时候要将自身驱动的信息通过DriverManager的静态方法注册进去,这样DriverManager就知道应该如何通过OracleDriver去连接该数据库了。
所以之后就可以通过DrvierManager的另一个静态方法:
getConnection()来根据之前注册的驱动信息获取连接了:
Connectionconn=DriverManager.getConnetion("","","");
2.5UUID
UUID为通用唯一标识码(UniversallyUniqueIndentifier)对于大数据量的表来说,UUID是存放ID最好的方式。
1)Java提供的支持(用法详见2.8案例)
UUID类:
UUID.randomUUID().toString():
获得一个36位不重复的字符串。
2)Oracle提供的支持(用法详见8.4案例step7)
函数sys_guid():
获取一个32位不重复的字符串。
2.6案例:
使用JDBC连接数据库,并操作SQL语句
/**连接数据库一定要捕获异常的*/
Connectionconn=null;//定义在try外面是用于在finally块中关闭它,同时局部变量在使用前,一定要初始化!
!
try{/**与数据库进行连接分为两步:
1)注册驱动:
不同的数据库实现不尽相同,所以要使用不同数据库厂商提供的驱动包。
连接不同数据库,传入的字符串不尽相同,但是目的相同,都是注册驱动。
而对于驱动包路径,名字是固定的,基本上不会变的!
2)根据数据库的位置(路径)以及用户名和密码进行连接*/
Class.forName("oracle.jdbc.driver.OracleDriver");
/**路径:
不同数据库连接的路径写法不尽相同,Oracle的写法:
jdbc:
oracle:
thin:
@HOST:
DB_NAME
其中HOST包含两部分:
IP地址和端口号;本机则使用localhost或127.0.0.1*/
conn=DriverManager.getConnection("jdbc:
oracle:
thin:
@192.168.0.20:
1521:
tarena",
"jsd1304","jsd1304");
/**使用SQL语句来操作数据库,若想执行SQL语句,我们需要使用一个专门处理SQL语句的类,这个类叫做Statement*/
Statementstate=conn.createStatement();
/**user_tables是Oracle用于存储当前用户创建的所有表的信息,其中一个字段叫做table_name用户保存的表名*/
Stringsql="SELECTtable_nameFROMuser_tables";
/**通过Statement执行查询语句,当查询完毕后,数据库会将查询结果返回,Statement会将查询结果存储到ResultSet中*/
ResultSetrs=state.executeQuery(sql);
while(rs.next()){//按行遍历,包含了是否有下一条记录的方法hasnext()
/**按字段取值;整数参数:
结果集的第几列。
注意:
这里从1开始,和Java对索引的习惯不同*/
StringtableName=rs.getString
(1);
System.out.println(tableName);
}
/**底层一定会用到网络socket和流,但我们不用关心使用字符还是字节接收,都由Statement做了*/
rs.close();state.close();
}catch(Exceptione){e.printStackTrace();
}finally{if(conn!
=null){try{conn.close();}catch(SQLExceptione){
e.printStackTrace();}}}
◆注意事项:
养成良好的编码习惯:
所有SQL关键字用纯大写,其他内容用纯小写。
2.7案例:
通过JDBC创建表
Connectionconn=null;
try{//1注册驱动
Class.forName("oracle.jdbc.driver.OracleDriver");
//2打开连接,支持importjava.sql.*,但全导入较耗费性能
conn=DriverManager.getConnection(
"jdbc:
oracle:
thin:
@192.168.0.20:
1521:
tarena","jsd1304","jsd1304");
//3创建用于执行SQL语句的Statement
Statementstate=conn.createStatement();
//创建建表语句
Stringsql="CREATETABLEStudent_chang("+
"idvarchar2(36)PRIMARYKEY,"+"namevarchar2(30),"+
"agenumber
(2),"+"sexvarchar2
(2)"+")";
//execute()方法详见2.2节
if(!
state.execute(sql)){System.out.println("创建表成功!
");
}else{System.out.println("创建失败!
");}
state.close();
}catch(Exceptione){e.printStackTrace();
}finally{if(conn!
=null){try{conn.close();}catch(SQLExceptione){
e.printStackTrace();}}}
2.8案例:
使用JDBC向表中插入数据
Connectionconn=null;
try{Class.forName("oracle.jdbc.driver.OracleDriver");
conn=DriverManager.getConnection(
"jdbc:
oracle:
thin:
@192.168.0.20:
1521:
tarena","jsd1304","jsd1304");
Statementstate=conn.createStatement();
//UUID详见2.5
Stringuuid=UUID.randomUUID().toString();System.out.println(uuid);
Stringsql="INSERTINTOStudent_changVALUES('"+uuid+"','Chang',22,'1')";
//或Stringsql="INSERTINTOStudent_changVALUES(sys_guid(),'chang',23,'1')";
//判断insert语句是否成功,看返回值是否大于0,executeUpdate方法详见2.2
if(state.executeUpdate(sql)>0){System.out.println("插入数据成功");}
state.close();
}catch(Exceptione){e.printStackTrace();
}finally{if(conn!
=null){try{conn.close();}catch(SQLExceptione){
e.printStackTrace();}}}
2.9遍历Student_chang表
Connectionconn=null;
try{Class.forName("oracle.jdbc.driver.OracleDriver");
conn=DriverManager.getConnection(
"jdbc:
oracle:
thin:
@192.168.0.20:
1521:
tarena","jsd1304","jsd1304");
Statementstate=conn.createStatement();
Stringsql="SELECT*FROMStudent_chang";
ResultSetrs=state.executeQuery(sql);
while(rs.next()){Stringid=rs.getString
(1);
Stringname=rs.getString("name");//不知第几列也可写列名
intage=rs.getInt("age");
Stringsex=rs.getString(4).equals("1")?
"男":
"女";
System.out.println(id+","+name+","+age+","+sex);}
rs.close();state.close();
}catch(Exceptione){e.printStackTrace();
}finally{if(conn!
=null){try{conn.close();}catch(SQLExceptione){
e.printStackTrace();}}}
3、
JDBC核心API:
PreparedStatement
3.1Statement的缺点
1)用Statement操作时代码的可读性和可维护性差,编写SQL语句复杂。
2)Statement操作SQL语句,每执行一次都要对传入的语句编译一次,效率比较差。
3)不安全可能出现SQL注入攻击,详见9.6案例step3。
4)扩展:
XSS攻击、html代码注入攻击、struts2OGNL存在可以远程执行底层操作系统命令的漏洞。
3.2PreparedStatement的优点
1)PreparedStatement实例包含已编译的SQL语句。
包含于PreparedStatement对象中的SQL语句可具有一个或多个IN参数。
IN参数的值在SQL语句创建时未被指定。
该语句为每个IN参数保留一个问号(“?
”)作为占位符,不考虑类型。
每个问号的值必须在该语句执行之前,通过适当的setString、setInt、setDouble……等方法来提供。
2)由于PreparedStatement对象已预编译过,所以其执行速度要快于Statement对象。
因此,多次执行的SQL语句经常创建为PreparedStatement对象,以提高效率。
3)PreparedStatement继承于Statement,其中三种方法:
execute、executeQuery、executeUpdate都已被更改为不再需要参数了。
因为我们在获取PreparedStatement时已经将SQL语句传入了。
所以执行就可以,不需要再传入SQL。
4)PreparedStatement可以进行批量处理。
5)可以防止SQL注入攻击。
◆注意事项:
v使用预编译语句,你传入的任何内容就不会和原来的语句发生任何匹配的关系,只要全使用预编译语句,你就不用对传入的数据作任何的过滤。
v对一个表只作一个操作用PreparedStatement,效率高、方便
v对表进行2种及以上的操作用Statement。
3.3PreparedStatement的常用方法
1)booleanexecute():
可以是任何种类的SQL语句。
一些预处理过的语句返回多个结果,execute方法处理这些复杂的语句,executeQuery和executeUpdate处理形式更简单的语句。
如果第一个结果是ResultSet对象,则返回true;如果第一个结果是更新计数或者没有结果,则返回false。
2)ResultSetexecuteQuery():
在此PreparedStatement对象中执行SQL查询,并返回该查询生成的ResultSet对象。
3)intexecuteUpdate():
在此PreparedStatement对象中执行SQL语句,该语句必须是一个DML语句,比如INSERT、UPDATE或DELETE语句;或者是无返回内容的语句,比如DDL语句。
4)voidaddBatch():
将一组参数添加到此PreparedStatement对象的批处理命令中。
其他批处理方法,见第六章。
5)voidsetObject(intparameterIndex,Objectx):
第一个参数用于设置“?
”中的值,且从1开始!
该方法可将任意给定的参数类型转换为所对应的SQL类型。
类似setInt、setString等。
3.4案例详见第五章StudentDAO类
4、
Connection封装
可建立一个DBUtils类,用于对数据库连接的封装。
privatestaticStringdriver;privatestaticStringurl;
privatestaticStringuser;privatestaticStringpassword;
static{//此处详细说明见5.4案例step2
try{Propertiesprops=newProperties();//Properties类详见5.3
props.load(DBUtils.class.getClassLoader().getResourceAsStream(
"db.properties"));
driver=props.getProperty("driver");
url=props.getProperty("url");
user=props.getProperty("user");
password=props.getProperty("password");
Class.forName(driver);//注意这里没有引号!
}catch(IOExceptione){e.printStackTrace();
}catch(ClassNotFoundExceptione){e.printStackTrace();}
}
/**封装连接操作,供其他类继承,再次使用数据库连接的时候,可以直接调用openConnection获取数据连接,其中url、user、pwd通过上面的.properties文件加载*/
protectedstaticConnectiongetConnection()throwsSQLException{
returnDriverManager.getConnection(url,user,pwd);
}
/**封装关闭操作,供其他类继承,关闭连接时调用该方法*/
protectedstaticvoidcloseConnection(Connectionconn){
if(conn!
=null){
try{conn.close();}catch(SQLExcptione){}
}//catch块内容可不写,即所谓的“安静”的关闭连接
}
5、
DAO
5.1持久类封装
对象关系映射(ORM)使用描述对象和数据库之间映射的元数据,将Java程序中的对象自动持久化到关系数据库中。
1)表和类对应。
2)表中的字段和类的属性对应。
3)记录和对象对应。
5.2DAO层
1)DAO:
数据连接对象(DataAccessObjects)
2)作用:
将数据库中的数据转化
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- JDBC 学习 笔记