JDBC

149 阅读5分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第1天,点击查看活动详情

JDBC简介

就是用Java语言操作关系型数据库的一套API

image.png JDBC定义了操作所有关系性数据库的规则。定义了一套标准接口。各大数据库定义实现类去实现JDBC接口

JDBC的本质:

·官方(sun公司)定义的一套操作所有关系型数据库的规则,即接口·各个数据库厂商去实现这套接口,提供数据库驱动jar包

·我们可以使用这套接口(JDBC)编程,真正执行的代码是驱动jar包中的实现类

JDBC好处

1.各数据库厂商使用相同的接口,Java代码不需要针对不同数据库分别开发

2.可随时替换底层数据库,访问数据库的Java代码基本不变

JDBC快速入门

image.png

JDBC快速入门
 */
public class jdbc {
    public static void main(String[] args) throws Exception {
        //1.注册驱动(也可以不用写)
        Class.forName("com.mysql.cj.jdbc.Driver");

        //2.获取连接
        String url = "jdbc:mysql://127.0.0.1:3306/fruitdb?";
        String user = "root";
        String password = "z15788901";
        Connection conn = DriverManager.getConnection(url, user, password);

        //3.定义sql语句
        String sql = "update t_fruit set fcount = 100 where fid = 51";

        //4.获取执行sql的对象Statement
        Statement stmt = conn.createStatement();

        //5.执行sql
        int count = stmt.executeUpdate(sql);//收影响的行数

        //6.处理结果
        System.out.println(count);

        //7.释放资源
        stmt.close();
        conn.close();
    }

第一步出现的bug

1.首先是导入jar包时,根据黑马上的视频是无法成功的(不知道为啥)。得在左上角项目结构中进行导入

2.然后是username的值,我输入的是"xiaokasidi"是无法识别的,用户名都得是root

JDBC API详解

1.DriverManager

作用:

1.注册驱动

2.获取数据库连接

DriverManager中的getConnection(url,user,password).

其中的url定义如下

image.png 获取连接步骤中如果连接的是本机mysql并且端口是默认的3306可以简化书写,即把127.0.0.1:3306去除即可

2.Connection

Connection(数据库连接对象)作用:

1.获取执行SQL的对象

image.png 2.事务管理

image.png 事务管理的三个方法代码演示如下

try {
    //开启事务
    conn.setAutoCommit(false);

    int count1 = stmt.executeUpdate(sql1);//收影响的行数
    int count2 = stmt.executeUpdate(sql1);

    System.out.println(count1);
    System.out.println(count2);

    //提交事务
    conn.commit();


} catch (Exception e) {
    conn.rollback();//回滚事务
    e.printStackTrace();
} finally {
    //7.释放资源
    stmt.close();
    conn.close();
}

做上述的目的在于为了保证在出现异常时进行回滚,防止一个修改了另一个因为异常没有修改

Statement

作用:执行sql语句

image.png 以下贴出"执行DML语句和DDL语句"的代码演示

//Statement
//执行DML语句和DDL语句
@Test
public void test() throws Exception {
   Class.forName("com.mysql.cj.jdbc.Driver");

   String url = "jdbc:mysql://127.0.0.1:3306/fruitdb?";
   String user = "root";
   String password = "z15788901";
   Connection conn = DriverManager.getConnection(url, user, password);

   String sql = "update t_fruit set fcount = 100 where fid = 51";//执行DDL语句,直接把sql语句改为DDL语句即可,如"create database db"

   Statement stmt = conn.createStatement();

   int count = stmt.executeUpdate(sql);//执行完DML语句,受影响行数
   //执行完DDL语句,count还是0
   if(count>0){
      System.out.println("修改成功");
   }else {
      System.out.println("修改失败");
   }

   stmt.close();
   conn.close();
}

ResultSet(结果集对象)

作用:

1.封装了DQL查询语句的结果

image.png

Class.forName("com.mysql.cj.jdbc.Driver");
    String url = "jdbc:mysql://127.0.0.1:3306/fruitdb?";
    String user = "root";
    String password = "z15788901";
    Connection conn = DriverManager.getConnection(url, user, password);
    //3.定义sql
    String sql = "select * from t_fruit";
    //4.获取statement对象
    Statement stmt = conn.createStatement();
    //5.执行sql
    ResultSet rs = stmt.executeQuery(sql);
    //6.遍历rs中的所有数据
    while(rs.next()){
        int fid = rs.getInt(1);//()内也可以直接填入要查询的列的名称
        String fname = rs.getNString(2);
        System.out.println(fid);
        System.out.println(fname);
        System.out.println("*****");
    }
    rs.close();
    stmt.close();
    conn.close();

}

上述代码输出的是

51 荔枝


52 苹果


练习:

image.png 思路:

查询t_fruit账户表数据,封装为t_fruit对象中,并且存储到ArrayList集合中

1.定义实体类t_fruit 2.查询数据,封装到t_fruit对象中 3.将t_fruit对象存入ArrayList集合中

代码如下

/*查询t_fruit账户表数据,封装为t_fruit对象中,并且存储到ArrayList集合中
1.定义实体类t_fruit
2.查询数据,封装到t_fruit对象中
3.将t_fruit对象存入ArrayList集合中
 */
public static void main(String[] args) throws Exception {
    Class.forName("com.mysql.cj.jdbc.Driver");
    String url = "jdbc:mysql://127.0.0.1:3306/fruitdb?";
    String user = "root";
    String password = "z15788901";
    Connection conn = DriverManager.getConnection(url, user, password);
    //3.定义sql
    String sql = "select * from t_fruit";
    //4.获取statement对象
    Statement stmt = conn.createStatement();
    //5.执行sql
    ResultSet rs = stmt.executeQuery(sql);

    //创建集合
    List<t_fruit> list = new ArrayList<>();
    while(rs.next()){
        t_fruit f = new t_fruit();
        int fid = rs.getInt(1);
        String fname = rs.getNString(2);
        int price = rs.getInt(3);

        f.setFid(fid);
        f.setFname(fname);
        f.setPrice(price);
        //存入集合中
        list.add(f);
    }
    System.out.println(list);

输出 [t_fruit{fid=51, fname='荔枝', price=10}, t_fruit{fid=52, fname='苹果', price=5}]

PreparedStatement

image.png 需求:用户登录的操作(无sql注入)

//用户登录的操作
    public static void main(String[] args) throws Exception {
        Class.forName("com.mysql.cj.jdbc.Driver");
        String url = "jdbc:mysql://127.0.0.1:3306/fruitdb?";
        String user = "root";
        String password = "z15788901";
        Connection conn = DriverManager.getConnection(url, user, password);

        //接收用户输入的用户名和密码
        String name = "xiaokasidi";
        String pwd = "z1578890";

        String sql = "select * from tb_user where username='"+name+"' and password ='"+pwd+"'";
        //获取stmt对象
        //执行sql
        Statement stmt = conn.createStatement();
        ResultSet rs = stmt.executeQuery(sql);
        //判断登录是否成功
        if(rs.next()){
            System.out.println("登录成功");
        }else{
            System.out.println("登录失败");
        }
        stmt.close();
        rs.close();
        conn.close();
    }

有sql注入,将密码改为"' or '1' = '1",那么就直接会登录成功

原因:传入Mysql中时会自动转化为or语句'1' = '1永远为true,因此都可查询出来

因此为了防止sql注入,用下列方式防止

image.png 即用问号来代替sql语句中的'"+name+"'等等,并在下文通过PreparedStatement pstmt.setString(1,字段名)(2,字段名)等等来设置问号的值。通过转义来解决sql注入的问题。

useServerPrepStmts=true来开启预编译功能

PreparedStatement的好处:

1.预编译sql,性能更高

2.防止sql注入:将敏感字符进行转义

数据库连接池简介

  • 数据库连接池是个容器,负责分配、管理数据库连接(Connection)

  • 它允许应用程序重复使用一个现有的数据库连接,而不是重新建立一个

  • 释放空闲时间超过最大空闲时间的数据库连接来避免因为没有释放数据库连接而引起的数据库连接遗漏。

  • 好处:

    • 资源重用
    • 提升系统响应速度
    • 避免数据库连接遗漏

image.png

德鲁伊方式连接数据库连接池

public static void main(String[] args) throws Exception {
    //1.导入jar包

    //2.定义配置文件

    //3.加载配置文件
    Properties prop = new Properties();
    prop.load(new FileInputStream("druid/druid.properties"));
    //4.获取连接池对象
    DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);

    //5.获取数据库连接Connection
    Connection connection = dataSource.getConnection();

    System.out.println(connection);