【JavaWeb】JDBC

Java Data Base Connectivity(JDBC)Java数据库连接

1 API

  • DriverManager: 用于注册驱动
  • Connection: 表示数据库的连接
  • Statement: 执行SQL语句的对象
  • ResultSet: 结果集或一张虚拟表
static void registerDriver(Driver driver)  DriverManager 注册给定驱动程序

static Connection getConnection(String url, String user, String password)

连接到给定数据库 URL,并返回连接。

Statement createStatement()

创建一个 Statement 对象来将 SQL 语句发送到数据库

// 1.注册驱动
// DriverManager.registerDriver(new Driver());
// 1.1 Mysql5版本之后,可以不用手动注册驱动
DriverManager.registerDriver(new com.mysql.jdbc.Driver());

// 2.获取数据库连接Connection对象
// 协议名:子协议://服务器名或IP地址:端口号/数据库名
Connection cn = DriverManager.getConnection("jdbc:mysql://localhost:3306/db1?useSSL=false", "root", "root");
// 2.1 如果连接的是本地,且端口是3306,localhost:3306可以省略
Connection cn2 = DriverManager.getConnection("jdbc:mysql:///db1?useSSL=false", "root", "root");

// 3.获取运送SQL的对象
Statement state = cn.createStatement();

ResultSet executeQuery(String sql)

用于执行查询语句; 返回查询到的结果集

int executeUpdate(String sql)

用于执行除查询外的SQL; 返回影响的行数

 // 1.注册驱动(自动注册)
// 2.获取Connection连接
Connection cn = DriverManager.getConnection("jdbc:mysql://localhost:3306/db1",
                "root", "root");
// 3.获取Statement(小货车)
Statement state = cn.createStatement();
// 4.执行SQL语句
String sql = "insert into user values (null,'NAME','1234');";
// 返回影响的行数
int row = state.executeUpdate(sql);
// 5.处理结果
System.out.println("row = " + row);
// 6.释放资源
state.close();
cn.close();

查询对象直接输出

boolean   next()

将光标从当前位置向前移动一行 ,判断当前行是否为有效行,true:有效行,当前行有数据

boolean getBoolean​(String columnLabel)

获取boolean

byte getByte​(String columnLabel)

获取byte

double getDouble​(String columnLabel)

获取double

int getInt​(String columnLabel)

获取int

long getLong​(String columnLabel)

获取long

String getString​(String columnLabel)

获取String

// 4.执行SQL语句
String sql = "SELECT * FROM user;";
// executeQuery查询
ResultSet rs = state.executeQuery(sql);
// 5.处理结果
// System.out.println("rs = " + rs);
while (rs.next()){
    // 获取这一行的数据
    int id = rs.getInt("id");
    String name = rs.getString("name");
    String password = rs.getString("password");
    System.out.println("id:" + id + ",name:" + name + ",password:" + password);
}
// 6.关闭资源
rs.close();
state.close();
cn.close();

查询内容封装成对象

// 4.执行SQL语句
String sql = "SELECT * FROM user;";
ResultSet rs = state.executeQuery(sql);
// 5.处理结果
// System.out.println("rs = " + rs);
List list = new ArrayList<>();
while (rs.next()){
    // 获取这一行的数据
    int id = rs.getInt("id");
    String name = rs.getString("name");
    String password = rs.getString("password");
    // System.out.println("id:" + id + ",name:" + name + ",password:" + password);
    // 封装成对象来使用
    User user = new User(id, name, password);
    list.add(user);
}

事务

void setAutoCommit(boolean autoCommit)

false:开启事务, ture:关闭事务

void commit()

提交事务

void rollback()

回滚事务

public class Demo05 {
	public static void main(String[] args) {
	    // 作用域问题,定义在try之外
        Connection cn = null;
        Statement state = null;
        try {
            // 1.注册驱动(自动注册)
            // 2.获取链接
            cn = DriverManager.getConnection("jdbc:mysql://localhost:3306/db1",
                    "root", "root");
            // 3.开启事务 false为开启事务,true为关闭事务
            cn.setAutoCommit(false);
            // 4.获取到Statement
            state = cn.createStatement();
            // 5.Statement执行SQL
            // id1-500
            state.executeUpdate("update account set balance = balance - 500 where id = 1");
            // id2+500
            // 计算异常
            // int a  = 10/0;
            state.executeUpdate("update account set balance = balance + 500 where id = 2");
            // 6.成功提交事务
            cn.commit();
            System.out.println("事务提交成功!");

        } catch (Exception throwables) {
            // 6.失败回滚事务
            // 回滚事务也可能失败,重试机制,记录信息,手动回滚
            try {
                if (cn!=null){
                    cn.rollback();
                }
                System.out.println("事务失败回滚");
            } catch (SQLException e) {
                e.printStackTrace();
            }
            throwables.printStackTrace();
        } finally {
            // 关闭资源
            try {
                if (state !=null){
                    state.close();
                }
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
            try {
                if (cn!=null){
                    cn.close();
                }
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
    }
}

2 登录

// 1.使用数据库保存用户的账号和密码
// 2.让用户输入账号和密码
Scanner sc = new Scanner(System.in);
System.out.println("请输入账号:");
String name = sc.nextLine();
System.out.println("请输入密码:");
String password = sc.nextLine();
// 3.使用SQL根据用户的账号和密码去数据库查询数据
// 3.1获取连接
Connection cn = DriverManager.getConnection("jdbc:mysql://localhost:3306/db1?useSSL=false","root", "root");
// 3.2获取Statement
Statement state = cn.createStatement();
// 3.3编写SQL语句,执行
String sql = "select * from user where name = '"+ name +"' and password = '"+ password +"';";
ResultSet rs = state.executeQuery(sql);
// 4.如果查询到数据,说明登录成功
// 只要有一个数据是有的,那就可以了
if (rs.next()){
    System.out.println("欢迎你~"+name);
} else {
    // 5.如果查询不到数据,说明登录失败
    System.out.println("账号或密码错误......");
}
// 6.关闭资源
rs.close();
state.close();
cn.close();
}

3 SQL注入攻击

上面那种方法若密码输入为a'or'1'='1 也登录成功,为了解决SQL注入,引入PrepareStatement

// ?是占位符
String sql = "SELECT * FROM USER WHERE NAME=? AND PASSWORD=?;";
setXxx(参数1,参数2);

Xxx代表:数据类型,参数1:第几个?   (编号从1开始),参数2?的实际参数

int executeUpdate();  执行insertupdatedelete语句
ResultSet executeQuery();  执行select语句
        // 1.获取连接
        Connection cn = DriverManager.getConnection("jdbc:mysql://localhost:3306/db1",
                "root", "root");
        // 2.编写参数化SQL(带?的SQL语句)
        String sql = "insert into user values (null,?,?);";
        // 之前的是这样获取状态
        // Statement state = cn.createStatement();
        PreparedStatement pstate = cn.prepareStatement(sql);
        // 3.给?赋值
        pstate.setString(1,"adamin");
        pstate.setString(2,"1234");
        // 4.执行
        int row = pstate.executeUpdate();
        System.out.println("row = " + row);
        // 5.释放资源
        pstate.close();
        cn.close();

4 数据库连接池

之前JDBC访问数据库的步骤:创建数据库连接→运行SQL语句→关闭连接

缺点:

  • 每次数据库访问执行这样重复的动作
  • 获取数据库连接需要消耗比较多的资源,而每次操作都要重新获取新的连接对象,
  • 执行一次操作就把连接关闭,而数据库创建连接通常需要消耗相对较多的资源。这样数据库连接对象的使用率低

连接池的概念: 连接池就是一个容器,连接池中保存了一些数据库连接,这些连接是可以重复使用的。

连接池的原理

  1. 启动连接池,连接池就会初始化一些连接
  2. 当用户需要使用数据库连接,直接从连接池中取出
  3. 当用户使用完连接,会将连接重新放回连接池中

连接池优点

  • 连接池中会保存一些连接,这些连接可以重复使用,降低数据资源的消耗

常见的连接池实现组件

  • 阿里巴巴-德鲁伊Druid连接池:Druid是阿里巴巴开源平台上的一个项目
  • C3P0是一个开源的连接池,目前使用它的开源项目有HibernateSpring等。
  • DBCP(DataBase Connection Pool)数据库连接池,是Tomcat使用的连接池组件。

Druid连接池

initialSize

刚启动连接池时,连接池中包含连接的数量

maxActive

连接池中最多可以放多少个连接

maxWait

获取连接时最大等待时间,单位毫秒

Druid连接池在创建的时候需要一个Properties对象来设置参数,所以我们使用properties文件来保存对应的参数。Druid连接池的配置文件名称随便,放到src目录下面方便加载

druid.properties文件内容

url=jdbc:mysql://localhost:3306/database1?useSSL=false
username=root
password=root
driverClassName=com.mysql.jdbc.Driver
initialSize=5
maxActive=10
maxWait=2000

Druid连接池使用步骤

  1. 导入druid-1.0.0.jarjar
  2. 复制druid.properties文件到src下,并设置对应参数
  3. 加载properties文件的内容到Properties对象中
  4. 创建Druid连接池,使用配置文件中的参数
  5. 从Druid连接池中取出连接
  6. 执行SQL语句
  7. 关闭资源
// 3.加载properties文件的内容到Properties对象中
Properties pp = new Properties();
FileInputStream fis = new FileInputStream("项目的名称\\src\\druid.properties");
pp.load(fis);
// 4.创建Druid连接池,使用配置文件中的参数
DataSource ds = DruidDataSourceFactory.createDataSource(pp);
// 5.从Druid连接池中取出连接
Connection cn = ds.getConnection();
// 6.执行SQL语句,预编译的方式
String sql = "insert into user values (null,?,?);";
// 6.1 创建预编译的对象
PreparedStatement pstate = cn.prepareStatement(sql);
pstate.setString(1,"name1");
pstate.setString(2,"1234");
int row = pstate.executeUpdate();
// 7.关闭资源
pstate.close();
// 这里的close不是关闭连接,而是放回连接池
cn.close();
fis.close();

数据库连接池工具类

// 数据库连接池的工具类
public class DruidDataUtils {
    // 静态资源可以被使用
    public static DataSource ds = null;

    // 如果资源只需要加载一次,后续使用的都是同样的资源,可以直接写在静态代码块里面
    static{
        try {
            // 3.加载properties文件的内容到Properties对象中
            Properties pp = new Properties();
            FileInputStream fis = new FileInputStream("项目的名称\\src\\druid.properties");
            pp.load(fis);
            // 4.创建Druid连接池,使用配置文件中的参数
            ds = DruidDataSourceFactory.createDataSource(pp);
            fis.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 提供给别人获取连接池中连接的方法,工具类中方法经常被别人调用,一般谁调用谁处理
    public static Connection getConnection() throws Exception {
        return ds.getConnection();
    }
}

使用

// Druid连接池抽象类
Connection cn = DruidDataUtils.getConnection();
// 执行SQL语句,预编译的方式
String sql = "insert into user values (null,?,?);";
// 创建预编译的对象
PreparedStatement pstate = cn.prepareStatement(sql);
pstate.setString(1,"name");
pstate.setString(2,"1234");
int row = pstate.executeUpdate();
System.out.println(row);
// 关闭资源
pstate.close();
cn.close();

查询数据

// 品牌类
public class Brand {
  private Integer id;
  private String brandName;
  private String companyName;
  private Integer ordered;
  private String description;
  private Integer status;
  public Brand() {
    }
  public Brand(Integer id, String brandName, String companyName, Integer ordered, String description, Integer status) {
        this.id = id;
        this.brandName = brandName;
        this.companyName = companyName;
        this.ordered = ordered;
        this.description = description;
        this.status = status;
    }
...
}
public static void queryAll() throws Exception {
        // 1.获取连接
        Connection cn = DruidDataUtils.getConnection();
        // 2.编写SQL语句
        String sql = "SELECT * FROM tb_brand;";
        // 3.生成对应的预编译对象
        PreparedStatement pstate = cn.prepareStatement(sql);
        // 4.执行SQL
        ResultSet rs = pstate.executeQuery();
        List list = new ArrayList<>();
        // 5.处理返回的结果
        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(id, brandName, companyName, ordered, description, status);
            list.add(brand);
        }
        // 6.释放资源
        rs.close();
        pstate.close();
        cn.close(); // 还
        list.forEach(System.out::println);
    }

添加数据

public static void add() throws Exception {
        // 1.获取连接
        Connection cn = DruidDataUtils.getConnection();
        // 2.编写SQL语句
        String sql = "insert into tb_brand values (null,?,?,?,?,?);";
        // 3.生成对应的预编译对象
        PreparedStatement pstate = cn.prepareStatement(sql);
        // 3.1 设置?参数
        pstate.setString(1,"品牌名称1");
        pstate.setString(2,"企业名称1");
        pstate.setInt(3,1); // 排序
        pstate.setString(4,"这是备注信息");
        pstate.setInt(5,1); // 当前状态
        // 4.执行SQL
        int row = pstate.executeUpdate();
        // 5.处理返回的结果
        System.out.println(row);
        // 6.释放资源
        pstate.close();
        cn.close();
    }

修改数据

public static void update() throws Exception {
        // 1.获取连接
        Connection cn = DruidDataUtils.getConnection();
        // 2.编写SQL语句
        String sql = "update tb_brand set brand_name=?,company_name=?," +
                "ordered=?,description=?,status=? where id = ?";
        // 3.生成对应的预编译对象
        PreparedStatement pstate = cn.prepareStatement(sql);
        // 3.1 设置?参数
        pstate.setString(1,"品牌名称11");
        pstate.setString(2,"企业名称11");
        pstate.setInt(3,2);
        pstate.setString(4,"备注信息111");
        pstate.setInt(5,1);
        pstate.setInt(6,1);
        // 4.执行SQL
        int row = pstate.executeUpdate();
        // 5.处理返回的结果
        System.out.println(row);
        // 6.释放资源
        pstate.close();
        cn.close();
    }

删除数据

 public static void delete() throws Exception {
        // 1.获取连接
        Connection cn = DruidDataUtils.getConnection();
        // 2.编写SQL语句
        String sql = "DELETE FROM tb_brand WHERE id = ?;";
        // 3.生成对应的预编译对象
        PreparedStatement pstate = cn.prepareStatement(sql);
        // 3.1 设置?参数
        pstate.setInt(1,3);
        // 4.执行SQL
        int row = pstate.executeUpdate();
        // 5.处理返回的结果
        System.out.println("row = " + row);
        // 6.释放资源
        pstate.close();
        cn.close();
    }

你可能感兴趣的:(数据库)