JDBC:Java数据库连接技术

一、JDBC概述

 1.什么是JDBC
  • JDBC(Java Data Base Connectivity),是 Java连接数据库的技术。

  • 是一种执行SQL的API, 可以为多种关系型数据库提供统一的访问。

  • 它是由一组用java语言编写的类和接口组成, 是Java访问数据库的标准规范。

 

 2.JDBC原理

 3.什么是数据库驱动

 

  • 数据库驱动就是直接操作数据库的一个程序

  • 在程序中需要依赖数据库驱动来完成对数据库的操作

 总结:JDBC就是由sun公司定义的一套操作所有关系型数据库的规则(接口), 而数据库厂商需要实现这套接口, 厂商的实现类在引入的数据库驱动jar包中。

二、JDBC实现查询

 1.引入MySQL的数据库驱动(.jar)

将MySQL的驱动jar包添加到项目中的lib文件夹, 并将jar添加到libraries。

2.实现过程
1.注册驱动

MySQL的Driver类是MySQL提供的数据库驱动类,实现了JDBC的Driver接口 

//注册驱动(使用反射)
        Class.forName("com.mysql.cj.jdbc.Driver");
2.获取数据库连接
  • JDBC提供了Connection接口, 代表一个数据库连接接口

  • MySQL通过DriverManager类中的静态方法getConnection可以获取连接

获取连接的静态方法说明
Connection getConnection(String url, String user, String password)通过数据库url、用户名和密码来获取数据库连接

 

url:连接数据库的地址,MySQL的格式为:jdbc:mysql://ip地址:端口号/数据库名

user:数据库用户名

password:数据库密码

String url="jdbc:mysql://localhost:3306/day04?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai";
        String username = "root";
        String userpwd="080900";
        Connection connection = DriverManager.getConnection(url, username, userpwd);

 

 String url = "jdbc:mysql://localhost:3306/test?useSSL=false&useUnicode=true" +
        "&characterEncoding=utf8&serverTimezone=Asia/Shanghai";

第一部分是协议 jdbc,这是固定的

第二部分是子协议,就是数据库名称

第三部分是由数据库厂商规定的

 3.获取SQL执行器

通过Connection 的 createStatement方法获取sql语句执行对象。

Connection接口中的方法说明
Statement createStatement()创建SQL语句执行对象
//3. 获取SQL语句执行对象
        Statement statement = connection.createStatement();
 4.发送sql,数据库执行sql,获取结果集

Statement对象用于发送SQL语句给MySQL服务器,执行SQL 语句并返回它所生成结果。

Statement类常用方法说明
int executeUpdate(String sql)执行insert、delete、update语句,返回int类型,代表受影响的函数
ResultSet executeQuery(String sql)执行select语句,返回ResultSet结果集对象
 //4. 执行SQL语句得到结果
        String sql = "select * from jdbc_user";
        ResultSet resultSet = statement.executeQuery(sql);
 5.处理结果集

 

//5. 遍历ResultSet结果集对象
        while(resultSet.next()){
            int id = resultSet.getInt("id");
            String username = resultSet.getString("username");
            String password1 = resultSet.getString("password");
            int age = resultSet.getInt("age");
            System.out.println("id:" + id + ", username:" + username + ", password:" + password1 + ", age:" + age);
        }
 6.资源释放
//6. 释放资源
        statement.close();
        connection.close();
 3.总结

JDBC操作步骤的总结:

  1. 加载驱动(可以省略)

  2. 获取连接

  3. 创建SQL执行器

  4. 发送SQL并执行, 拿到返回结果集

  5. 处理结果集(查询需要)

  6. 资源的释放

三、JDBC实现增删改

1.插入记录

public class Test2 {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        //1. 注册数据库驱动
        Class.forName("com.mysql.cj.jdbc.Driver");

        //2. 获取数据库连接
        String url = "jdbc:mysql://localhost:3306/test?useSSL=false&useUnicode=true" +
        "&characterEncoding=utf8&serverTimezone=Asia/Shanghai";
        Connection connection = DriverManager.getConnection(url, "root", "root3306");

        //3. 创建执行语句对象
        Statement statement = connection.createStatement();

        String sql = "insert into jdbc_user values(default,'tom','123',20)";

        //4. 执行SQL并得到结果
        int i = statement.executeUpdate(sql);

        System.out.println("受影响的行数是:" + i);

        //5. 释放资源
        statement.close();
        connection.close();
    }
}

2.修改记录

public class Test2 {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        //1. 注册数据库驱动
        Class.forName("com.mysql.cj.jdbc.Driver");

        //2. 获取数据库连接
        String url = "jdbc:mysql://localhost:3306/test?useSSL=false&useUnicode=true" +
        "&characterEncoding=utf8&serverTimezone=Asia/Shanghai";
        Connection connection = DriverManager.getConnection(url, "root", "root3306");

        //3. 创建执行语句对象
        Statement statement = connection.createStatement();

        String sql = "update jdbc_user set username='jack' where id=4";

        //4. 执行SQL并得到结果
        int i = statement.executeUpdate(sql);

        System.out.println("受影响的行数是:" + i);

        //5. 释放资源
        statement.close();
        connection.close();
    }
}

3.删除记录

public class Test2 {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        //1. 注册数据库驱动
        Class.forName("com.mysql.cj.jdbc.Driver");

        //2. 获取数据库连接
        String url = "jdbc:mysql://localhost:3306/test?useSSL=false&useUnicode=true" +
        "&characterEncoding=utf8&serverTimezone=Asia/Shanghai";
        Connection connection = DriverManager.getConnection(url, "root", "root3306");

        //3. 创建执行语句对象
        Statement statement = connection.createStatement();

        String sql = "delete from jdbc_user where id=4";

        //4. 执行SQL并得到结果
        int i = statement.executeUpdate(sql);

        System.out.println("受影响的行数是:" + i);

        //5. 释放资源
        statement.close();
        connection.close();
    }
}

四、ORM编程思想

对象关系映射(英语:Object Relational Mapping,简称ORM,或O/R mapping)是一种为了解决面向对象语言与关系数据库存在的互不匹配的现象。

五、用户登录功能

  • 需求 用户在控制台上输入用户名和密码, 显示 欢迎xxx登陆成功 或 登录失败

  • 实现思路

    1. 获取用户从控制台上输入的用户名和密码来查询数据库

    2. JDBC查询操作的6步

    3. 根据用户名和密码查询

  • 查询到记录(该用户存在), 登陆成功

  • 查询不到记录(该用户不存在), 登陆失败

 

public class Test3 {
    public static void main(String[] args) {
        Connection connection = null;
        Statement statement = null;
        try {
            Scanner scanner = new Scanner(System.in);
            System.out.println("请输入用户名:");
            String username = scanner.next();

            System.out.println("请输入密码:");
            String password = scanner.next();

            //1.注册驱动
            Class.forName("com.mysql.cj.jdbc.Driver");

            //2.获取数据库连接
            String url = "jdbc:mysql://localhost:3306/test?useSSL=false&useUnicode=true" +
        "&characterEncoding=utf8&serverTimezone=Asia/Shanghai";
            connection = DriverManager.getConnection(url, "root", "root3306");

            //3.创建执行语句对象
            statement = connection.createStatement();

            String sql = "select * from jdbc_user where username='"+username + "' and password='"+password+"'";

            //4.执行SQL得到结果集
            ResultSet resultSet = statement.executeQuery(sql);

            if(resultSet.next()){
                System.out.println("登录成功!");
            }else{
                System.out.println("登录失败!");
            }

        } catch (ClassNotFoundException | SQLException e) {
            e.printStackTrace();
        } finally {
            if(statement != null){
                try {
                    statement.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if(connection != null){
                try {
                    connection.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

 

        我们让用户输入的密码和 SQL 语句进行字符串拼接。用户输入的内容作为了 SQL 语句语法的一部分,但是改变了原有 SQL真正的意义,以上问题称为SQL注入。

SQL注入: 输入的内容作为sql执行一部分, 改变了原有sql的真正含义。

/*
        * ?:为占位符
        * */
        PreparedStatement ps = connection.prepareStatement("select * from user where username=? and password=?");
        //SQL中存在占位符,为占位符赋值
            //为第一个占位符赋值
        ps.setString(1,"zs");
            //为第二个占位符赋值
        ps.setString(2,"000000");
        //执行SQL(数据库执行sql)
        ResultSet rs = ps.executeQuery();
        ArrayList<user> list = new ArrayList<>();

六、PreparedStatement预处理对象

1. PreparedStatement接口介绍
  • PreparedStatement 是Statement 接口的子接口,继承于父接口中所有的方法。它是一个预编译的 SQL 语句对象。

  • 预编译:是指SQL 语句被预编译, 并存储在PreparedStatement 对象中。然后可以使用此对象多次高效地执行该语句。

  • 2.PreparedStatement特点
  • 因为有预先编译的功能,提高SQL的执行效率

  • 可以有效的防止SQL 注入的问题,安全性更高

3. 获取PreparedStatement对象

通过Connection创建PreparedStatement对象。

Connection接口中的方法说明
PreparedStatement prepareStatement(String sql)指定预编译的SQL语句,SQL语句中使用占位符?创建一个语句对象
 4.使用PerpareStatement对象

1.编写SQL语句, 未知内容使用 ? 占位

String sql = "select * from jdbc_user where username=? and password=?";

2.获取PreparedStatement对象

3.设置实际参数: setXxx(占位符的位置, 真实的值)

4.执行SQL

5.执行原理

6.PreparedStatement批量添加
  1. 批处理是指将关联的SQL语句组合成一个批处理,并将他们当成一次调用提交给数据库, 一次发送多个SQL语句到数据库,可以减少通信的资源消耗,从而提高了性能

  2. executeBatch() 方法用于启动执行所有组合在一起的语句。

  3. executeBatch() 方法返回一个整数数组,数组中的每个元素代表了各自的影响行数

public class Test6 {
    public static void main(String[] args) throws Exception {
        //注册驱动
        Class.forName("com.mysql.cj.jdbc.Driver");

        //获取数据库连接
        String url = "jdbc:mysql://localhost:3306/test?useSSL=false&useUnicode=true" +         "&characterEncoding=utf8&serverTimezone=Asia/Shanghai";
        Connection connection = DriverManager.getConnection(url, "root", "root3306");

        String sql = "insert into jdbc_user values(null,?,?,?)";
        //创建预编译语句对象
        PreparedStatement ps = connection.prepareStatement(sql);

        //设置参数
        ps.setString(1, "张无忌");
        ps.setString(2, "111");
        ps.setInt(3, 20);

        ps.addBatch(); //添加到批量操作

        ps.setString(1, "赵敏");
        ps.setString(2, "222");
        ps.setInt(3, 25);

        ps.addBatch(); //添加到批量操作

        //执行批量操作
        int[] ints = ps.executeBatch();
        System.out.println(Arrays.toString(ints));

        ps.close();
        connection.close();
    }
}
 7.获取自增主键值
//6.获取自增主键
        ResultSet resultSet = ps.getGeneratedKeys();
        if(resultSet.next()){
            System.out.println("主键id是:" + resultSet.getInt(1));
        }

  • 七、JDBC事务控制
 1.概述

事务(ACID): 原子性、一致性、隔离性、持久性。 ​ 事务的隔离级别:

1. 读未提交: 脏读 不可重复读 幻读

2. 读已提交: 不可重复读 幻读

3. 可重复读: 幻读

4. 串行化: 完全解决,整张表加锁, 同时只能有一个客户端操作。

 2.使用事务控制实现转账
1.思路分析
  1. 加载驱动(可以省略)

  2. 获取连接

  3. 开启事务控制

  4. 获取SQL执行器(PreparedStatement对象)

  5. 执行SQL

  6. 没出现异常, 事务提交

  7. 出现异常, 事务回滚

  8. 释放资源

2.代码实现

 

public class Test8 {
    public static void main(String[] args) {
        Connection connection = null;
        PreparedStatement ps = null;
        try {
            //1.注册驱动
            Class.forName("com.mysql.cj.jdbc.Driver");

            //2.获取数据库连接
            String url = "jdbc:mysql://localhost:3306/test?useSSL=false&useUnicode=true" +         "&characterEncoding=utf8&serverTimezone=Asia/Shanghai";
            connection = DriverManager.getConnection(url, "root", "root3306");

            //3.设置手动提交事务
            connection.setAutoCommit(false);

            String sql = "update account set money=money+? where name=?";
            //4.创建预编译语句对象
            ps = connection.prepareStatement(sql);

            //5.设置占位符参数
            ps.setInt(1, -500);
            ps.setString(2, "张三");

            //6.执行sql
            ps.executeUpdate();

            int i = 1 / 0;

            //7.设置占位符参数
            ps.setInt(1, 500);
            ps.setString(2, "李四");
            //8.执行sql
            ps.executeUpdate();

            //提交事务
            connection.commit();
        } catch (Exception e) {
            e.printStackTrace();
            try {
                //事务回滚
                connection.rollback();
            } catch (SQLException ex) {
                ex.printStackTrace();
            }
        } finally {
            if(ps != null){
                try {
                    ps.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if(connection != null){
                try {
                    connection.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

八、连接池

 1.连接池原理

        数据库连接池的基本原理是连接池对象中维护一定数量的数据库连接,并对外暴露数据库连接获取和返回方法

        外部使用者可通过getConnection 方法获取连接,使用完毕后再通closeConnection方法将连接返回,注意此时连接并没有关闭,而是放回连接池,并为下一次使用做好准备。

2.手写连接池
public class MyConnectionPool {
    private static LinkedList<Connection> list = new LinkedList<>();

    //在类加载的时候会执行,只会执行一次
    static {
        try {
            //注册驱动
            Class.forName("com.mysql.cj.jdbc.Driver");
            String url = "jdbc:mysql://localhost:3306/zqwl?useSSL=false&useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai";

            for (int i = 0; i < 50; i++) {
                //获取连接
                Connection connection = DriverManager.getConnection(url, "root", "root");
                list.add(connection);
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    //从连接池中获取连接
    public synchronized static Connection getConnection() {
        if (list.size() == 0) {
            try {
                MyConnectionPool.class.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //移除链表中头部的元素,返回值就是这个元素
        Connection connection = list.remove(0);
        return connection;
    }

    //将连接放回连接池
    public synchronized static void closeConnection(Connection connection) {
        list.add(connection);
        //唤醒等待的线程
        MyConnectionPool.class.notifyAll();
    }
}
 3.连接池的工具类
  1. C3P0数据库连接池,速度相对较慢,稳定性不错。(hibernate,spring)

  2. DBCP数据库连接池,速度相比C3P0快,但不稳定。

  3. Druid(德鲁伊)数据库连接池,是由阿里提供的连接池,及DBCP,C3P0,...优点于一身的数据库连接池。

 1.C3P0使用
//创建一个数据源对象
ComboPool edDataSource cpds = new ComboPooledDataSource();
String url = "jdbc:mysql://localhost:3306/zqwl?useSSL=false&useUnicode=true" +
    "&characterEncoding=utf8&serverTimezone=Asia/Shanghai";
String driver = "com.mysql.cj.jdbc.Driver";
String username = "root";
String password = "root";
cpds.setDriverClass(driver);
cpds.setJdbcUrl(url);
cpds.setUser(username);
cpds.setPassword(password);
//设置初始化连接数
cpds.setInitialPoolSize(10);
//最大连接数
cpds.setMaxPoolSize(50);
//测试连接池的效率, 测试对 mysql 5000 次操作
long start = System.currentTimeMillis();
for (int i = 0; i < 5000; i++) {
    Connection connection = cpds.getConnection();
    connection.close();
}
long end = System.currentTimeMillis();
System.out.println("c3p0 5000 连接 mysql 耗时=" + (end - start));
2.Druid使用
DruidDataSource dbs = new DruidDataSource();
String url = "jdbc:mysql://localhost:3306/zqwl?useSSL=false&useUnicode=true" +
    "&characterEncoding=utf8&serverTimezone=Asia/Shanghai";
String driver = "com.mysql.cj.jdbc.Driver";
String username = "root";
String password = "root";
dbs.setDriverClassName(driver);
dbs.setUrl(url);
dbs.setUsername(username);
dbs.setPassword(password);
//测试连接池的效率, 测试对 mysql 5000 次操作
long start = System.currentTimeMillis();
for (int i = 0; i < 500000; i++) {
    Connection connection = dbs.getConnection();
    connection.close();
}
long end = System.currentTimeMillis();
System.out.println("druid 5000 连接 mysql 耗时=" + (end - start));

  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值