JDBC总结

本文演示了如何使用Java JDBC连接MySQL数据库,包括加载驱动、创建连接、执行SQL(Statement与PreparedStatement的区别)、获取结果集以及资源释放。还介绍了事务处理的基本概念,展示了关闭自动提交、开启事务以及在事务中执行SQL的例子。最后提到了预编译SQL(PreparedStatement)以防止SQL注入,并讨论了线程池在数据库操作中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

先来看一个简单的demo

CREATE TABLE `users` (
  `id` int NOT NULL,
  `NAME` varchar(40) DEFAULT NULL,
  `PASSWORD` varchar(40) DEFAULT NULL,
  `email` varchar(60) DEFAULT NULL,
  `birthday` date DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;

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

        //用户信息和url
        String url = "jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true";
        String username = "root";
        String password = "root";
        String sql = "SELECT * FROM users";
        //连接数据库,记得释放资源
        try (Connection connection = DriverManager.getConnection(url, username, password);
             final Statement statement = connection.createStatement();
             ResultSet resultSet = statement.executeQuery(sql)) {
            //resultset第一个是头指针,是没有数据的
            while (resultSet.next()) {
                System.out.println(resultSet.getObject("id"));
            }
        }
    }
}

java连接数据库一共分为以下几步:
_
1.加载驱动
Class.forName(“com.mysql.cj.jdbc.Driver”);
_
2.连接数据库
Connection connection = DriverManager.getConnection(url, username, password);
_
3.与数据库进行交互
1)Statement
用于对数据库进行通用访问,在运行时使用静态SQL语句时很有用。 Statement接口不能接受参数。
2)PreparedStatement
当计划要多次使用SQL语句时使用。PreparedStatement接口在运行时接受输入参数。可以防止sql注入,并且效率更高。
3)CallableStatement
当想要访问数据库存储过程时使用。CallableStatement接口也可以接受运行时输入参数。
_
4.获取查询结果
ResultSet resultSet = statement.execute(sql)
ResultSet resultSet = statement.executeQuery(sql);
ResultSet resultSet = statement.executeUpdate(sql);
_
5.释放资源
用try with resource或者手动释放
if (resultSet != null) {
resultSet.close();
}
if (statement != null) {
statement.close();
}
if (connection != null) {
connection.close();
}

由于加载驱动、连接数据库还有释放资源的操作是固定的,所以我们可以把它封装到工具类中。

补充:
下面程序中获取配置文件的输入流我使用了三种方法
1.通过类加载器获取,限制是只能获取classpath下的文件(就是resources文件夹下的文件),不能用绝对路径来获取;
2.直接通过class来获取,能自动识别是相对路径还是绝对路径,path 不以’/'开头时默认是从此类所在的包下取资源,以’/'开头则是从ClassPath根下获取;
3.通过文件输入流来获取,这里是用的绝对路径。

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;

public class JDBCUtils {
    private static String driver = null;
    private static String url = null;
    private static String username = null;
    private static String password = null;

    static {
        try {
            //final InputStream inputStream = JDBCUtils.class.getClassLoader().getResourceAsStream("db.properties");
            final InputStream inputStream = JDBCUtils.class.getResourceAsStream("db.properties");
            //final InputStream inputStream = new FileInputStream(new File("/Users/riter/Documents/work/java/JDBC/src/main/resources/db.properties"));
            final Properties properties = new Properties();
            properties.load(inputStream);
            driver = properties.getProperty("driver");
            url = properties.getProperty("url");
            username = properties.getProperty("username");
            password = properties.getProperty("password");
            //驱动只用加载一次

            Class.forName(driver);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //获取连接
    public static Connection getConnection() throws SQLException {
        return DriverManager.getConnection(url, username, password);
    }

    //释放资源
    public static void release(Connection connection, Statement statement, ResultSet resultSet) throws SQLException {
        if (resultSet != null) {
            resultSet.close();
        }
        if (statement != null) {
            statement.close();
        }
        if (connection != null) {
            connection.close();
        }
    }
}

下面是配置文件

driver = com.mysql.cj.jdbc.Driver
url = jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true
username = root
password = root

然后就可以写测试了
可以看到这里的connection,statement还有resultset的值都是工具类里配置的,实现了解耦,提高了可复用性。

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;

public class TestInsert {
    public static void main(String[] args) throws Exception {
        Connection connection = null;
        Statement statement = null;
        ResultSet resultSet = null;
        connection = JDBCUtils.getConnection();
        statement = connection.createStatement();
        String sql = "INSERT INTO users ( id, `NAME`, `PASSWORD`, `email`, `birthday` )" +
                "VALUES" +
                "(" +
                "4," +
                "'hzh'," +
                "'123456'," +
                "'767641495@qq.com '," +
                "'2020-11-09')";
        final int i = statement.executeUpdate(sql);
        if (i > 0) {
            System.out.println("Success!");
        }
        JDBCUtils.release(connection, statement, resultSet);

    }
}

这样去写的话,可能会产生sql注入,所以可以考虑将statement换成preparedStatement,它会将传入的参数当作字符串,将符号进行转义。mybatis底层就是用这个来实现的,需要重点理解。

  1. 预编sql语句
  2. 参数用?代替
  3. 再用方法手动注入参数
  4. 执行sql
  5. 释放资源
import java.sql.Connection;
import java.sql.PreparedStatement;

public class TestPreoaredStatement {
    public static void main(String[] args) throws Exception {
        Connection connection = JDBCUtils.getConnection();
        //使用?占位符代替参数
        String sql = "INSERT INTO users ( id, `NAME`, `PASSWORD`, `email`, `birthday` )" +
                "VALUES" +
                "(" +
                "?," +
                "?," +
                "?," +
                "?," +
                "?)";
        //预编译sql,先写sql,但不执行
        PreparedStatement preparedStatement = connection.prepareStatement(sql);
        //手动设置参数
        //给第一个参数赋值5
        preparedStatement.setInt(1, 5);
        //依此类推
        preparedStatement.setString(2, "xiaoCai");
        preparedStatement.setString(3, "767641495");
        preparedStatement.setString(4, "767641495@qq.com");
        preparedStatement.setDate(5, new java.sql.Date(new java.util.Date().getTime()));
        //执行sql
        final int i = preparedStatement.executeUpdate();
        if (i > 0) {
            System.out.println("Success");
        }
        JDBCUtils.release(connection, preparedStatement, null);
    }
}

事务的实现

  1. 关闭自动提交(开启事务)
  2. 增删改完成后,提交
CREATE TABLE `account` (
  `id` int NOT NULL AUTO_INCREMENT,
  `name` varchar(40) DEFAULT NULL,
  `money` float DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class TestTransaction {
    public static void main(String[] args) {
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;

        try {
            connection = JDBCUtils.getConnection();
            //关闭自动提交后,自动开启事务
            connection.setAutoCommit(false);

            String sql = "update account set money = money - 100 where name = 'A' ";
            preparedStatement = connection.prepareStatement(sql);
            preparedStatement.executeUpdate();

            String sql1 = "update account set money = money + 100 where name = 'B' ";
            preparedStatement = connection.prepareStatement(sql1);
            preparedStatement.executeUpdate();

            //业务完成,提交事务
            connection.commit();
            System.out.println("Success!");
        } catch (SQLException throwable) {
            //失败就回滚
            try {
                connection.rollback();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
            throwable.printStackTrace();
        }
    }
}

最后就是线程池部分
可以使用现成的线程池,也可以自己实现DataSource接口,自己写

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值