JDBC
简介
java database connectivity
就是用java语言操作关系型数据库的一套API。
jdbc本质就是sun公司定义的一套操作所有关系型数据库的规则,即接口。
各个数据库厂商去实现这个接口,提供数据库驱动jar包。
我们可以使用这套接口编程,真正执行的代码是驱动jar包中的实现类。
可随时替换底层数据库,访问数据库的java代码基本不变。
快速入门
基本步骤
0、创建工程、导入驱动jar包
1、注册驱动(mysql5后的驱动jar包可以省略不写)
Class.forName("com.mysql.jdbc.Driver");
2、获取连接
String url = "jdbc:mysql://127.0.0.1:3306/db1";
String username = "root";
String password = "root";
Connection conn = DriverManager.getConnection(url,username,password);
3、定义sql语句
String sql = "update account set money = 2000 where id = 1";
4、获取执行sql对象
Statement stnt = conn.createStatement();
5、执行sql
int count = stnt.executeUpdate(sql); //受影响的行数
6、处理返回结果
System.out.println(count);
7、释放资源
stnt.close();
conn.close();
JDBC(API详解)
DriverManager
驱动管理类作用:(工具类)
1、注册驱动
2、获取数据库连接
URL连接:语法:jdbc:mysql://ip地址(域名)端口号/数据库名称?参数键值对1&参数键值对2...
示例:jdbc:mysql://127.0.0.1:3306/db1
细节:如果连接的是本机mysql服务器,并且mysql服务器的默认端口号是3306.则URL可以简写为
jdbc:mysql:///数据库名称?参数键值对
在默认路径后配置useSSL=false参数,禁用安全连接方式,解决警告提示。
Connection
数据库连接对象作用
1、获取执行sql对象
(1)普通执行sql对象
Statement createStatemnet()
(2)预编译sql的执行sql对象:防止sql注入
PreparedStatement prepareStatement(sql)
(3)执行存储过程的对象
CallableStatement prepareCall(sql)
2、管理事务:Connection接口中定义了3个对应的方法
开启事务:setAutoCommit(boolean autoCommit):true为自动提交事务;false为手动提交事务,即为开启事务。
提交事务:commit()
回滚事务:rollback()
代码示例:
//执行sql的对象
try {
//开启事务
conn.setAutoCommit(false);
int count = stat.executeUpdate(sql); //受影响的行数
//处理结果
System.out.println(count);
int i = 3/0; //制造一个异常
//执行sql的对象
int count1 = stat.executeUpdate(sql1); //受影响的行数
//处理结果
System.out.println(count1);
//提交事务
conn.commit();
} catch (Exception e) {
//回滚事务
conn.rollback();
e.printStackTrace();
}
java中使用try-catch来处理事务异常的方式,在catch中回滚事务。
statement
作用:
1、执行sql语句
int executeUpdate(sql): 执行DML语句、DDL语句
返回值:(1)DML语句影响的行数、(2)DDL语句执行后,执行成功也可能返回0
ResultSet executeQuery(sql):执行DQL语句
返回值:ResultSet结果集对象
ResultSet
ResultSet(结果集对象)作用:
1、封装了DQL查询语句的结果
ResultSet stmt.executeQuery(sql):执行DQL语句,返回ResultSet对象
2、获取查询结果
boolean next();(1)将光标从当前位置向前移动一行
(2)判断当前行为是否为有效行
返回值:
true:有效行,当前行有数据
false:无效行,当前行没有数据
3、xxx getXxx(参数) 获取数据
xxx:数据类型;如:int getInt(参数);String getString(参数)
参数:
int:列的编号,从1开始
String:列的名称
## 使用步骤
1、游标向下移动一行、并判断该行是否有数据
2、获取数据:getXxx
//循环判断游标是否是最后一行末尾
while(rs.next){
//获取数据
rs.getXxx(参数);
}
如:
public class JDBCdemo_ResultSet {
@Test
public void testResultSet() throws Exception{
//获取连接
String url = "jdbc:mysql://127.0.0.1:3306/db1";
String username = "root";
String password = "root";
Connection conn = DriverManager.getConnection(url,username,password);
//3、定义sql
String sql = "select * from account";
//4、获取statement对象
Statement stat = conn.createStatement();
//5、执行sql
ResultSet rs = stat.executeQuery(sql);
//6、处理结果、遍历rs中的所有数据
//6.1光标向下移动一行,并且判断当前行是否有数据
while(rs.next()){
//6.2获取数据 getXxx()
int id = rs.getInt(1);
String name = rs.getString(2);
double money = rs.getDouble(3);
System.out.println(id);
System.out.println(name);
System.out.println(money);
}
//7、释放资源
rs.close();
stat.close();
conn.close();
}
}
ResultSet案列
需求:查询account账户表数据,封装为Account对象中,并且存储到ArrayList集合中。
//需求:查询account账户表数据,封装为Account对象中,并且存储到ArrayList集合中。
/*
*1、定义实体类Account
* 2、查询数据,封装到Account对象中
* 3、将Account对象存入到ArrayList集合中
* */
package com.itheima.jdbc;
import com.itheima.pojo.Account;
import org.junit.Test;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
@Test
public void testResultSet2() throws Exception{
//获取连接
String url = "jdbc:mysql://127.0.0.1:3306/db1";
String username = "root";
String password = "root";
Connection conn = DriverManager.getConnection(url,username,password);
//3、定义sql
String sql = "select * from account";
//4、获取statement对象
Statement stat = conn.createStatement();
//5、执行sql
ResultSet rs = stat.executeQuery(sql);
//创建集合
List<Account> list = new ArrayList<>();
//6、处理结果、遍历rs中的所有数据
//6.1光标向下移动一行,并且判断当前行是否有数据
while(rs.next()){
Account account = new Account();
//6.2获取数据 getXxx()
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、释放资源
rs.close();
stat.close();
conn.close();
}
}
Account类
package com.itheima.pojo;
public class Account {
private int id;
private String name;
private double money;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getMoney() {
return money;
}
public void setMoney(double money) {
this.money = money;
}
@Override
public String toString() {
return "Account{" +
"id=" + id +
", name='" + name + '\'' +
", money=" + money +
'}';
}
}
PreparedStatement(sql注入问题)
作用:
1、预编译SQL语句并执行:预防SQL注入问题
2、SQL注入:是通过操作输入来修改事先定义好的SQL语句,用以达到执行代码对服务器进行攻击的方法。
之登录的逻辑:
public void testLogin() throws Exception{
//获取连接
String url = "jdbc:mysql://127.0.0.1:3306/db1";
String username = "root";
String password = "root";
Connection conn = DriverManager.getConnection(url,username,password);
//接收用户名和密码
String name = "zhangsan";
String pwd = "123";
String sql = "select * from tb_user where username = '"+name+"' and password = '"+pwd+"' ";
//获取stmt对象
Statement stmt = conn.createStatement();
//执行sql
ResultSet resultSet = stmt.executeQuery(sql);
//判断是否登录成功
if(resultSet.next()){
System.out.println("登录成功");
}else{
System.out.println("登录失败");
}
// 7、释放资源
resultSet.close();
stmt.close();
conn.close();
演示sql注入
//演示SQL注入
public void testLogin_Inject() throws Exception{
//获取连接
String url = "jdbc:mysql://127.0.0.1:3306/db1";
String username = "root";
String password = "root";
Connection conn = DriverManager.getConnection(url,username,password);
//接收用户名和密码
String name = "sfgsfbsj";
String pwd = "'or' '1' = '1'";
//下面这个sql语句打印出来后是一个永真式,无论密码是多少,都会查到,登录成功 即是select * from tb_user where usename = 'sfgsfbsj' and password = ''or'1' = '1 '
String sql = "select * from tb_user where username = '"+name+"' and password = '"+ pwd+"' ";
System.out.println(sql);
//获取stmt对象
Statement stmt = conn.createStatement();
//执行sql
ResultSet resultSet = stmt.executeQuery(sql);
//判断是否登录成功
if(resultSet.next()){
System.out.println("登录成功");
}else{
System.out.println("登录失败");
}
// 7、释放资源
resultSet.close();
stmt.close();
conn.close();
}
解决sql注入问题(PreparedStatement)
PrepareStatement作用:
1、预编译SQL并执行SQL语句
(1)获取PrepaerStatement对象
//SQL语句中的参数值,使用?占位符替代
select sql = "select * from user where username = ? and password = ?"
//通过Connection对象获取,并传入对应的sql语句
PreparedStatement pstmt = connn.prepareStatement(sql);
(2)设置参数值
PreparedStatement对象: setXxx(参数1,参数2):给?赋值
Xxx:数据类型;如setint(参数1,参数2)
参数:
参数1:?的位置编号,从1开始
参数2:?的值
(3)执行sql
executeUpdate();/executeQuery();:不需要再传递sql。
代码:
//获取连接
String url = "jdbc:mysql://127.0.0.1:3306/db1";
String username = "root";
String password = "root";
Connection conn = DriverManager.getConnection(url,username,password);
//接收用户名和密码
String name = "zhangsan";
String pwd = "svfhafv";
//定义sql
String sql = "select * from tb_user where username = ? and password = ?";
//获取pstmt对象
PreparedStatement pstmt = conn.prepareStatement(sql);
//设置?的值
pstmt.setString(1,name);
pstmt.setString(2,pwd);
//执行sql语句
ResultSet rs = pstmt.executeQuery();
//判断是否登录成功
if(rs.next()){
System.out.println("登录成功");
}else{
System.out.println("登录失败");
}
// 7、释放资源
rs.close();
pstmt.close();
conn.close();
}
PreparedStatement的预编译功能
好处:
1、预编译sql,性能更高
(1)PrepareStatement预编译功能的开启,需要在URL后面加上useSeverPrepStmts=true。
原理:
在获取PrepareStatement对象时,就sql语句发送给mysql服务器进行检查,编译(这些很耗时)
执行时就不用再执行这些步骤了,速度更快
如果sql模板一样,则只需进行一次检查、编译
2、防止sql注入:将敏感字符进行转义
数据库连接池
数据库连接池是一个容器,负责分配,管理数据库连接(Connection)
它允许应用程序重复使用一个现有的数据库连接,而不再是重新建立一个
释放空闲时间超过最大空闲时间的数据库连接来避免因为没有释放数据库连接而引起的数据库连接遗漏
好处:
资源重用
提升系统响应速度
避免数据库连接遗漏
标准接口:DataSource
功能:获取连接
Connection getConnection()
常见的数据库连接
DBCP、C3P0、Druid(使用)
Druid(德鲁伊)是阿里开源的数据库连接池项目
德鲁伊使用步骤:
1、导入jar包druid-1.1 12jar
2、定义配置文件
3、加载配置文件
4、获取数据库连接池对象
5、获取连接
如:输出连接池连接对象
//导入jar包
//定义配置文件
//加载配置文件
Properties prop = new Properties();
prop.load(new FileInputStream("jdbc-demo/src/druid.properties"));
//获取连接池对象
DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);
//获取对应的数据库连接
Connection connection = dataSource.getConnection();
System.out.println(connection);
//System.out.println(System.getProperty("user.dir"));
JDBC练习之查询所有
完成商品品牌数据的增删改查操作
1、查询所有数据
(1)获取Connection
变化的 (2)定义SQL:select * from tb_brand
(3)获取PreparedStatement对象
变化的 (4)设置参数:不需要
(5)执行SQL
变化的 (6)处理结果:List<Brand>
(7)释放资源
如:
@Test
public void testSelectAll() throws Exception {
//获取connection
//加载配置文件
Properties prop = new Properties();
prop.load(new FileInputStream("C:/Users/dell/IdeaProjects/jdbc/jdbc-demo/src/druid.properties"));
//获取连接池对象
DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);
//获取数据连接Connection
Connection conn = dataSource.getConnection();
//定义SQL
String sql = "select * from tb_brand";
//获取pstmt对象
PreparedStatement pstmt = conn.prepareStatement(sql);
//设置参数
//执行SQL
ResultSet rs = pstmt.executeQuery();
//处理结果List<Brand> 封装为List集合
Brand brand = null;
List<Brand> brands = new ArrayList<>();
while (rs.next()){
//获取数据
int id = rs.getInt("id");
String brandName = rs.getString("brand_name");
String companyName = rs.getString("company_name");
int ordered = rs.getInt("ordered");
String description = rs.getString("description");
int status = rs.getInt("status");
//封装Brand对象
brand = new Brand();
brand.setId(id);
brand.setBrandName(brandName);
brand.setCompanyName(companyName);
brand.setOrdered(ordered);
brand.setDescription(description);
brand.setStatus(status);
//装载集合
brands.add(brand);
}
System.out.println(brand);
//释放资源
rs.close();
pstmt.close();
conn.close();
}
JDBC练习之添加&修改&删除
添加:public void testAdd() throws Exception {
//接收页面提交的参数
String brandName = "香飘飘";
String companyName = "香飘飘";
int ordered = 1;
String description = "绕地球一圈";
int status = 1;
//获取connection
//加载配置文件
Properties prop = new Properties();
prop.load(new FileInputStream("C:/Users/dell/IdeaProjects/jdbc/jdbc-demo/src/druid.properties"));
//获取连接池对象
DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);
//获取数据连接Connection
Connection conn = dataSource.getConnection();
//定义SQL
String sql = "insert into tb_brand(brand_name,company_name,ordered,description,status) values (?,?,?,?,?);";
//获取pstmt对象
PreparedStatement pstmt = conn.prepareStatement(sql);
//设置参数
pstmt.setString(1,brandName);
pstmt.setString(2,companyName);
pstmt.setInt(3,ordered);
pstmt.setString(4,description);
pstmt.setInt(5,status);
//执行SQL
int count = pstmt.executeUpdate();
//处理结果
System.out.println(count > 0);
//释放资源
pstmt.close();
conn.close();
修改: @Test
/*
* 修改:
* 1、SQL语句:
* update tb_brand set brand_name = ?,company_name = ?,ordered = ?,description = ?,status = ? where id = ?;
*2、参数需要:所有
* 3、返回的结果:Boolean
* */
public void testUpdate() throws Exception {
//接收页面提交的参数
String brandName = "香飘飘";
String companyName = "香飘飘";
int ordered = 1000;
String description = "绕地球三圈";
int status = 1;
int id = 4;
//获取connection
//加载配置文件
Properties prop = new Properties();
prop.load(new FileInputStream("C:/Users/dell/IdeaProjects/jdbc/jdbc-demo/src/druid.properties"));
//获取连接池对象
DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);
//获取数据连接Connection
Connection conn = dataSource.getConnection();
//定义SQL
String sql = "update tb_brand set brand_name = ?,company_name = ?,ordered = ?,description = ?,status = ? where id = ?;";
//获取pstmt对象
PreparedStatement pstmt = conn.prepareStatement(sql);
//设置参数
pstmt.setString(1,brandName);
pstmt.setString(2,companyName);
pstmt.setInt(3,ordered);
pstmt.setString(4,description);
pstmt.setInt(5,status);
pstmt.setInt(6,id);
//执行SQL
int count = pstmt.executeUpdate();
//处理结果
System.out.println(count > 0);
//释放资源
pstmt.close();
conn.close();
}
删除:
@Test
/*
* 删除:
* 1、SQL语句:
* delete from tb_brand where id = ?;
*2、参数需要:需要id
* 3、返回的结果:Boolean
* */
public void testDelete() throws Exception {
//接收页面提交的参数
int id = 4;
//获取connection
//加载配置文件
Properties prop = new Properties();
prop.load(new FileInputStream("C:/Users/dell/IdeaProjects/jdbc/jdbc-demo/src/druid.properties"));
//获取连接池对象
DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);
//获取数据连接Connection
Connection conn = dataSource.getConnection();
//定义SQL
String sql = "delete from tb_brand where id = ?;";
//获取pstmt对象
PreparedStatement pstmt = conn.prepareStatement(sql);
//设置参数
pstmt.setInt(1,id);
//执行SQL
int count = pstmt.executeUpdate();
//处理结果
System.out.println(count > 0);
//释放资源
pstmt.close();
conn.close();
}