首页 > 其他分享 >JDBC详解

JDBC详解

时间:2024-03-22 13:33:23浏览次数:14  
标签:JDBC String Driver connection 详解 mysql new properties

文章目录

JDBC

JDBC是Java提供的一套用于数据库操作的接口API,Java程序员只需要面向这套接口编程即可。不同的数据库厂商需要针对这套接口提供不同的实现。

请添加图片描述

快速入门

需要先引入驱动jar包mysql-connector-java

public static void main(String[] args) throws Exception {
    Driver driver = new Driver(); // 获取驱动
    String url = "jdbc:mysql:///user";
    Properties properties = new Properties();
    // user=root password=xxx
    properties.load(new FileInputStream("src/main/java/com/lhs/mysql.properties")); 
    Connection connect = driver.connect(url, properties); // 获取连接
    String sql = "insert into tb_user(username,address) values('lxg','tj');";
    Statement statement = connect.createStatement(); //拿到可以执行sql语句的句柄
    int i = statement.executeUpdate(sql); // 返回影响的行数
    System.out.println(i); // 1
    //关闭连接资源
    statement.close();
    connect.close();
}

获取数据库连接 4 种方式

方式一:获取Driver实现类对象

Driver driver = new Driver();
String url = "jdbc:mysql:///user";
Properties properties = new Properties();
properties.load(new FileInputStream("src/main/java/com/lhs/mysql.properties"));
Connection connect = driver.connect(url, properties);
System.out.println(connect);
connect.close();

方式二:使用反射动态加载

Class<?> aClass = Class.forName("com.mysql.cj.jdbc.Driver");
Driver driver = (Driver)aClass.newInstance();
String url = "jdbc:mysql:///user";
Properties properties = new Properties();
properties.load(new FileInputStream("src/main/java/com/lhs/mysql.properties"));
Connection connect = driver.connect(url, properties);
System.out.println(connect);
connect.close();

方式三:使用DriverManager替换Driver

DriverManager可以注册多个驱动,并且会自动选择合适的驱动来创建连接。在需要支持多种数据库时,使用DriverManager可以让代码更加灵活,更易于管理和维护。

Class<?> aClass = Class.forName("com.mysql.cj.jdbc.Driver");
Driver driver = (Driver)aClass.newInstance();
String url = "jdbc:mysql:///user";
Properties properties = new Properties();
properties.load(new FileInputStream("src/main/java/com/lhs/mysql.properties"));
DriverManager.registerDriver(driver);
Connection connection = DriverManager.getConnection(url, properties);
System.out.println(connection);
connection.close();

方式四:使用DriverManager自动完成注册

Class<?> aClass = Class.forName("com.mysql.cj.jdbc.Driver");
Driver driver = (Driver)aClass.newInstance();
String url = "jdbc:mysql:///user";
String user = "root";
String password = "xxx";
Connection connection = DriverManager.getConnection(url,user,password);
System.out.println(connection);
connection.close();

ResultSet结果集

ResultSet表示数据表的结果集,通过select查询语句生成。

ResultSet对象保存一个光标指向其当前的数据行。最初,光标位于第一行之前。

next方法将光标移动到下一行,若下一行没有数据则返回false,因此可以在while循环中遍历结果集

代码示例

Class<?> aClass = Class.forName("com.mysql.cj.jdbc.Driver");
Driver driver = (Driver)aClass.newInstance();
String url = "jdbc:mysql:///user";
Properties properties = new Properties();
properties.load(new FileInputStream("src/main/java/com/lhs/mysql.properties"));
DriverManager.registerDriver(driver);

Connection connection = DriverManager.getConnection(url, properties);
Statement statement = connection.createStatement();
String sql = "select * from tb_user";

ResultSet resultSet = statement.executeQuery(sql);
while (resultSet.next()) {
    int id = resultSet.getInt("id");
    String name = resultSet.getString("username");
    String address = resultSet.getString("address");
    System.out.println(id + " " + name + " " +address);
}

statement.close();
connection.close();

Statement和PreparedStatement

Statement对象用于执行静态SQL语句并返回其生成的结果的对象。

但Statement执行SQL语句时存在SQL注入的风险。

PreparedStatement采用预处理的机制来解决SQL注入的问题。

PreparedStatement执行的SQL语句中的参数用(?)来表示,调用PreparedStatement对象的setXxx()方法来设置这些参数。

预处理机制

当我们使用PreparedStatement对象执行SQL语句时,该SQL语句会被发送到数据库服务器,数据库服务器会对SQL语句进行解析,确定SQL语句的语义,然后编译SQL语句,并生成执行计划。这个过程只在第一次执行该SQL语句时进行,生成的执行计划会被缓存起来,以后再执行相同的SQL语句,就直接使用缓存的执行计划,不需要再次解析和编译,从而提高了执行效率。

预处理的优势:

  • 不再使用 + 拼接sql语句,减少语法错误。
  • 有效的解决了sql注入问题。
  • 大大减少了编译次数,效率较高。

PreparedStatement代码

Class<?> aClass = Class.forName("com.mysql.cj.jdbc.Driver");
Driver driver = (Driver)aClass.newInstance();
String url = "jdbc:mysql:///user";
Properties properties = new Properties();
properties.load(new FileInputStream("src/main/java/com/lhs/mysql.properties"));
DriverManager.registerDriver(driver);

Connection connection = DriverManager.getConnection(url, properties);

String sql = "select * from tb_user where id = ? and username = ?";
PreparedStatement preparedStatement = connection.prepareStatement(sql);
preparedStatement.setInt(1,109);
preparedStatement.setString(2,"lhs123");

ResultSet resultSet = preparedStatement.executeQuery();

while (resultSet.next()) {
    int id = resultSet.getInt("id");
    String name = resultSet.getString("username");
    String address = resultSet.getString("address");
    System.out.println(id + " " + name + " " +address);
}

preparedStatement.close();
connection.close();

封装 JDBCUtils

在jdbc操作中,获取连接和释放资源是经常用到的,可以将其封装成工具类。

public class JDBCUtils {
    private static Properties properties;
    private static String url;
    static {
        try {
            Class<?> aClass = Class.forName("com.mysql.cj.jdbc.Driver");
            Driver driver = (Driver)aClass.newInstance();
            url = "jdbc:mysql:///user";
            properties = new Properties();
            properties.load(new FileInputStream("src\\main\\java\\com\\lhs\\mysql.properties"));
            DriverManager.registerDriver(driver);
        } catch (Exception e) {
            //在实际开发中,我们可以这样处理
            //1. 将编译异常转成 运行异常
            //2. 调用者,可以选择捕获该异常,也可以选择默认处理该异常,比较方便. 
            throw new RuntimeException(e);
        }
    }
    //连接数据库, 返回 Connection
    public static Connection getConnection(){
        try {
            return DriverManager.getConnection(url,properties);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    //关闭相关资源
    /*
    1.	ResultSet 结果集
    2.	Statement 或者 PreparedStatement
    3.	Connection
    4.	如果需要关闭资源,就传入对象,否则传入 null
	*/

    public static void close(ResultSet resultSet, Statement statement, Connection connection){
        try {
            if(resultSet != null){
                resultSet.close();
            }
            if(statement != null){
                statement.close();
            }
            if(connection != null){
                connection.close();
            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }
}

测试:

Connection connection = JDBCUtils.getConnection();
String sql = "select * from tb_user";
PreparedStatement preparedStatement = connection.prepareStatement(sql);
ResultSet resultSet = preparedStatement.executeQuery();
while (resultSet.next()){
    int id = resultSet.getInt("id");
    String name = resultSet.getString("username");
    String address = resultSet.getString("address");
    System.out.println(id + " " + name + " " + address);
}
JDBCUtils.close(resultSet,preparedStatement,connection);

事务

JDBC程序中当一个Connection对象创建时,默认情况下是自动提交事务的。

调用Connection的**setAutoCommit(false)**可以取消自动提交事务。

在所有SQL语句都成功执行后,调用Connection的**commit()**方法提交事务。

在其中某个操作失败或出现异常时,调用Connection的**rollback()**方法回滚事务。

Connection connection = null;
PreparedStatement preparedStatement = null;
try {
    connection = JDBCUtils.getConnection();
    //取消自动提交事务
    connection.setAutoCommit(false);
    String sql1 = "update tb_user set address = 'bj' where id = 1";
    preparedStatement = connection.prepareStatement(sql1);
    preparedStatement.execute();
    String sql2 = "update tb_user set address = 'sh' where id = 2";
    preparedStatement.execute(sql2);
    //提交事务
    connection.commit();
}catch (Exception e){
    //若执行失败则回滚
    connection.rollback();
    System.out.println(e);
}finally {
    JDBCUtils.close(null,preparedStatement,connection);
}

批量处理

当需要成批插入或者更新记录时。可以采用Java的批量更新机制,这一机制允许多条语句一次性提交给数据库批量处理。通常情况下效率会比单独提交高。

JDBC连接MySQL时,如果要使用批量处理功能,需要在url中添加?rewriteBatchedStatements=true

JDBC的批量处理语句包括下面方法:

1)addbatch():添加需要批量处理的SQL语句或参数。

2)executeBatch():执行批量处理语句。

3)clearBatch():清空批量处理包的语句。

Connection connection = null;
PreparedStatement preparedStatement = null;
try {
    connection = JDBCUtils.getConnection();
    String sql = "insert into tb_user(username,address) values(?,?)";
    preparedStatement = connection.prepareStatement(sql);
    for (int i = 0; i < 10000; i++) {
        preparedStatement.setString(1,"lxg" + i);
        preparedStatement.setString(2,"tj");
        preparedStatement.addBatch();
        // 每添加2000条语句执行一次
        if(i % 2000 == 0){
            preparedStatement.executeBatch();
            preparedStatement.clearBatch();
        }
    }
}catch (Exception e){
    System.out.println(e);
}finally {
    JDBCUtils.close(null,preparedStatement,connection);
}

数据库连接池

数据库连接池用于管理数据库连接,以提高数据库访问的性能和效率。连接池会在应用程序启动时创建一定数量的数据库连接,并将这些连接保存在池中。当应用程序需要访问数据库时,它会从连接池中获取一个可用的连接,使用完毕后再将连接放回连接池,而不是每次都重新创建和销毁连接。

C3P0

C3P0数据库连接池速度相对较慢,稳定性不错,是spring框架默认使用的连接池。

连接方式一
//1. 创建一个数据源对象
ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
//2. 通过配置文件 mysql.properties  获取相关连接的信息
Properties properties = new Properties();
properties.load(new FileInputStream("src\\main\\java\\com\\lhs\\mysql.properties"));
//读取相关的属性值
String user = properties.getProperty("user");
String password = properties.getProperty("password");
String url = properties.getProperty("url");
String driver = properties.getProperty("driver");
//给数据源 comboPooledDataSource 设置相关的参数
//注意:连接管理是由 comboPooledDataSource 来管理
comboPooledDataSource.setDriverClass(driver);
comboPooledDataSource.setJdbcUrl(url);
comboPooledDataSource.setUser(user);
comboPooledDataSource.setPassword(password);
//设置初始化连接数
comboPooledDataSource.setInitialPoolSize(10);
//最大连接数
comboPooledDataSource.setMaxPoolSize(50);
//测试连接池的效率, 测试对 mysql 5000 次操作
long start = System.currentTimeMillis(); for (int i = 0; i < 5000; i++) {
    Connection connection = comboPooledDataSource.getConnection(); //这个方法就是从 DataSource 接口实现的
    connection.close();
}
long end = System.currentTimeMillis();
System.out.println("c3p0 5000 连接 mysql  耗时=" + (end - start));
方式二:使用配置文件

创建c3p0-config.xml文件

<c3p0-config>

    <named-config name="hello"> 
        <!-- 驱动类 -->
        <property name="driverClass">com.mysql.jdbc.Driver</property>
        <!-- url-->
        <property name="jdbcUrl">jdbc:mysql://127.0.0.1:3306/user</property>
        <!-- 用户名 -->
        <property name="user">root</property>
        <!-- 密码 -->
        <property name="password">xxx</property>
        <!-- 每次增长的连接数-->
        <property name="acquireIncrement">5</property>
        <!-- 初始的连接数 -->
        <property name="initialPoolSize">10</property>
        <!-- 最小连接数 -->
        <property name="minPoolSize">5</property>
        <!-- 最大连接数 -->
        <property name="maxPoolSize">10</property>

        <!-- 可连接的最多的命令对象数 -->
        <property name="maxStatements">5</property> 

        <!-- 每个连接对象可连接的最多的命令对象数 -->
        <property name="maxStatementsPerConnection">2</property>
    </named-config>
</c3p0-config>
ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource("c3p0-config.xml");

long start = System.currentTimeMillis(); for (int i = 0; i < 5000; i++) {
    Connection connection = comboPooledDataSource.getConnection(); //这个方法就是从 DataSource 接口实现的
    connection.close();
}
long end = System.currentTimeMillis();
System.out.println("c3p0 5000 连接 mysql  耗时=" + (end - start));

Druid(德鲁伊)

导入相关jar包并加入配置文件到src目录下

#key=value
driverClassName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/user?rewriteBatchedStatements=true
username=root
password=xxx
#initial connection Size
initialSize=10
#min idle connecton size
minIdle=5
#max active connection size
maxActive=20
#max wait time (5000 mil seconds)
maxWait=5000
Properties properties = new Properties();
properties.load(new FileInputStream("src\\main\\java\\com\\lhs\\druid.properties"));


//4. 创建一个指定参数的数据库连接池, Druid 连接池
DataSource dataSource =
    DruidDataSourceFactory.createDataSource(properties);


long start = System.currentTimeMillis(); for (int i = 0; i < 5000; i++) {
    Connection connection = dataSource.getConnection(); 
    connection.close();
}
long end = System.currentTimeMillis();
System.out.println("druid 5000 连接 mysql  耗时=" + (end - start));

Apache—DBUtils

使用select查询语句可得到resultSet,但关闭连接后就无法使用resultSet,并且resultSet不利于数据管理。

DBUtils能将查询的结果保存到映射类中并封装成集合返回。

1)要使用Apache—DBUtil,首先需要在项目中引入相关的依赖。

<dependency>
    <groupId>commons-dbutils</groupId>
    <artifactId>commons-dbutils</artifactId>
    <version>1.8.1</version>
</dependency>

2)创建与表数据相映射的类

public class User implements Serializable {
    private int id;
    private String username;
    private String address;

    public User() {
    }

    public User(int id, String username, String address) {
        this.id = id;
        this.username = username;
        this.address = address;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String name) {
        this.username = name;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "User{" +
            "id=" + id +
            ", name='" + username + '\'' +
            ", address='" + address + '\'' +
            '}';
    }
}

3)使用DBUtils查询数据

Connection connection = JDBCUtils.getConnection();
QueryRunner queryRunner = new QueryRunner();
String sql = "select * from tb_user where id < 100";
// 若查询单条数据可使用BeanHandler,返回单个对象。
List<User> userlist = queryRunner.query(connection,sql, new BeanListHandler<>(User.class));
for (User user : userlist) {
    System.out.println(user);
}
JDBCUtils.close(null,null,connection);

DAO

DAO(Data Access Object)是一种设计模式,用于将应用程序的业务逻辑和数据访问逻辑分离。DAO 主要负责封装对数据的访问和操作,隐藏了底层数据库操作的细节,使业务逻辑与数据访问逻辑解耦,提高了代码的可维护性和可测试性。

我们可以将增删改查的方法封装到dao中,使用时直接调用dao方法传入参数即可。

public class UserDao {
    private Connection connection;

    public UserDao(Connection connection) {
        this.connection = connection;
    }
    public List<User> getAllUsers() {
        List<User> userList = new ArrayList<>();
        String query = "SELECT * FROM users";

        try (PreparedStatement statement = connection.prepareStatement(query);
             ResultSet resultSet = statement.executeQuery()) {
            while (resultSet.next()) {
                int id = resultSet.getInt("id");
                String name = resultSet.getString("name");
                int age = resultSet.getInt("age");
                User user = new User(id, name, age);
                userList.add(user);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }

        return userList;
    }
}

标签:JDBC,String,Driver,connection,详解,mysql,new,properties
From: https://blog.csdn.net/weixin_74144099/article/details/136938190

相关文章

  • Raku教程值运算符详解
    文章目录简介数值和字符串运算比较类型转换构造数据高级运算符简介raku中提供了非常多的运算符操作,除了常见的数值和逻辑上的计算之外,对于类型转换、数据生成等常用操作,也提供了相应的运算符。此外,运算符作用在变量或字面量的不同位置,可能会产生不同的结果,据此可将......
  • Linux mke2fs命令教程:创建和管理你的ext2/ext3/ext4文件系统(附案例详解和注意事项)
    Linuxmke2fs命令介绍mke2fs(makeext2filesystem)命令是用来创建ext2/ext3/ext4文件系统的。它通常在磁盘分区上创建文件系统,设备是对应设备的特殊文件(例如/dev/hdXX)。如果省略了块数,mke2fs会自动计算文件系统的大小。Linuxmke2fs命令适用的Linux版本mke2fs命令在所有......
  • Linux hdparm命令教程:优化硬盘性能和读写速度(附实例详解和注意事项)
    Linuxhdparm命令介绍hdparm是一个用于控制和配置硬盘驱动器的命令行工具。它允许您查看和修改硬盘的参数,包括缓存设置、高级电源管理、硬盘性能等。通过hdparm,您可以优化硬盘的读写速度和性能。Linuxhdparm命令适用的Linux版本hdparm在大多数Linux发行版中都可用,......
  • 结构体&&联合&&枚举(详解版)
    1.结构体    1.结构体的声明structtag{member-list;}variable-list;    2.结构体的特殊声明struct{inta;charb;floatc;}x;struct{inta;charb;floatc;}a[20],*p;                 上述代码属于匿名结构体类型......
  • 邻接矩阵详解
    邻接矩阵是图论中用于表示图(Graph)结构的一种重要数据结构,特别适用于表示顶点之间连接关系的图形。在计算机科学和数学领域,它被广泛应用来编码无向图和有向图的信息。对于一个具有n个顶点的图G=(V,E),邻接矩阵是一个n×n的矩阵A,其中的行和列分别对应着图中的每个顶点。矩......
  • burpsuit插件Turbo Intruder:突破速率限制详解
    一、插件介绍Turbo Intruder是一个BurpSuite扩展插件,用于发送大量HTTP请求并分析结果,可拥抱十亿请求攻击。它旨在处理那些需要异常速度、持续时间或复杂性的攻击来补充Burp Intruder。二、插件原理使用第一次请求的时候就建立好连接,后续获取资源都是通过这条连接来获取资......
  • 对象Constructor构造函数解析详解
    构造函数解析构造函数解析示例,code如下。定义实体类:packagecom.gientech.constructor;publicclassPerson{privateStringname;privateintid;privateintage;privateStringsex;publicPerson(){}publicPerson(String......
  • 二叉树详解
    二叉树详解一:什么是树1:概念2:树的特点##3:树的一些重要概念二:二叉树1:二叉树的概念2:二叉树的特点3:特殊的二叉树:三:二叉树的性质四:二叉树的存储一:什么是树1:概念树是一种非线性的数据结构,它是由n个节点组成的一个具有层次关系的集合,把它叫做树的原因是因......
  • 开源一个教学型分库分表示例项目 shardingsphere-jdbc-demo
    在笔者心中,消息队列,缓存,分库分表是高并发解决方案三剑客。分库分表之所以被广泛使用,因为工程相对简单,但分库分表并不仅仅是分片,还是需要考虑如何扩缩容(全量同步、增量同步、数据校验等)。因此笔者做了一个教学型分库分表示例项目,计划将分库分表的技术体系都实际演示一遍。ht......
  • ConcurrentHashMap底层详解
    ConcurrentHashMap是线程安全且高效的HashMap。一、使用原因在并发编程中使用HashMap可能导致程序死循环。而使用线程安全的HashTable效率又非常低下,基于此产生了ConcurrentHashMap。1.线程不安全的HashMap在多线程环境下,使用HashMap进行put操作会引起死循环,导致CPU利用率......