今日内容【重点掌握】
- JDBC基本概念
- 快速入门
- 对JDBC中各个接口和类详解
1. JDBC:
- 概念:Java数据库连接(Java DataBase Connectivity)
- Java语言操作数据库
- JDBC本质:
- 其实是官方(sun公司)定义的一套操作++所有关系型数据库的规则++,即接口。
- 各个数据库厂商去实现这套接口,提供数据库驱动jar包。
- 我们可以使用这套接口(JDBC)编程,真正执行的代码是驱动jar包中的实现类。
- 快速入门:
- 步骤:
- 导入驱动jar包(mysql-connector-java-5.1.37-bin.jar)
- 复制到项目的libs目录下
- 右键libs文件–>Add As Library(这样了才真正的加入到了项目中)
- 注册驱动(编写代码)
- Class.forName(“”);的作用是将代码加载进内存
- 会有异常:正常写的时候要处理
- 获取数据库的连接对象(Connection)
- 定义sql
- 获取执行sql语句的对象(Statement)
- 执行sql,接收返回结果
- 处理结果
- 释放资源
- ++详解各个对象++:
1. ++DriverManager:驱动管理对象++
- 是一个类
- 功能:
- 注册驱动:告诉程序该使用哪一个数据库驱动jar包
- 方法:static void registerDriver(Driver driver):注册与给定的驱动程序(DriverManager)
- 写代码时使用的是:Class.forName(“com.mysql.jdbc.Driver”);【重点掌握】//作用是将代码(类文件)加载进内存
- ++这样有一些代码会随着类的加载而自动执行(静态代码块static)++
- 通过查看源码发现:在com.mysql.jdbc.Driver类中存在静态代码块
- 所以底层实现就是DriverManager,只不过使用Class.forName(“com.mysql.jdbc.Driver”);简单【总结】
- 注:mysql之后的驱动jar包可以省略注册驱动的步骤【一般写上】
- 在jar包–>META-INF–>services–>java.sql.Driver中
- 注:Class.forName会有异常:正常写的时候要处理
- 获取数据库连接
- 方法:static Connection getConnection(String url, String user, String password);//静态方法,可以直接通过类名调用
- 这个也是会抛出异常,和Class.forName抛出的异常放到一起
- 参数:
- url:指定连接的路径
- 语法【重点】(每个sql语言都不太一样):
- MySQL
- 例子:
- 细节:如果访问本地则ip和端口号可以省略(了解)
- user:用户名
- password:密码
2. ++Connection:数据库连接对象++
- 是个接口
- 功能:
- 获取执行sql的对象
- 方法:
- Statement createStatement():【重点掌握】
- 例子:获取==执行sql语句的对象(Statement是返回值类型)
- PreparedStatement preparedStatement(String sql)
- 管理事务
- 开启事务:void setAutoCommit(boolean autoCommit):调用该方法设置参数为false(自动变为手动),即为开启事务
- 提交事务:commit()
- 回滚事务:rollback()
3. ++Statement:执行sql的对象【重点】++
- 是个接口
- 功能:
- 执行sql
- 方法:
- boolean execute(String sql):可以执行任意的sql–>(了解)
- int executeUpdate(String sql):【重点掌握】–>执行DML(增删改insert,delete,update)语句、DDL(表和库的操作create,alter,drop)语句
- 注:返回值就是执行语句影响的行数
- 执行DDL的时候不返回(默认0)
- 可以通过这个影响的行数判断DML语句是否执行成功,返回值>0则执行成功,反之,则失效
- ResultSet executeQuery(String sql):【重点掌握】–>执行DQL(查询select)语句
- 返回值是:结果集对象(就是查询sql后显示的呢个结果)
- 练习:
- account表 添加一条记录(insert)
- 注:释放资源放到finally里面(不管代码对不对都要释放)
- 导入sql包不要看错了
- account表 修改记录
- 修改id为3的钱为1500
- account表 删除一条记录
- 删除id=3的记录
4. ++ResultSet:结果集对象(用来封装查询结果)++
- 是一个接口
- 意义:从ResultSet结果集对象中,把查出来的结果数据拿出来
- 默认在第一行,所以先向下
- 执行方法让游标一行一行向下进行数据获取
- 每次获取的是该行的某一列数据
- 方法:
- boolean next():++游标向下移动一行,判断当前行是否是最后一行末尾(是否有数据),如果没有数据,返回false++
- getXxx(参数):获取数据
- Xxx:代表数据类型
- 比如获取id的时候getInt()
- 获取name的时候getString()
- 参数:(体现了方法的重载)
- Int:代表列的编号(从1开始)
- 获取id的列数据
- getInt(1):表示获取id列数据
- String:代表列的名称。
- 获取balance列的数据(余额)
- getDouble(“balance”);
- 演示:(将来不是这样使用的,这里只是基本使用)
- 结果集对象也是资源,所以也需要释放
- 出现的问题
- 获取第二行的时候又要复制所有获取数据代码
- ResultSet真正使用方式
- 游标向下移动一行
- 判断是否有数据
- 获取数据
- 练习:
- 定义一个方法,查询emp表的数据将其封装为对象,然后装载集合,返回。
- 定义Emp类
- 定义方法 public List findAll(){}
- 实现方法 select * from emp;
5. ++PreparedStatement:表示预编译sql语句的对象【开发真正用的】(功能更多)++
- Statement接口的子接口
- 注:浏览顺序,先看JDBC工具类在回头来看该内容
- JDBC工具类中综合案例出现的问题:SQL注入问题【重点】
- SQL注入概念【*】:在拼接sql时,有一些sql的特殊关键字参与字符串的拼接。(会造成安全问题)
- 例子:
- 输入用户随便(gxw),输入密码(特殊密码):
- 就会生成一段sql语句
- or之前确实是false但是后面加的为true,or是或运算,所有就恒等于true了(就很危险)
- ++解决SQL注入问题++:使用PreparedStatement对象来解决
- 预编译的sql【重点】:参数使用?作为占位符
- 步骤【真正要掌握的】:
- 导入驱动jar包(mysql-connector-java-5.1.37-bin.jar)
- 注册驱动(编写代码)
- Class.forName(“”);的作用是将代码加载进内存
- 获取数据库的连接对象(Connection)
- 定义sql
- 注意:sql的参数使用?作为占位符【#】
- 如:
- 获取执行sql语句的对象(PreparedStatement)
- 调用:Connection.prepareStatement(String sql)方法
- 要传递一个sql进来(不同之处)【注】
- 给?去赋值:
- 方法:setXxx(参数1,参数2);
- 参数1:?的位置编号从1开始
- 参数2:?的值
- 执行sql,接收返回结果(这里就不需要传递sql语句了)
- 处理结果
- 释放资源
- 优化JDBC工具类中的登录方法:
- 注意:后期都会使用PreparedStatement来完成增删改查的所有操作【重点】
- 防止SQL注入
- 效率更高
2. 抽取JDBC工具类 : JDBCUtils【工具类重点,会使用即可】
- 目的:简化书写
- 分析:【抽取的:注册驱动,获取连接对象,释放资源】
- 注册驱动也抽取
- 抽取一个方法获取连接对象【DriverManager.getConnection】
- 需求:++不想传递参数(麻烦),还得保证工具类的通用性。++
-
解决:配置文件
jdbc.properties
url=
user=
password=
- 抽取一个方法释放资源
- 代码实现【*】:
- 配置文件:jdbc.properties
- 方便调取,所以都是静态
- 什么时候使用静态代码块
- 如果需要程序在启动之前就进行一些操作,以及一些经常用到却不占用多少内存的代码或变量直接写在static静态代码块中,当程序启动的时候随之初始化,这样可以节省部分后续操作的时间
- 格式:
- ClassLoader 类加载器【先了解】
- 作用
- 获取src路径下的(资源路径)文件的方式
- 可以来加载我们的字节码文件进内存
- (JDBC工具类获取配置文件路径的)使用步骤【重点】
- 获取到ClassLoader,首先获取到对应的字节码文件对象
- 类名.class对象
- 其中一个getClassLoader()方法:获取到ClassLoader
- ClassLoader一个方法:getResource(String name):传入一个文件名(配置文件),就可以获取Resource资源。
- ++返回的是一个URL对象(表示:统一资源标识符/定位符):可以用来定位一个文件的绝对路径++
- 使用URL对象的一个方法,getPath():可以获取一个字符串路径
- 最后就可以将获取到的path,写到加载文件中了(上面三步就可以获取对应的资源文件的绝对路径了)
- Properties集合类
- 双列集合,键值都是String,唯一一个可以直接结合IO流使用的集合类,++从流中读取文件,直接写入文件到流中++
- 读取资源文件获取值的步骤
- 创建Properties集合类
- 加载文件:
- Properties集合类中load()方法:从字节输入流中读取键值对。参数中使用了字节输入流,通过流对象,可以关联到某文件上,这样就能够加载文本中的数据了。文本中的数据,必须是键值对形式,可以使用空格、等号、冒号等符号分隔。该方法常用于读取配置文件
- 获取值
- Properties集合类中getProperty()方法:将搜索此属性列表中指定键的属性值
- 演示JDBC工具类
- 练习:
- 需求(给db4数据库):
- 通过键盘录入用户名和密码
- 判断用户是否登录成功
- 如果这个sql有查询结果,则成功,反之,则失败
- 步骤:
- 创建数据库表 user
- 代码实现:
- 配置文件中的路径要进行修改:
- 前提要有前面写好的JDBCUtils工具类和配置文件
- 注:定义sql语句时,里面传入的username和password都是字符串,所以拼接的时候别忘了单引号
- 存在的问题SQL注入问题,请看上面第五个内容有讲解【注】
3. 使用JDBC控制事务:
- 事务:一个包含多个步骤的业务操作。如果这个业务操作++被事务管理,则这多个步骤要么同时成功,要么同时失败++
- 操作JDBC事务处理的位置【重点】:
- 开启事务:++执行sql之前++
- 在获取到Connection对象之后开启–>(因为事务管理功能就属于Connection对象)
- 提交事务:++sql都执行完++
- 在执行完sql语句之后
- 回滚事务:++catch中++
- 在catch当中,且注意判断conn是否为空
- Connection对象的两个功能:
- 获取执行sql的对象
- 管理事务
- 所以使用Connection对象来管理事务
- 开启事务:void setAutoCommit(boolean autoCommit):调用该方法设置参数为false(false–>手动:开启事务后如果没有提交事务,就会回滚事务),(true–>自动:每次执行完自动提交事务)
- 提交事务:commit()
- 回滚事务:rollback()
- 注:只要有异常就让回滚(放到catch中)
- 回滚的时候,conn有可能为null,所以在回滚前判断是否为空
- 案例:银行转账
- 注:catch一般写的范围比较大