• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

java_JDBC,连接数据库方式,RestSet结果集,Statement,PreparedStatement,事务,批 ...

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

一、JDBC的概述

1.JDBC为访问不同的数据薛是供了统一的接口,为使用者屏蔽了细节问题。
2. Java程序员使用JDBC,可以连接任何提供了JDBC驱动程序的数据库系统,从而完成对数据库的各种操作。

 

 二。JDBC带来的好处

java程序可以直接对数据库进行调用,但是没有很好的移植性(对用于不同的数据库),所以不推荐

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

 

 JDBC API:JDBC API 是一系列的接口,它统一和规范了应用程序与数据库的连接,执行SQL语句,并得到返回结果等各类操作;

 

 JDBC程序编写步骤

1、注册驱动 --- 加载Driver类

2、获取连接 --- 得到Connection

3、执行增删改查 --- 发送Sql给mysql执行

4、释放资源 --- 关闭相关连接

 获取数据库连接的5种方式:

方式1:使用(com.mysql.jdbc.Driver)com.mysql.cj.jdbc.Driver,属于静态加载,灵活性差,依赖性强

方式2:使用反射机制,属于静态加载

 

 方式3:使用DriverManager替代driver进行统一管理

 

 方式4:使用Class.forName自动完成注册驱动,简化代码

这种方式连接是使用得最多的(推荐使用)

 

 在底层会完成注册:

 

 提示:

(1)mysql驱动5.1.6可以无需Class.forName(“com.mysql.jdbc.Driver”);

(2)从jdk1.5以后使用了jdbc4,不再需要显示调用class.forName()注册驱动而是自动调用驱动jar包下META-INF\servicesljava .sql.Driver文本中的类名称去注册

(3)建议加上Class.forName(“com.mysql.jdbc.driver”),能够更加明确的感受到程序流程,利于掌握;

方式5:利用properties文件配置数据库需要的相关的配置

更加的灵活,可以直接通过properties配置文件修改数据库连接相关的数据

 

 对方式5的实例:

//properties配置文件
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/test_db?useSSL=false&characterEncoding=utf8&serverTimezone=UTC
user=root
password=123456
//连接数据库的相关操作
import java.io.*;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;

public class jdbc02 {
    public static void main(String[] args) throws ClassNotFoundException, IOException, SQLException {
        //创建一个properties对象
        Properties properties = new Properties();
        //加载和获取创建的properties的相关数据
        properties.load(new FileInputStream("src\\db.properties"));
        String driver = properties.getProperty("driver");
        String url = properties.getProperty("url");
        String user = properties.getProperty("user");
        String password = properties.getProperty("password");

        String sql = "insert into actor values (null,'王五','男','1975-11-23','110')";

        //driver驱动,也可以不加,但是加上更容易读懂流程
        Class.forName(driver);
        //连接和执行操作
        Connection connection = DriverManager.getConnection(url, user, password);
        Statement statement = connection.createStatement();
        statement.executeUpdate(sql);
        //关闭连接
        System.out.println("连接"+connection);
        statement.close();
        connection.close();


    }
}

三、RestSet【结果集】

基本介绍:

1.表示数据库结果集的数据表,通常通过执行查询数据库的语句生成
2. ResultSet对象保持一个光标指向其当前的数据行。最初,光标位于第一行之前

3. next方法将光标移动到下一行,并且由于在ResultSet对象中没有更多行时返回
false,因此可以在while循环中使用循环来遍历结果集

简单测试:

 

 四、Statement:

基本介绍:

1.Statement对象用于执行静态SQL语句并返回其生成的结果的对象
2.在连接建立后,需要对数据库进行访问,执行命名或是SQL语句,可以通过

Statement【存在SQL注入】
PreparedStatement【预处理】
CallableStatement【存储过程】

3. Statement对象执行SQL语句,存在SQL注入风险

4.SQL注入是利用某些系统没有对用户输入的数据进行充分的检查,而在用户输入数据中注入非法的SQL语句段或命令,恶意攻击数据库。

5.要防范SQL注入,只要用 PreparedStatement(从Statement扩展而来)取
代 Statement就可以了

import java.io.*;
import java.sql.*;
import java.util.Properties;

public class jdbc02 {
    public static void main(String[] args) throws ClassNotFoundException, IOException, SQLException {
        //创建一个properties对象
        Properties properties = new Properties();
        //加载和获取创建的properties的相关数据
        properties.load(new FileInputStream("src\\db.properties"));
        String driver = properties.getProperty("driver");
        String url = properties.getProperty("url");
        String user = properties.getProperty("user");
        String password = properties.getProperty("password");

        String sql = "insert into actor values (null,'三毛','男','1975-11-23','110')";
        String sql1 = "select id,name from actor";

        //driver驱动,也可以不加,但是加上更容易读懂流程
        Class.forName(driver);
        //连接和执行操作
        Connection connection = DriverManager.getConnection(url, user, password);
        Statement statement = connection.createStatement();
//        statement.executeUpdate(sql);

//        String sql1 = "select id,name from actor";
        ResultSet resultSet = statement.executeQuery(sql1);
        while (resultSet.next()) {
            int i = resultSet.getInt(1);
            String string1 = resultSet.getString(2);
            System.out.println(i+"=="+string1);
        }
        //关闭连接
        resultSet.close();
        System.out.println("连接"+connection);
        statement.close();
        connection.close();


    }
}

 

PrepareStatement:

1. PreparedStatement 执行的SQL语句中的参数用问号(?)来表示,调用
PreparedStatement对象的setXxx()方法来设置这些参数. setXxx()方法有两个参数,第一个参数是要设置的SQL语句中的参数的索引(从1开始),第二个是设置的SQL语句中的参数的值
2.调用executeQuery),返回ResultSet 对象
3.调用executeUpdate):执行更新,包括增、删、修改

预处理的好处:

1.不再使用+拼接sql语句,减少语法错误

2.有效的解决了sql注入问题!
3.大大减少了编译次数,效率较高

 对preparestatement的测试代码,配置文件还是上面的配置文件

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Properties;

public class PrepareStatement {
    public static void main(String[] args) throws Exception {

        Properties properties = new Properties();
        properties.load(new FileInputStream("src\\db.properties"));
        String drive = properties.getProperty("driver");
        String url = properties.getProperty("url");
        String user = properties.getProperty("user");
        String password = properties.getProperty("password");

        //更新操作
//        String sql = "update actor set phone = ? where name = ?";
        //删除操作
//        String sql = "delete from actor where name = ?";
//        添加操作
//        String sql = "insert into actor values(null,?,?,?,?)";
//查询操作
        String sql = "select * from actor";

        Class.forName(drive);

        Connection connection = DriverManager.getConnection(url, user, password);

        PreparedStatement preparedStatement = connection.prepareStatement(sql);
        //更改操作
//        preparedStatement.setString(1, "123456");
//        preparedStatement.setString(2, "三毛");
//删除操作
//        preparedStatement.setString(1, "二狗");
//添加操作
//        preparedStatement.setString(1, "张三");
//        preparedStatement.setString(2, "男");
//        preparedStatement.setString(3, "1975-11-23 00:00:00");
//        preparedStatement.setString(4,"456789");
//        int i = preparedStatement.executeUpdate();
//        System.out.println(i >0 ? "成功" : "失败");

//查询操作
        ResultSet resultSet = preparedStatement.executeQuery();
        while (resultSet.next()) {
            System.out.println(resultSet.getString(2));
        }

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


    }
}

总结:

 

    

 

 五、事务:将多行代码当做SQL事务来处理,主要流程需要的关键代码:

connection.setAutoCommit(false);//取消自动提交的操作,取消之后,会在提及之后完成事务
connection.commit();提交事务
connection.rollback();//用于回退事务
批处理:

基本介绍:

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

2、JDBC的批量处理语句包括下面方法:
addBatch():添加需要批量处理的SQL语句或参数executeBatch(:执行批量处理语句;
clearBatch():清空批处理包的语句
3、 JDBC连接MySQL时,如果要使用批处理功能,请再url中加参
数?rewriteBatchedStatements=true
4、批处理往往和PreparedStatement一起搭配使用,可以既减少编译次数,又减少运行次数,效率大大提高

过程:

(1)将sql语句加入到批处理包中

preparedStatement.addBatch();
preparedStatement.addBatch(sql);

(2)执行sql和清空sql

//批量执行sql语句
preparedStatement.executeBatch();
//清除批量的sql语句
preparedStatement.clearBatch();

 将 SQL加入到批处理包中源码所做的事情:

 

 

六、数据库连接池

 传统connection问题分析

1.传统的JDBC数据库连接使用 DriverManager来获取,每次向数据库建立
连接的时候都要将Connection 加载到内存中,再验证IP地址,用户名和密码(0.05s~1s时间)。需要数据库连接的时候,就向数据库要求一个,频繁的进行数据库连接操作将占用很多的系统资源,容易造成服务器崩溃。2每一次数据库连接,使用完后都得断开,如果程序出现异常面未能关闭,将
导致数据库内存泄漏,最终将导致重启数据库。
3.传统获取连接的方式,不能控制创建的连接数量,如连接过多,也可能导致
内存泄漏,MySQL崩溃。
4.解决传统开发中的数据库连接问题,可以采用数据库连接池技术
(connection pool).

数据库连接池基本介绍:

1.预先在缓冲池中放入一定数量的连接,,当需
要建立数据库连接时,只需从“缓冲池”中取出一个,,使用完毕之后再放回去。
2.数据库连接池负责分配、管理和释放数据库
连接,它允许应用程序重复使用一个现有的数据库连接,而不是重新建立一个。
3.当应用程序向连接池请求的连接数超过最大
连接数量时,这些请求将被加入到等待队列中

 

 

数据库连接池示意图:

 数据库连接池种类:

1.JDBC的数据库连接池使用javax.sql.DataSource来表示,DataSource
只是一个接口,该接口通常由第三方提供实现
2.C3PO 数据库连接池,速度相对较慢,稳定性不错(hibernate, spring)

3.DBCP数据库连接池,速度相对c3p0较快,但不稳定
4. Proxool数据库连接池,有监控连接池状态的功能,稳定性较c3p0差一点

5.BoneCP数据库连接池,速度快
6.Druid(德鲁伊)是阿里提供的数据库连接池,集DBCP、C3P0、Proxool
优点于身的数据库连接池

 

 

 测试:C3P0连接池的连接(需要导入第三方库:c3p0的jar包)

第一个C3P0连接的配置文件还是上面的配置文件内容

第二个C3P0的连接需要有一个xml配置文件

import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.junit.jupiter.api.Test;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;

public class ConDatasource {
    public static void main(String[] args) throws Exception {
        Properties properties = new Properties();
        properties.load(new FileInputStream("src\\db.properties"));
        String driver = properties.getProperty("driver");
        String user = properties.getProperty("user");
        String password = properties.getProperty("password");
        String url = properties.getProperty("url");

        //建立comboPooledDataSource管理连接池
        ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();

        comboPooledDataSource.setDriverClass(driver);
        comboPooledDataSource.setJdbcUrl(url);
        comboPooledDataSource.setUser(user);
        comboPooledDataSource.setPassword(password);

        //设置初始化连接数和最大连接数
        comboPooledDataSource.setInitialPoolSize(10);
        comboPooledDataSource.setMaxPoolSize(50);
        //这个方法就是从DataSource接口实现的
        Connection connection = comboPooledDataSource.getConnection();
        System.out.println("1连接成功");
        connection.close();

    }

    @Test
    public  void ConDatasource02() throws SQLException {
        ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource("test_C3P0");

        long start = System.currentTimeMillis();
        System.out.println("测试连接5000次需要的时间");
        for (int i = 0; i < 5000; i++) {
        Connection connection = comboPooledDataSource.getConnection();
//        System.out.println("2连接成功");
        connection.close();
        }
        long end = System.currentTimeMillis();
        System.out.println("花费时长:"+(end-start));
    }
}
//第二种方式的xml文件
<c3p0-config>

  <named-config name="test_C3P0">
<!-- 驱动类 -->
  <property name="driverClass">com.mysql.cj.jdbc.Driver</property>
  <!-- url-->
      <property name="jdbcUrl">jdbc:mysql://localhost:3306/test_db?useSSL=false&amp;characterEncoding=utf8&amp;serverTimezone=UTC</property>
  <!-- 用户名 -->
          <property name="user">root</property>
          <!-- 密码 -->
      <property name="password">123456</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>

测试:Druid连接池的连接(需要第三方库druid的jar包)

package com.zjl.jdbc;

import com.alibaba.druid.pool.DruidDataSourceFactory;

import javax.sql.DataSource;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.sql.Connection;
import java.util.Properties;

public class Druidsource {
    public static void main(String[] args) throws Exception {
        Properties properties = new Properties();
        properties.load(new FileInputStream("src\\druid.properties"));//如下定义的配置文件

        DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);
        long start = System.currentTimeMillis();
        for (int i = 0;i < 500000;i++ ) {
            Connection connection = dataSource.getConnection();
            connection.close();
        }
        long end = System.currentTimeMillis();
        System.out.println("Druid连接5000 次需要的时间:" + (end - start));//Druid连接500000 次需要的时间:625
    }
}
//连接中需要的一个配置文件
druid.properties:放在src目录下

#key=value
driverClassName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/test_db?useSSL=false&characterEncoding=utf8&serverTimezone=UTC
#url=jdbc:mysql://localhost:3306/girls
username=root
password=123456
#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
 

注意:对于c3p0和Druid他们的close()是按照第三方库的连接方式,仅仅是将从连接池引用的数据库连接断开(放弃引用)

重新将连接放回到连接池中,和原生 的jdbc连接中的close方法断开连接不同;

用Druid创建一个连接和断开的工具类;

package com.zjl.jdbc;

import com.alibaba.druid.pool.DruidDataSourceFactory;

import javax.sql.DataSource;
import java.io.FileInputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;

public class JDBCUtilsByDruid {
    static DataSource ds;
    static {
        Properties properties = new Properties();

        try {
            properties.load(new FileInputStream("src\\druid.properties"));
            ds = DruidDataSourceFactory.createDataSource(properties);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
        //编写获取Connection的方法
    public static Connection getConnection() throws SQLException {
        return ds.getConnection();
    }

    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);
        }
    }
}

 

七、Apache-DBUtils

1、问题引出:在使用Druid连接数据库,返回结果集之后,如果断开连接,结果集就不能够再使用。解决方法如图,将返回的结果集保存到一个泛型列表中,那么当数据库连接断开后,还是可以使用返回的结果集。

 

 

2、对Apache-DBUtils的基本介绍

1).commons-dbutils 是 Apache组织提供的一个开源 JDBC工具类库,它是对JDBC的封装,
使用dbutils能极大简化jdbc编码的工作量[真的]。
DbUtils类
(1). QueryRunner类:该类封装了SQL的执行,是线程安全的。可以实现增、删、改、查、批处理

(2).使用QueryRunner类实现查询
(3). ResultSetHandler接口:该接口用于处理java.sql.ResultSet,将数据按要求转换为另一种形式

 对该DBUtils进行测试:需要对应的jar包(commons-dbutils-1.7.jar)可以去:http://commons.apache.org/下载

相应的JDBCUtilsByDruid类是上面的测试类:

package com.zjl.jdbc;

import com.zjl.bean.Actor;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanListHandler;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Iterator;
import java.util.List;

public class TestDBUtils {
    public static void main(String[] args) throws Exception {
        String sql = "select * from `actor`";
        //从Druid中获取一个连接
        Connection connection = JDBCUtilsByDruid.getConnection();
        //引入DBUtils的jar包,并获得一个QueryRunner对象
        QueryRunner queryRunner = new QueryRunner();

        //利用QueryRunner对象就可以直接查询数据库,执行SQl语句,返回结果封装到ArrayList集合中
        // connection是一个连接,sql是一个执行语句
        //new BeanListHandler<>(Actor.class):在将resultSet中的结果以Actor对象方式封装到ArrayList
        //底层使用反射机制,获取Actor类的属性,然后进行封装
        //1就是给sql 语句中的?赋值,可以有多个值,因为是可变参数0bject... params
//        List<Actor> list = queryRunner.query(connection, sql, new BeanListHandler<>(Actor.class), 1);
        //如果要返回单个查询数据就使用BeanHandler<>(Actor.class),返回结果就会是单个对象或者为空
        List<Actor> list = queryRunner.query(connection, sql, new BeanListHandler<>(Actor.class));
        //在底层会得到resultSet并在query中关闭,也会在底层使用preparedStatement并关闭
//        JDBCUtilsByDruid.close(null, null, connection);
        Iterator<Actor> iterator = list.iterator();
        while (iterator.hasNext()) {
            Actor next = iterator.next();
            System.out.println(next);
        }
        //进行更新操作
        String updateSql = "update `actor` set name = ? where id = ?";
        int update = queryRunner.update(connection, updateSql, "王无无", 8);
        System.out.println((update > 0) ? "更新成功" : "更新失败");
        //进行删除操作
        String delSql = "delete from `actor` where id = ?";
        int update1 = queryRunner.update(connection, delSql, 10);
        System.out.println((update > 0) ? "删除成功" : "删除失败");

        //关闭资源
        JDBCUtilsByDruid.close(null, null, connection);
    }

}

八、BasicDao--DAO和增删改查通用方法(DAO:data access object   数据访问对象)

 基本说明:

1)、 DAO:data access object数据访问对象
2)、这样的通用类,称为 BasicDao,是专门和数据库交互的,即完成对数据库(表)的crud操作。

3)、在BaiscDao的基础上,实现一张表对应一个Dao,更好的完成功能;

关系图如下:

 

 

 



 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 



 

 

 

 

 

 

 

 

 

 




鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
黄聪:用C#为Excel创建个人宏工作薄(原创)发布时间:2022-07-13
下一篇:
C++《STL源码剖析》学习-vector发布时间:2022-07-13
热门推荐
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap