JAVA企业级开发-jdbc入门(09)
一、 jdbc介绍
JDBC全称为:Java DataBase Connectivity(java数据库连接)。
SUN公司为了简化、统一对数据库的操作,定义了一套Java操作数据库的规范,称之为JDBC。
没有jdbc
有jdbc之后
二、 JDBC API 常用类与接口
jdbc的api在java.sql 以及 javax.sql的两个包下,以后同学们导包的时候要注意。
图中是几个核心类的关系。
DriverManager:数据库驱动管理类。
Connection:接口,建立数据库连接的一个接口。
Statement,preparedStatment,CallableStatment:接口:向数据库发送sql,并且得到数据库返回的信息。
ResultSet:结果集,Statement执行完sql---select之后,会返回结果,结果给了ResultSet
三、 JDBC 入门案例----重要
1、要连接mysql数据库。有一个mysql的数据库,并且要启动
2、创建一个数据库,创建一个表,把表添加一些数据。
3、找到msyql的驱动(jdbc的实现类),并且拷贝到工程中。build-path
4、书写java代码
5. 编程步骤
四、 jdbc-api详解
1. DriverManager 介绍
注意:这里只需要掌握 Class.forName(“com.mysql.jdbc.Driver”); 并且知道怎么来的
DriverManager驱动管理类。
|
|
参数:Driver---来自于你要连接的数据库(如果连接orcale,来自于oracle如果要连接mysql,来自于mysql)
registerDriver(new com.mysql.jdbc.Driver() );
不足:
1、对驱动api依赖性太高。
2、驱动会注册两次。(因为在mysql中的Driver中有静态代码块,已经注册了。)
com.mysql.jdbc.Driver 里面会静态代码块 加载两次
改进:
以后我们会使用Class.forname(“com.mysql.jdbc.Driver”); ---会把com.mysql.jdbc.Driver中的静态代码块执行一次。会实现驱动的注册。
jdbc提供的规范(要求驱动类中的静态代码块注册自己)。
java注册驱动的时候:
|
|
反射:把class文件加载,会执行类中的静态代码块
3. 建立与数据库的连接;
url:连接到某一个具体的数据库包括了 ip以及端口
user:数据库的用户名
password:数据库用户名对应的密码。
具体的调用方式:Connetion conn= DriverManager.getConnection()
3.a、 url介绍:指定一个具体的数据库
jdbc:mysql:///day07 ======jdbc:mysql://localhost:3306/day07?userUnicode=true&characterEncoding=utf8
jdbc:mysql:///sid ===== jdbc:mysql://localhost:3306/sid
要求是localhost,并且端口是3306; 才可以进行简写
前面是后面的简写。
jdbc:mysql://localhost:3306?key=value
url后面可以跟参数去解决数据库的乱码问题。
2、 Connection详解
需要注意的方法:
conn. prepareStatement (); 有待讲解
conn.createStatement();
2.a Connection详解
与特定数据库的连接(会话)。在连接上下文中执行 SQL 语句并返回结果。
如果想要发送sql到数据库,一定要通过这个连接。
Jdbc程序中的Connection,它用于代表数据库的链接,Collection是数据库编程中最重要的一个对象,客户端与数据库所有交互都是通过connection对象完成的,这个对象的常用方法
|
与特定数据库的连接(会话)。在连接上下文中执行 SQL 语句并返回结果。
如果想要发送sql到数据库,一定要通过这个连接。
Jdbc程序中的Connection,它用于代表数据库的链接,Collection是数据库编程中最重要的一个对象,客户端与数据库所有交互都是通过connection对象完成的,这个对象的常用方法:
|
PreparedStatment预编译的sql。
prepareStatement(sql) :创建向数据库发送预编译sql的PrepareSatement对象
---下午内容
PreparedStatment 继承 statement。
preparedStatement向数据库发送sql的。
|
prepareCall(sql):创建执行存储过程的callableStatement对象。仍然是statement对象的子接口。
--- 存储过程 ---oracle中
----明天内容
|
开启事务 |
setAutoCommit(boolean autoCommit):设置事务是否自动提交。--开启事务
|
|
commit() :在链接上提交事务。 ---与事务相关!!
|
|
rollback() :在此链接上回滚事务。
3. Statement 详解
需要掌握的方法:
stmt.executeUpdate(sql);
stmt.executeQuery(sql);
Statement:向数据发送sql的对象,并且得到执行sql之后的结果。 接口
Jdbc程序中的Statement对象用于向数据库发送SQL语句, Statement对象常用方法:
|
resultSet = executeQuery(String sql) :用于向数据发送查询语句。select * from 表名
resultSet结果集。
|
|
返回值说明:表示的是 sql语句执行之后,所改变的行数,影响的行数。
代码:
|
执行任意的sql语句。既可以执行insert,delete,update,还可以执行select。
返回值说明:
true:当执行select的时候返回true ---- 数据库返回来的内容是 resultSet
false:执行insert,update,,delete或者其他sql的时候返回false 数据库返回的内容是影响的行数。
如果执行的是 insert update delete 语句,程序希望获取影响的行数,可以通过getUpdateCount();获取影响的行数
|
|
如果执行的是select 语句:我们需要处理select语句执行之后获取的结果集
可以通过stmt.getResultSet(); 获取当前sql 执行之后得到的结果集
|
-----明天
addBatch(String sql) :把多条sql语句放到一个批处理中。
executeBatch():向数据库发送一批sql语句执行。
statement对象中的重要方法
executeUpdate(); ---update insert delete
executeQuery();---select
4、 ResultSet 详解
结果集:我们执行select 语句的时候,得到结果集
|
|
从1开始计数。
|
|
|
|
|
|
光标向上滚动
5. 滚动结果集---了解
结果集是如何获取到的---statement对象。
statement 如何获取到的:conn.createStatment();
结果集:Statement.executeQuery();
设置结果集的类型,conn.createStatment(参数。);
参数的值:ResultSet
结果集类型
ResultSet.TYPE_FORWARD_ONLY 只能向前,只能调用next 不能向回滚动
ResultSet.TYPE_SCROLL_INSENSITIVE 支持结果集向回滚动,不能查看修改结果
ResultSet.TYPE_SCROLL_SENSITIVE 支持结果集向回滚动,查看修改结果
结果集并发策略
ResultSet.CONCUR_READ_ONLY 只读
ResultSet.CONCUR_UPDATABLE 支持修改
常见三种组合
ResultSet.TYPE_FORWARD_ONLY 和 ResultSet.CONCUR_READ_ONLY (默认) 只读不支持向回滚动
ResultSet.TYPE_SCROLL_INSENSITIVE 和 ResultSet.CONCUR_READ_ONLY 只读,支持向回滚动
ResultSet.TYPE_SCROLL_SENSITIVE 和 ResultSet.CONCUR_UPDATABLE 支持向回滚动,支持对数据修改
rs提供了updateXXX( int , object);
XXX表示的数据类型。
第一个参数。表示列顺序,object具体的值
updateXXX(String,object);
第一个参数:列名
第二个参数:要修改的值。
|
|
通过updateXX() 更改数据库中某一列的值。
不长使用:
1、遍历结果集的时候,我们通常值遍历一次。
2、我们查询的时候,只想获得数据,不希望去此时修改数据。
如果修改数据采用update 语句修改数据
6、 资源释放
连接资源是珍贵的,是有数目限制的。如果只有打开没有关闭,那么当达到一个限定之后,其他人将无法继续连接数据库。所以需要关闭连接。
五、 JDBC CRUD 操作
1. insert
2. update
全部代码:
1 @Test 2 public void update() throws ClassNotFoundException{ 3 // 1、加载驱动 4 Class.forName("com.mysql.jdbc.Driver"); 5 // 2、建立链接 6 String url = "jdbc:mysql://localhost:3306/day07"; 7 String user = "root"; 8 String password = "123456"; 9 Connection conn = null; 10 Statement stmt = null; 11 12 try { 13 conn = DriverManager.getConnection(url, user, password); 14 // 3、获取statement对象 15 stmt = conn.createStatement(); 16 // 4、执行sql 17 String sql = " update tb_user set age=20 where id = 1 "; 18 int resnum = stmt.executeUpdate(sql); 19 System.out.println("您成功修改了"+resnum+"条数据"); 20 // 5、关闭链接 21 } catch (SQLException e) { 22 // TODO Auto-generated catch block 23 e.printStackTrace(); 24 }finally{ 25 try { 26 if(stmt != null){ 27 stmt.close(); 28 stmt = null; 29 } 30 } catch (SQLException e) { 31 e.printStackTrace(); 32 } 33 try { 34 if(conn != null){ 35 conn.close(); 36 conn = null; 37 } 38 } catch (SQLException e) { 39 e.printStackTrace(); 40 } 41 } 42 } 43 44
3. delete
重点部分:
4. select
2 @Test 3 public void select() throws ClassNotFoundException{ 4 5 // 加载驱动 6 Class.forName("com.mysql.jdbc.Driver"); 7 String url = "jdbc:mysql://localhost:3306/day07"; 8 String user = "root"; 9 String password = "123456"; 10 Connection conn = null; 11 Statement stmt = null; 12 ResultSet rs = null; 13 14 // 定义一个list 存放所有用户信息 15 List<User> userList = new ArrayList<User>(); 16 17 try { 18 conn = DriverManager.getConnection(url, user, password); 19 // 获取stmt对象 20 stmt = conn.createStatement(); 21 // 定义一个sql 22 String sql = " select * from tb_user "; 23 // 执行sql 24 rs = stmt.executeQuery(sql); 25 // 对结果集进行遍历 26 while(rs.next()){ 27 int id = rs.getInt("id"); 28 String username = rs.getString("username"); 29 int age = rs.getInt("age"); 30 String sex = rs.getString("sex"); 31 //会把查询出来的内容进行封装, 封装成我们java中的对象 32 User u = new User(); 33 u.setAge(age); 34 u.setId(id); 35 u.setSex(sex); 36 u.setUsername(username); 37 // 把u放入到集合中 38 userList.add(u); 39 40 // System.out.println(id + username + age + sex); 41 } 42 } catch (SQLException e) { 43 // TODO Auto-generated catch block 44 e.printStackTrace(); 45 }finally{ 46 try { 47 if(rs != null){ 48 rs.close(); 49 rs = null; 50 } 51 } catch (SQLException e) { 52 e.printStackTrace(); 53 }finally{ 54 55 } 56 /// 57 try { 58 if(stmt != null){ 59 stmt.close(); 60 stmt = null; 61 } 62 } catch (SQLException e) { 63 e.printStackTrace(); 64 } 65 try { 66 if(conn != null){ 67 conn.close(); 68 conn = null; 69 } 70 } catch (SQLException e) { 71 e.printStackTrace(); 72 } 73 } 74 75 for(User u : userList){ 76 System.out.println(u); 77 } 78 }
六、 JDBC 工具(JdbcUtil)类抽取
1. 在src目录下创建jdbc.properties 文件
2、 jdbc.properties文件里面的内容注意书写属性 的时候,不要书写 双引号和空格。
properties是配置文件L:里面已KEY=VALUE的形式保存
url=jdbc:mysql://localhost:3306/day07
user=root
password=123456
driverClass=com.mysql.jdbc.Driver
3. jdbc工具类:
a. 全局静态变量
b. 静态块
静态块中完成的功能:
1、读取外部的配置文件(读取properties)
2、把properties的内容 赋值 到 当前变量 例如 url = prop.getProperty(“url”);
3、加载驱动
new fileImputStream(默认在根目录下)
c、 获取连接方法:
d、 释放资源方法:
七、 三层介绍
八、jdbc案例(登录)
----建表语句
create table user(
id int primary key auto_increment,
username varchar(30) unique not null,
password varchar(30) not null
);
insert into user(id,username,password) values(null,'zhangsan','123456');
创建一个User这个对象。 通常会把放到一个固定的包里面 entity bean domain
要属性一个业务。 登录。 一个查询数据库的过程。所以 在dao层提供一个查询数据库的方法。
没一层的方法写好之后,要进行单独的测试。
整体包的分类
包介绍
2. dao的接口和实现
a. 接口:
b. 接口的实现:
3. servcie层代码
a. 接口:
b. 实现:
4.web层的实现
username 和 pwd 是对应页面上input标签上name属性所对应text中填写的值 这就为什么如果你要写form标签必须要有name属性,方便传给web层
request 和 response 这个在后面会讲到
5. 页面代码:
九、 sql注入问题
sql注入:在页面中输入sql的片段。达到串改程序中sql语句。
正常情况:
select * from user where username='zhangsan' and password = '123456';
当sql被注入之后的语句:
select * from user where username='zhangsan' and password = '' or '1'='1'
造成系统的不安全不保密。
十、 PreparedStatement解决sql注入
对sql进行预编译处理,sql的格式固定。可以防止预编译。
PrepareStatment 进行了预编译的处理,当下次执行相同格式的sql的时候,sql不会在进行编译。比statement的效率高。
statement每执行一次sql进行一次编译。
通过Connection
|
注意:sql提前创建好的。sql语句中需要参数。使用?进行站位。
举例:
select *from user where username=zhangsan and password = 123456;
使用?进行站位
select * from user where username=? and password=?
1、conn.prepareStatement(sql); -----需要你事先传递sql。如果sql需要参数,使用?进行占位。
2、设置参数(执行sql之前):prepStmt.setXXX(int index, 要放入的值) -----根据不同类型的数据进行方法的选择。第一个参数表示的是?出现的位置。从1开始计数
有几个问号,就需要传递接个参数。
方法的参数说明:
第一个参数:int index ;表示的是问号出现的位置。 问号是从1开始计数
第二个参数:要问号的位置传入的值。
3、执行,不需要在传递sql了。
prepStmt.executeQuery();---执行select
prepStmt.executeUpdate();---执行insert,delete,update
为什么用preparestatement就可以防止SQL注入?
如果进行sql注入后 会把 ‘进行转义
1. PreparedStatement优点
l PreparedStatement是Statement的子接口,它的实例对象可以通过调用Connection.preparedStatement(sql)方法获得,相对于Statement对象而言:
- PreperedStatement可以避免SQL注入的问题。
- Statement会使数据库频繁编译SQL,可能造成数据库缓冲区溢出。PreparedStatement 可对SQL进行预编译,从而提高数据库的执行效率。
- 并且PreperedStatement对于sql中的参数,允许使用占位符的形式进行替换,简化sql语句的编写。方便阅读。
使代码的可读性更高。
以后在企业中几乎都是用PreparedStatement
十一、 JDBC批处理
业务场景:当需要向数据库发送一批SQL语句执行时,应避免向数据库一条条的发送执行,而应采用JDBC的批处理机制,以提升执行效率。
实现批处理有两种方式,第一种方式:
- Statement.addBatch(sql)
- 执行批处理SQL语句
- executeBatch()方法:执行批处理命令
- clearBatch()方法:清除批处理命令
1. 批处理介绍和优点
2. statement 批处理
Statement.addBatch(sql)
执行批处理SQL语句
executeBatch()方法:执行批处理命令
clearBatch()方法:清除批处理命令
采用Statement.addBatch(sql)方式实现批处理:
优点:可以向数据库发送多条不同的sql语句。
缺点: SQL语句没有预编译。当向数据库发送多条语句相同,但仅参数不同的SQL语句时,需重复写上很多条SQL语句。例如:
Insert into user(name,password) values(‘aa’,’111’);
Insert into user(name,password) values(‘bb’,’222’);
Insert into user(name,password) values(‘cc’,’333’);
Insert into user(name,password) values(‘dd’,’444’);
3. preparestatement 批处理
4.两种批处理比较
statement
就是可以发送不同格式的SQL
preparedStatement