java程序员第十八课 -JDBC02
来源:互联网 发布:一搜网络一搜同志0731 编辑:程序博客网 时间:2024/06/06 04:34
课程回顾:JDBC第一天
JDBC的概述
1.JDBC作用:Java数据库的链接。使用Java代码操作数据库。
2.JDBC接口是SUN提供的接口(规范),各个数据库的生厂商提供接口的实现类(jar包 – 驱动)
3.JDBC开发的步骤
* 加载驱动 Class.forName(“com.mysql.jdbc.Driver”);
* 获取链接 DriverManager.getConnection(url,username,password) url:jdbc:mysql:///day17
* 编写SQL语句
* 获取能执行SQL语句的接口 conn.createStatement();
* 执行SQL语句 stmt.executeQuery(sql); stmt.executeUpdate(sql);
* 返回的结果 while(rs.next){ rs.getXXX(“字段名称”) }
* 释放资源 (可以在finally块中,调用close()销毁链接)
DriverManager
1.加载驱动(过于依赖某个jar包,加载两次)
* Class.forName(“com.mysql.jdbc.Driver”);
2.获取链接
* DriverManager.getConnection(url,username,password) url:jdbc:mysql:///day17
* jdbc: 数据库协议
* mysql: 子协议
Connection接口(链接)
1.创建能执行SQL语句的对象
* Statement接口 – 能执行SQL语句
* PreparedStatement接口(重要) – 能执行SQL语句,可以进行预编译,防止SQL注入漏洞。
2.管理事物
* set autoCommit(false);
* commit(); – 提交事物
* rollback(); – 回滚事物
Statement接口(能执行SQL语句)
1.能执行SQL语句
* stmt.executeQuery(sql);
* stmt.executeUpdate(sql);
2.能执行批处理(MySQL批处理默认没有开启,需要通过参数手动的开启)
ResultSet接口(结果集)
1.如果执行查询语句的时候,把结果集(表格)封装到ResultSet接口中。
2.结果集中存在游标,默认存在第一行数据之前,调用rs.next()移动游标,游标移动到哪一行,获取到该行的数据。
while(rs.next){
// 获取数据
rs.getInt
rs.getString
rs.getObject 返回是Object
}
3.结果集默认只能向下移动,并且不能修改记录。了解设置滚动的结果集。
释放资源
1.可以在finally块中,调用close()销毁链接
JavaEE三层结构
1.SUN公司提出解决问题的方案,WEB层 – 业务层 – 持久层(操作数据库)
2.DAO的模式(规范:提供接口,提供实现类,封装的是表的单个操作(增删改查的操作))
登陆的案例
SQL注入的问题
1.产生:SQL语句使用的拼接的方式,用户在已知用户名的情况下,通过输入一些关键字
* ccc ’ or ’ 1=1
* ccc ’ – ’ 注释
2.解决问题:
* 使用PreparedStatement接口,能执行SQL语句,预编译。先把SQL语句发送到服务器,编译SQL语句。格式就固定了,再传入任何值,做为参数数据。
* 编写SQL语句的时候,使用?占位符代替参数。
数据库中的大的数据
1.文本 字符
2.MP3 字节
批处理
1.把一批SQL语句存入到一个批处理中,执行该批处理。
2.通过参数进行设置
今天内容:JDBC的第二天
事物
事物的概述
1.事物的概述:在同一个事物中,执行的SQL语句,要么都成功,要么都失败。
在MySQL数据库中使用事物
1.在MySQL的数据库中使用事物
* 可以使用命令操作事物
* start transaction; – 开启事物
sql1…
sql2…
* commit; – 提交事物(数据保存数据库,交易完成了)
* rollback; – 回滚事物(数据保存数据库中,恢复最初的状态)
* MySQL数据库中的事物是默认提交的。(你只要写一条SQL语句,该条SQL语句就独占一个事物,写完之后什么都不做,事物也是默认提交了) * 设置MySQL的事物不默认提交(在编写SQL语句,事物提交了吗?没有提交。) sql1... sql2... * 手动的提交获取回滚
2.测试MySQL中的事物
create database day18;
use day18;
create table t_account(
id int primary key auto_increment,
name varchar(50),
money double
);
insert into t_account values (null,'美美',10000);insert into t_account values (null,'冠希',10000);insert into t_account values (null,'小凤',10000);insert into t_account values (null,'小花',10000);insert into t_account values (null,'熊大',10000);
3.模拟测试
* 冠希给美美转1000块钱。(第一种方式)
* 开启事物 start transaction;
* 扣除冠希的1000块钱 update t_account set money = money - 1000 where name = ‘冠希’;
* 给美美加1000块钱 update t_account set money = money + 1000 where name = ‘美美’;
* 先编写查询的语句 select * from t_account;
* 提交或者回顾 rollback;
* 冠希给美美转1000块钱。(第二种方式) * show variables like '%commit%'; -- 查询和commit命令相关的属性信息(判断数据库的事物是否是默认提交的) * 手动设置不自动提交(默认只针对当前的窗口) * set autocommit = off或者0;设置不默认提交。 * 事物就不默认提交了 set autocommit = 0; * 扣除冠希的1000块钱 update t_account set money = money - 1000 where name = '冠希'; * 给美美加1000块钱 update t_account set money = money + 1000 where name = '美美'; * 手动提交或者回滚 rollback;
在JDBC中使用事物
1.如果在JDBC中使用事物,先找Connection接口。
2.和事物相关的方法
* void setAutoCommit(boolean autoCommit) – 传入false,设置MySQL事物不是默认提交的。
* void commit() – 提交事物
* void rollback() – 回滚事物
* void rollback(Savepoint savepoint) – 回滚到保存点的位置
3.代码
@Test
public void run(){
Connection conn = null;
PreparedStatement stmt = null;
try {
// 链接链接
conn = MyJdbcUtil.getConnection();
// 添加事物(设置MySQL数据库事物不是默认提交的)
conn.setAutoCommit(false);
// 编写SQL语句
String sql = “update t_account set money = money + ? where name = ?”;
// 预编译SQL
stmt = conn.prepareStatement(sql);
// 传入参数(给冠希扣除1000元)
stmt.setDouble(1, -1000);
stmt.setString(2, “冠希”);
// 先执行
stmt.executeUpdate();
// 添加点异常
int a = 10 / 0;
// 在美美加1000元
stmt.setDouble(1, 1000);
stmt.setString(2, “美美”);
stmt.executeUpdate();
// 提交事物
conn.commit();
} catch (Exception e) {
// 回滚事物
try {
conn.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
e.printStackTrace();
}finally{
MyJdbcUtil.release(stmt, conn);
}
}
回滚到保存点的位置(了解)
1.语句执行的过程中,设置一个保存点,事物回滚到保存点的位置上。
2.方法
* Savepoint sp = conn.setSavepoint(); – 设置保存点
* conn.rollback(sp); – 回滚到保存点的位置上
* conn.commit(); – 提交事物
3.模拟,冠希借给美美10000块钱,(中间添加保存点)美美说我还你100000元。
事物的特性ACID(面试)
1.原子性 :强调的是事物的不可分隔的特性。
2.一致性 :强调的是事物的执行的前后,数据完整性保持一致。
3.隔离性 :强调的多个事物同时操作一条记录,并发访问的问题。
4.持久性 :强调的事物结束后,数据永久的保存在数据库中。
不考虑事物的隔离性,产生一些问题
1.脏读 – 一个事物读取到另一个事物没有提交的数据
2.不可重复读 – 一个事物读取到了另一个事物提交的数据,导致两次查询的结果不一致。(强调的是更新数据的操作)
3.虚读(幻读) – 一个事物读取到了另一个事物提交的数据,导致两次查询的结果不一致。(强调的是添加数据的操作)
设置事物的隔离性(在数据库中进行设置)
1.read uncommitted – 未提交读 如果数据库的隔离级别是该级别,脏读、不可重复读、虚读都有可能发生
2.read committed – 提交读 如果数据库的隔离级别是该级别,脏读不能发生,但是不可重复读、虚读都有可能发生
3.repeatable read – 可重复读 如果数据库的隔离级别是该级别,脏读和不可重复不能发生,虚读有可能发生
4.serializable – 串行的 如果数据库的隔离级别是该级别,脏读、不可重复读和虚读都不能发生
- 效率 read uncommitted > read committed > repeatable read > serializable
- 安全 read uncommitted < read committed < repeatable read < serializable
- 注意:数据库中一般都不会采用效率最低的和安全性最低的
- MySQL默认的隔离级别:repeatable read
Oracle默认的隔离级别:read committed
通过一些命令查询和设置数据库的隔离级别
- select @@tx_isolation;
- set session transaction isolation level XXX; (XXX代表隔离级别)
演示脏读
1.脏读:一个事物读取到了另一个事物未提交的数据。
2.进行测试
* 开启两个窗口,一个A窗口(左),一个B窗口(右)。
* 在A窗口中,查询A窗口的隔离级别:select @@tx_isolation;
* 设置A窗口的隔离级别为最低级别: set session transaction isolation level read uncommitted;
* 在两个窗口中,都开启事物
* start transaction;
* 在B窗口中完成转账的工作。(冠希给美美转1千钱)
* update t_account set money = money - 1000 where name = ‘冠希’;
* update t_account set money = money + 1000 where name = ‘美美’;
* 注意:B窗口的事物未提交。
* 在A窗口中,查询的结果(美美)
* select * from t_account;
* 在B窗口中,回滚的是事物
* rollback;
避免脏读和演示不可重复读
1.避免脏读的发生,提高的隔离级别。
* set session transaction isolation level read committed;
* 在两个窗口中,都开启事物 * start transaction;* 在B窗口中完成转账的工作。(冠希给美美转1千钱) * update t_account set money = money - 1000 where name = '冠希'; * update t_account set money = money + 1000 where name = '美美'; * 注意:事物还是没有提交,但是你需要观察A窗口中是否能读取到B创建未提交的数据。* 在A窗口中,查询的结果(美美) * select * from t_account;* 在B窗口中把事物提交了 * commit;* 在A窗口中,再查询一次钱。 * 两次查询的结果不一致,发生了不可重复读。
避免不可重复读
1.设置隔离级别:set session transaction isolation level repeatable read;
* 在两个窗口中,都开启事物
* start transaction;
* 在B窗口中完成转账的工作。(冠希给美美转1千钱)
* update t_account set money = money - 1000 where name = ‘冠希’;
* update t_account set money = money + 1000 where name = ‘美美’;
* 注意:事物还是没有提交,但是你需要观察A窗口中是否能读取到B创建未提交的数据。
* 在A窗口中,查询的结果(美美)
* select * from t_account;
* 在B窗口中把事物提交了 * commit;* 在A窗口中,再查询一次钱。 * 两次查询的结果不一致,发生了不可重复读。
避免各种读
1.设置隔离级别:set session transaction isolation level serializable;
* 在两个窗口中,都开启事物
* start transaction;
* 在B窗口中添加一条数据
* insert into t_account values (null,’小苍’,10000);
* 注意:没有提交事物
* 在A窗口中查询数据库
* select * from t_account;
JDBC中设置事物的隔离级别
1.void setTransactionIsolation(int level) – 通过该方法设置数据库的隔离级别
2.包含4个值,在Connection接口中的4个常量
* static int TRANSACTION_READ_UNCOMMITTED :指示可以发生脏读 (dirty read)、不可重复读和虚读 (phantom read) 的常量
* static int TRANSACTION_READ_COMMITTED :指示不可以发生脏读的常量;不可重复读和虚读可以发生。
* static int TRANSACTION_REPEATABLE_READ :指示不可以发生脏读和不可重复读的常量;虚读可以发生。
* static int TRANSACTION_SERIALIZABLE :指示不可以发生脏读、不可重复读和虚读的常量。
数据库的连接池
连接池的概述
1.概述:为什么要有数据库的连接池,连接池有什么样的作用?
* 在没有连接池的情况下,需要创建链接的对象和销毁链接的对象。比较销毁时间的。
* 在程序中,指定连接池,中存放的都是连接,如果在使用的时候,从池中获取链接,然后直接使用。使用完之后,把链接归还到连接池中。
2.连接池的池参数(如果不指定值,肯定会有默认值的)
* 初始大小:10个
* 最小空闲连接数:3个
* 增量:一次创建的最小单位(5个)
* 最大空闲连接数:12个
* 最大连接数:20个
* 最大的等待时间:1000毫秒
3.连接池的时候,有4个配置的参数,必须要配置的
* driverClass – 驱动
* url – 数据库的链接
* username – 用户名
* password – 密码
自定义连接池
1.目的:连接池有一定的问题,讲解装饰者的模式。
2.条件
* 如果你想开发自定义连接池,需要实现javax.sql.DataSource接口。
* 实现Connection getConnection()方法。具体实现怎么写,需要自己来编写。
* 数据库的连接池,创建数据库的连接池的时候,需要先创建几个链接的对象,保存启动。最后指定的归还的链接方法。
3.问题
* 不能使用DataSource接口进行操作了。
* 自定义的归还链接的方法,用户需要掌握。
4.目的:
* 现在目的:就想修改close()方法,把销毁链接改成归还链接!!!!
装饰者模式(难点)
0.玩的面向接口的开发,你们知道MySQL实现类的名称叫什么么?
1.目的:增强某个类中的某个方法。
2.方式:
* 继承该类,重写该方法。
* 要继承的类的构造方法!!
* 使用装饰者的模式来完成该操作。 * 增强的类和被增强的类必须要实现同一个接口 * 在增强的类中必须要获取到被增强类的引用* 使用动态代理完成该操作。
3.过程
* 假设MySQL数据库的Connection接口的实现类的名字叫MysqlConnection
class MysqlConnection implements Connection{
public Statement createStatement(){
// 逻辑代码已经写完了
}
public PreparedStatement prepareStatement(String sql) { // 实现了.... } ... public void close(){ // 销毁链接 }}* 是你还有你,一切拜托你。* 自己编写一个实现类class myConnection implements Connection{ private Connection sqlConn; public myConnection(Connection sqlConn){ this.sqlConn = sqlConn; } public void close(){ // 这还是销毁 // sqlconn.close(); // 自己去定义一些内容,归还链接 } public Statement createStatement(){ // 调用MySQL实现类的方法 return sqlConn.createStatement(); } public PreparedStatement prepareStatement(String sql) { // 我自己实现了.... return sqlConn.prepareStatement(sql); } ... 都能使用sqlConn.xxxx实现一遍}myConnection myconn = new myConnection(new MysqlConnection());myconn.createStatement();
开源的数据库连接池
1.这些开源的数据库的连接池,Connection接口的close()方法都已经增强过了,调用该方法默认就是归还的方法了。
2.要求大家会使用就ok了。会完成一些配置。
DBCP连接池(重点)
1.是Apache组织提供开源的数据库的连接池。
2.导入2个jar包。
* commons-pool-1.5.6.jar
* commons-dbcp-1.4.jar
3.开发入门
* BasicDataSource 是DBCP的连接池对象(手动设置4大参数)
* BasicDataSourceFactory 有方法: static DataSource createDataSource(Properties properties) – 通过 properties获取到DataSource接口,获取连接对象。
* 设置4大参数 * 驱动 * url * username * password
4.代码:入门
@Test
public void run(){
Connection conn = null;
PreparedStatement stmt = null;
try {
// 先有DBCP的连接池
BasicDataSource dataSource = new BasicDataSource();
// 手动设置4大参数 dataSource.setDriverClassName("com.mysql.jdbc.Driver"); dataSource.setUrl("jdbc:mysql:///day18"); dataSource.setUsername("root"); dataSource.setPassword("root"); // 获取链接(从DBCP的连接池获取) conn = dataSource.getConnection(); // 编写SQL String sql = "update t_account set money = ? where name = ?"; stmt = conn.prepareStatement(sql); stmt.setDouble(1, 300); stmt.setString(2, "美美"); stmt.executeUpdate(); } catch (Exception e) { e.printStackTrace(); }finally{ // 先释放资源 MyJdbcUtil.release(stmt, conn); }}
5.通过配置文件的方式(properties文件)
* 需要先编写配置文件
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql:///day18
username=root
password=root
#<!-- 初始化连接 -->initialSize=10#最大连接数量maxActive=50#<!-- 最大空闲连接 -->maxIdle=20#<!-- 最小空闲连接 -->minIdle=5#<!-- 超时等待时间以毫秒为单位 6000毫秒/1000等于60秒 -->maxWait=60000/** * 读取配置文件的方式使用DBCP的连接池 */@Testpublic void run2(){ Connection conn = null; PreparedStatement stmt = null; try { // 先解析dbcp.properties文件 // 获取dbcp.properties文件 Properties pro = new Properties(); // 获取dbcp.properties文件的输入流 InputStream in = DbcpDemo.class.getClassLoader().getResourceAsStream("dbcp.properties"); pro.load(in); DataSource dataSource = BasicDataSourceFactory.createDataSource(pro); // 获取链接(从DBCP的连接池获取) conn = dataSource.getConnection(); // 编写SQL String sql = "update t_account set money = ? where name = ?"; stmt = conn.prepareStatement(sql); stmt.setDouble(1, 1300); stmt.setString(2, "美美"); stmt.executeUpdate(); } catch (Exception e) { e.printStackTrace(); }finally{ // 先释放资源 MyJdbcUtil.release(stmt, conn); }}
C3P0连接池(重点)
1.有需要导入jar包。
2.开发的操作
* ComboPooledDataSource 类代表C3P0连接池的对象
* 设置4个参数
* cpds.setDriverClass( “org.postgresql.Driver” );
* cpds.setJdbcUrl( “jdbc:postgresql://localhost/testdb” );
* cpds.setUser(“dbuser”);
* cpds.setPassword(“dbpassword”);
3.代码
@Test
public void run(){
Connection conn = null;
PreparedStatement stmt = null;
try {
// 获取连接池对象
ComboPooledDataSource dataSource = new ComboPooledDataSource();
// 设置4大参数
dataSource.setDriverClass(“com.mysql.jdbc.Driver”);
dataSource.setJdbcUrl(“jdbc:mysql:///day18”);
dataSource.setUser(“root”);
dataSource.setPassword(“root”);
// 先获取链接
conn = dataSource.getConnection();
String sql = “update t_account set money = ? where name = ?”;
stmt = conn.prepareStatement(sql);
stmt.setDouble(1, 100);
stmt.setString(2, “美美”);
stmt.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
}finally{
MyJdbcUtil.release(stmt, conn);
}
}
4.编写配置文件
* C3P0默认查询XML的配置文件,配置文件的名称c3p0-config.xml。
* 配置文件存放在src的目录下。
* 满足上述的条件,C3P0默认查询到配置文件,解析。把4大参数配置到XML文件中。
<c3p0-config> <!-- 默认的配置,C3P0默认加载默认配置 --> <default-config> <!-- 配置4大参数 --> <property name="driverClass">com.mysql.jdbc.Driver</property> <property name="jdbcUrl">jdbc:mysql:///day18</property> <property name="user">root</property> <property name="password">root</property> </default-config> <!-- 类加载的时候指定了配置的名称(named-config name="intergalactoApp") --> <named-config name="myoracle"> <property name="driverClass">com.mysql.jdbc.Driver</property> <property name="jdbcUrl">jdbc:mysql:///day18</property> <property name="user">root</property> <property name="password">root</property> </named-config></c3p0-config>* 代码: @Test public void run2(){ Connection conn = null; PreparedStatement stmt = null; try { // 获取连接池对象 ComboPooledDataSource dataSource = new ComboPooledDataSource("myoraclesssssssss"); // 有4大参数没关 // 先获取链接 conn = dataSource.getConnection(); String sql = "update t_account set money = ? where name = ?"; stmt = conn.prepareStatement(sql); stmt.setDouble(1, 11100); stmt.setString(2, "美美"); stmt.executeUpdate(); } catch (Exception e) { e.printStackTrace(); }finally{ MyJdbcUtil.release(stmt, conn); } }
工具类已经重写了
package cn.itcast.utils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import com.mchange.v2.c3p0.ComboPooledDataSource;
/**
* JDBC的工具类
* @author rt
*/
public class MyJdbcUtil2 {
public static ComboPooledDataSource dataSource = new ComboPooledDataSource();/** * 获取链接对象 * @throws SQLException */public static Connection getConnection() throws SQLException{ return dataSource.getConnection();}/** * 释放资源(两个参数和三个参数) */public static void release(ResultSet rs,Statement stmt,Connection conn){ if(rs != null){ try { rs.close(); } catch (SQLException e) { e.printStackTrace(); } rs = null; } if(stmt != null){ try { stmt.close(); } catch (SQLException e) { e.printStackTrace(); } stmt = null; } if(conn != null){ try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } conn = null; }}/** * 释放资源(两个参数和三个参数) */public static void release(Statement stmt,Connection conn){ if(stmt != null){ try { stmt.close(); } catch (SQLException e) { e.printStackTrace(); } stmt = null; } if(conn != null){ try { // 归还链接 conn.close(); } catch (SQLException e) { e.printStackTrace(); } conn = null; }}
}
Tomcat内置的连接池(了解)
1.把连接池的信息内置到Tomcat服务器中。
2.配置配置,来决定WEB服务器中的项目是否可以使用内置的连接池。
3.
- java程序员第十八课 -JDBC02
- JDBC02
- 第十八篇 黑马程序员-Java高新技术
- JAVA学习第十八课(异常及其思想 (一) )
- 黑马程序员——java第十八、十九天:IO流(一)
- JDBC02-Statement,PreparedStatement,ResultSet
- 第十八课:函数
- 第十八课 接口
- 第十八课 数学库
- Android第十八课;ListView
- 第十八课 使用视图
- 2017.11.27第十八课
- 第十八
- JAVA第十八弹(Map)
- Java基础笔记-第十八记
- 第十八章 JAVA多线程交互
- Java 编程题目 第十八题
- 孙鑫 第十八课ActiveX控件
- java程序员第十七课 -JDBC01
- 关于tomcat是否有必要设置环境变量
- Masonry介绍与使用实践:快速上手Autolayout
- Swift基本语法快速一览
- Face Alignment at 3000 FPS via Regressing Local Binary Features
- java程序员第十八课 -JDBC02
- iOS_常用宏定义汇总
- 二叉树的先序 中序 后序 层次遍历 求叶节点个数、深度、最大元、最小元
- Linux socket 编程实例——简单易懂,太好了!
- Unity3d中设置UISprite图片灰显方法
- RecylerViewd的Item高度自适应,Scrollview 嵌套 RecyclerView 及在Android 5.1版本滑动时 惯性消失问题
- Android dp转换像素问题
- MYSql主从复制原理
- 四则运算计速器算法