Java Web学习 JDBC
1 JDBC概述
(1) JDBC本质:
//全称:( Java DataBase Connectivity ) Java 数据库连接。
<1> 官方(sun公司)定义的一套操作所有关系型数据库的规则,即接口。
<2> 各个数据库厂商去实现这套接口,提供数据库驱动jar包。
<3> 我们可以使用这套接口(JDBC)编程,真正执行的代码是驱动jar包中的实现类。
(2) JDBC好处:
<1> 各数据库厂商使用相同的接口,Java代码不需要针对不同数据库分别开发。
<2> 可随时替换底层数据库,访问数据库的Java代码基本不变。
//对于各个厂商,官方提供的接口中已经定义了相同的方法签名以及要实现的功能,具体实现交由厂商来完成。
//无论用户使用哪一种数据库,要实现某种功能,都会使用同一个方法。
(3) JDBC流程:
第一步:编写Java代码
第二步:Java代码将SQL发送到MySQL服务端
第三步:MySQL服务端接收到SQL语句并执行该SQL语句
第四步:将SQL语句执行的结果返回给Java代码
2 JDBC快速入门
(1) 创建工程,导入驱动jar包。
//jar包一般放在文件夹:lib。该文件夹与src同级。
(2) 注册驱动
Class.forName("com.mysql.jdbc.Driver");
//加载Driver类。Driver注册驱动底层执行的仍是DriverManager类中的方法。
//MySQL 5之后的驱动包,可以省略注册驱动的步骤。
(3) 获取连接
String url ="jdbc:mysql://127.0.0.1:3306/db1";
//语法:jdbc:mysql://ip地址(域名):端口号/数据库名称?参数键值对1&参数键值对2…
//本机mysql服务器,并且mysql服务默认端口是3306,则url可以简写为:jdbc:mysql:///数据库名称?参数键值对
//配置 useSSL=false 参数,禁用安全连接方式,解决警告提示。
String username = "root";
String password = "1234";
Connection conn = DriverManager.getConnection(url, username,password);
(4) 定义SQL语句
String sql = “update…” ;
(5) 获取执行SQL对象
Statement stmt = conn.createStatement();
(6) 执行SQL
int count = stmt.executeUpdate(sql);
//count是受影响的行数。
(7) 处理返回结果
System.out.println(count);
或
if(count > 0){
System.out.println("修改成功!");
}else{
System.out.println("修改失败!");
}
(8) 释放资源
stmt.close();
conn.close();
3 DriverManager作用
(1) 注册驱动
在Driver类中的静态代码块中已经执行了 DriverManager 对象的registerDriver() 方法进行驱动的注册了。
那么我们只需要加载 Driver 类,该静态代码块就会执行。Class.forName(“com.mysql.jdbc.Driver”); 就可以加载Driver类。
//Driver注册驱动底层执行的仍是DriverManager类中的registerDriver()。
(2) 获取数据库连接
<1> 方法:
public static Connection getConnection(String url,String user,String password)
throws SQLException
//试图建立到给定数据库 URL 的连接。
<2> 参数:
url: 连接路径
//相当于数据库的位置信息。
user:用户名
password:密码
4 Connection作用
(1) 获取执行 SQL 的对象
<1> 普通执行SQL对象
Statement createStatement()
<2> 预编译SQL的执行SQL对象:防止SQL注入
PreparedStatement prepareStatement(sql)
(见 7 PreparedStatement)
<3> 执行存储过程的对象
CallableStatement prepareCall(sql)
//通过这种方式获取的 CallableStatement 执行对象是用来执行存储过程的,而存储过程在MySQL中不常用。
(2) 管理事务
<1> Connection接口中的相关方法:
<1.1> 开启事务:将此连接的自动提交模式设置为给定状态。
void setAutoCommit(boolean autoCommit)
//参数autoCommit 表示是否自动提交事务,true表示自动提交事务,false表示手动提交事务。
//自动提交事务默认为true,而开启事务需要将该参数设为为false。
<1.2> 提交事务:所有上一次提交/回滚后进行的更改成为持久更改,并释放此 Connection 对象当前持有的所有数据库锁。
void commit()
throws SQLException
<1.3> 回滚事务:取消在当前事务中进行的所有更改,并释放此 Connection 对象当前持有的所有数据库锁。
void rollback()
throws SQLException
<2> 代码实现:
try {
// ============开启事务==========
conn.setAutoCommit(false);
int count1 = stmt.executeUpdate(sql1);//sql1语句受影响的行数
System.out.println(count1);
//一旦两句sql某一句出现异常,就会转入到catch语句,回滚事务。
int count2 = stmt.executeUpdate(sql2);//sql2受影响的行数
System.out.println(count2);
// ============提交事务==========
//程序运行到此处,说明没有出现任何问题,则需求提交事务。
conn.commit();
} catch (Exception e) {
// ============回滚事务==========
//程序在出现异常时会执行到这个地方,此时就需要回滚事务.
conn.rollback();
e.printStackTrace();
}
5 Statement作用
(1) 执行DDL、DML语句
<1> 执行给定SQL语句,该语句可能为INSERT、UPDATE或DELETE语句,或者不返回任何内容的SQL语句(如SQL DDL语句)。
//执行完DDL语句,可能是0。以后开发很少使用java代码操作DDL语句。
int executeUpdate(String sql)
throws SQLException
<2> 代码实现:
(见 2 JDBC快速入门)
(2) 执行DQL语句
<1> 执行给定的SQL语句,通常为静态SQL SELECT语句,该语句返回单个ResultSet对象。
ResultSet executeQuery(String sql)
throws SQLException
<2> 代码实现:
(见 6 ResultSet中<2> 代码实现)
6 ResultSet作用
//只有一个作用,加标号只是为符合格式。
//释放资源时,rs需要被释放。
(1) 封装了SQL查询语句的结果。
<1> ResultSet 对象提供了操作查询结果数据的方法
//作为executeQuery(String sql)方法的返回值类型使用。
<1.1>将指针“先”从当前位置向下移动一行,“然后”判断当前行是否为有效行。//该方法实际分为两部分。
//ResultSet可以理解为一张表格,指针默认指向表头,执行next()方法后,指针指向第一行,判断是否为空。
//此时就可以通过 getxxx() 获取当前行某一字段的值,如果想获取下一行的数据,继续调用next() 方法,依此类推。
boolean next()
/*返回值:
true : 有效航,当前行有数据
false : 无效行,当前行没有数据*/
<1.2>获取数据,以xxx的形式获取此ResultSet对象的当前行中指定列的值。
xxx getXxx(参数)
//xxx : 表示数据类型。如: int getInt(参数) ;String getString(参数)
/*参数
int类型的参数:列的编号,从1开始。
String类型的参数: 列的名称,即数据表中的字段名。
int类型表示获取当前行的第int列的数据,String类型表示获取当前行字段为String的列中数据。*/
<2> 代码实现
<2.1> 判断是否登陆成功
if(rs.next()){
//只需查询到一行即成功,多用于账号密码登录。
System.out.println("登录成功!");
}else{
System.out.println("登录失败!");
}
<2.2> 输出所有查询到的数据
ResultSet rs = stmt.executeQuery(sql);
//处理结果, 遍历rs中的所有数据:
while (rs.next()){//光标向下移动一行,并且判断当前行是否有数据。
//获取数据 getXxx():
int id = rs.getInt(1);
String name = rs.getString(2);
double money = rs.getDouble(3);
或
int id = rs.getInt("id");
String name = rs.getString("name");
double money = rs.getDouble("money");
//输出数据
System.out.println(id);
System.out.println(name);
System.out.println(money);
}
(2) 案例:查询account账户表数据,封装为Account对象中,并且存储到ArrayList集合中。
ResultSet rs = stmt.executeQuery(sql);
// 创建集合
List<Account> list = new ArrayList<>();//不能在循环内定义,否则就会每次循环定义一个集合。
while (rs.next()){
//创建对象
Account account = new Account();
//获取数据
int id = rs.getInt("id");
String name = rs.getString("name");
double money = rs.getDouble("money");
//将数据封装到对象中
account.setId(id);
account.setName(name);
account.setMoney(money);
//将每一次遍历封装的对象存入集合
list.add(account);
}
System.out.println(list);
7 PreparedStatement
(1) SQL注入
String name = "sjdljfld";
String pwd = "' or '1' = '1";
String sql = "select * from tb_user where username = '"+name+"' and password = '"+pwd+"'";
//sql语句拼接方式不安全。
上面代码是将用户名和密码拼接到sql语句中,拼接后的sql语句为:
select * from tb_user where username = "sjdljfld" and password = "'or '1' = '1"
从上面语句可以看出条件 username = “sjdljfld” and password = “” 不管是否满足,而 or 后面的 ‘1’ = ‘1’ 是始终满足的,最终条件是成立的,就可以正常的进行登陆了。
(2) PreparedStatement作用:
<1> 预编译SQL,性能更高
在获取PreparedStatement对象时,将sql语句发送给mysql服务器进行检查,编译(这些步骤很耗时)。
执行时就不用再进行这些步骤了,速度更快。如果多条sql语句除了参数都一样,则只需要进行一次检查、编译。
<2> 防止SQL注入:
将敏感字符进行转义(引号转译成+引号)。
(3) 编写步骤
<1> 创建工程,导入驱动jar包。
<2> 注册驱动//可以省略
<3> 获取连接
<4> 定义SQL语句
String sql = "select * from user where username = ? and password = ?";
// SQL语句中的参数值,使用?占位符替代
PreparedStatement pstmt = conn.prepareStatement(sql);
<6> 设置参数值
pstmt.setxxx(1,参数);//xxx:数据类型 ; 如 setInt (参数1,参数2)
pstmt.setxxx(2,参数);//给第二个?赋值为参数。
/*参数:
1:?的位置编号,从1开始。
参数:?的值。*/
<7> 执行SQL
//调用这两个方法时不需要传递SQL语句,因为获取SQL语句执行对象时已经对SQL语句进行预编译了(dql语句在获取PreparedStatement对象时就已被传递)。
<7.1> 执行DDL语句和DML语句
int count = pstmt.executeUpdate();
<7.2> 执行DQL语句
ResultSet rs = pstmt.executeQuery();
<8> 处理返回结果
<9> 释放资源
8 数据库连接池
(1) 数据库连接池作用
<1> 数据库连接池是个容器,负责分配、管理数据库连接(Connection)
<2> 它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个。
//创建一个Connection对象,使用完毕就会将其销毁。这样重复创建销毁的过程是特别耗费计算机的性能的及消耗时间的。
//连接池是在一开始就创建好了一些连接(Connection)对象存储起来。
//用户需要连接数据库时,不需要自己创建连接,而只需要从连接池中获取一个连接进行使用,使用完毕后再将连接对象归还给连接池。
<3> 释放空闲时间超过最大空闲时间的数据库连接来避免因为没有释放数据库连接而引起的数据库连接遗漏。
//超过最大空闲时间则自动回收数据库链接。
(2) 标准接口:DataSource
官方(SUN) 提供的数据库连接池标准接口,由第三方组织实现此接口。该接口提供了获取连接的功能:
Connection getConnection()
//那么以后就不需要通过 DriverManager 对象获取 Connection对象,而是通过连接池(DataSource)获取 Connection 对象。
(3) 编写步骤
<1> 导入jar包 druid.jar//置于src同级目录lib下
<2> 定义配置文件 druid.properties//置于src路径下
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql:///db1?
useSSL=false&useServerPrepStmts=true
username=root
password=1234
# 初始化连接数量
initialSize=5
# 最大连接数
maxActive=10
# 最大等待时间
maxWait=3000
<3> 加载配置文件
Properties prop = new Properties();
prop.load(new FileInputStream("jdbc-demo/src/druid.properties"));
<4> 获取数据库连接池对象
DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);
<5> 获取连接
Connection connection = dataSource.getConnection();
••••••
9 总结
(1) 导入jar包 驱动jar和druid.jar//置于src同级目录lib下
(2) 定义配置文件 druid.properties//置于src路径下
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql:///db1?
useSSL=false&useServerPrepStmts=true
username=root
password=1234
# 初始化连接数量
initialSize=5
# 最大连接数
maxActive=10
# 最大等待时间
maxWait=3000
(3) 加载配置文件
Properties prop = new Properties();
prop.load(new FileInputStream("jdbc-demo/src/druid.properties"));
(4) 获取数据库连接池对象
DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);
(5) 获取连接
Connection connection = dataSource.getConnection();
(6) 定义SQL语句
String sql = "sql语句(参数用?代替)";
(7) 获取PreparedStatement对象
PreparedStatement pstmt = conn.prepareStatement(sql);
(8) 设置参数值
pstmt.setxxx(1,参数);
pstmt.setxxx(2,参数);
(9) 执行SQL
<1> 执行DDL语句和DML语句
int count = pstmt.executeUpdate();
<2> 执行DQL语句
ResultSet rs = pstmt.executeQuery();
(10) 处理返回结果
<1> 执行DDL语句和DML语句
if(count > 0){
System.out.println("修改成功!");
}else{
System.out.println("修改失败!");
}
<2> 执行DQL语句
while (rs.next()){
int id = rs.getInt(1);
......
或
int id = rs.getInt("id");
......
System.out.println(id);
......
}
(11) 释放资源
<1> 执行DDL语句和DML语句
pstmt.close();
conn.close();
<2> 执行DQL语句
rs.close();
pstmt.close();
conn.close();

浙公网安备 33010602011771号