【jdbc详解】

3 篇文章 0 订阅
3 篇文章 0 订阅

目录

一、JDBC入门

1.jdbc的概念

2.jdbc的JDBC 核心思想

3.JDBC七大步骤

1.导包

2.注册驱动

3.准备sql语句---定义String类型,里面书写插入/修改/删除

4.获取数据库的连接对象 java.sql.Connnection

5.获取执行对象执行静态sql语句

6. java.sql.ResultSet:获取数据表的结果集  (接口)

7.释放资源

二、JDBC各个功能类详解

        1.DriverManager

2.Connection

3.Statement

4.ResultSet

三、PreparedStatement预编译对象

1.使用Statement的弊端 

2.PreparedStatement

3.核心步骤

4.Statement和PreparedStatement的区别?

四、数据库的连接池

1.图解

2. 自定义连接池

2.1导包

2.2 连接池的配置文件(druid.properties)

2.3配置文件参数说明

2.4 具体代码体现 

五、JDBC工具类

1.工具类的抽取

2.工具类优化 (使用数据库连接池并加入事务开启回滚提交)

六、commons-dbutils的使用步骤


一、JDBC入门

1.jdbc的概念

JDBC(Java DataBase Connectivity:java数据库连接)
Java 连接数据库的规范(标准),可以使用 Java 语言连接数据库完成CRUD 操作。

2.jdbc的JDBC 核心思想

Java 中定义了访问数据库的接口,可以为多种关系型数据库提供统一的访问方式。
由数据库厂商提供驱动实现类(Driver 数据库驱动)。

3.JDBC七大步骤

1.导包

mysql5.1的jar包---com.mysql.jdbc.Driver 驱动类
mysql8.0的jar包---com.mysql.cj.jdbc.Driver 驱动类

2.注册驱动

 Class.forName("com.mysql.jdbc.Driver") ;  获取正在运行的这个类的字节码文件对象;

3.准备sql语句---定义String类型,里面书写插入/修改/删除

 静态sql语句,里面的参数要么键盘录入,要么直接给值,存在字符串拼接!
 String sql = "insert into account(name,balance) values('文章',1000);" ;

4.获取数据库的连接对象 java.sql.Connnection

java.sql.DriverManager类:
       提供静态方法:
       public static Connection getConnection(String url,
                                              String user,
                                              String password)
                                       throws SQLException
        url:统一资源定位符
jdbc:mysql://本地默认localhost或者127.0.0.1:端口号/库名(mysql驱动包5.1jar包这个地址不需要带参数)          
jdbc:mysql://本地默认localhost或者127.0.0.1:端口号/库名?characterEncoding=utf8&useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true
                                                               mysql驱动包8.0jar包后面带参数

5.获取执行对象执行静态sql语句

 Statement createStatement() java.sql.Statement:在数据库中执行sql语句的接口

6. java.sql.ResultSet:获取数据表的结果集  (接口)

针对ddl语句(创建表/修改表/删除表):返回值是0
    int executeUpdate(String sql)throws SQLException
执行DQL语句,数据库查询语句 select语句
    ResultSet executeQuery(String sql)throws SQLException

7.释放资源

rs.close();
stat.close();
conn.close();

二、JDBC各个功能类详解

1.DriverManager

jdk提供的DriverManager驱动管理类:管理jdbc服务的
    public static void registerDriver(Driver driver)throws SQLException 注册驱动
                参数:java.sql.Driver接口
     书写代码中不需要上面的这个步骤,是因为
        com.mysql.jdbc.Driver 这个类里面已经注册驱动了
                里面有静态代码块
                static {
                		try {
                		    //注册驱动
                			java.sql.DriverManager.registerDriver(new Driver());
                		} catch (SQLException E) {
                			throw new RuntimeException("Can't register driver!");
                		}
                	}
随着类的加载就直接注册驱动了,所以我们只需要获取正在运行的这个类的字节码文件对象,就会立即注册驱动

2.Connection

Connection:数据库连接对象
    获取执行者对象
        获取普通执行者对象:Statement createStatement();
        获取预编译执行者对象:PreparedStatement prepareStatement(String sql);
管理事务
    开启事务:setAutoCommit(boolean autoCommit); 参数为false,则开启事务。
    提交事务:commit();
    回滚事务:rollback();
    释放资源:void close();

3.Statement

Statement:执行sql语句的对象
    执行DML语句:int executeUpdate(String sql);
        返回值int:返回影响的行数。
        参数sql:可以执行insert、update、delete语句。
    执行DQL语句:ResultSet executeQuery(String sql);
        返回值ResultSet:封装查询的结果。
        参数sql:可以执行select语句。
    释放资源:void close();

4.ResultSet

ResultSet:结果集对象
    判断结果集中是否还有数据:boolean next();
        有数据返回true,并将索引向下移动一行
        没有数据返回false
    获取结果集中的数据:getXXX getXXX(“字段名称”)/(索引);
        例如:以int数据举例:
            getInt(int columnIndex)  这个检索的当前行中指定列的值 ResultSet作为对象 
            getInt(String columnLabel)  此ResultSet对象的当前行中指定列的值。 
        XXX代表数据类型(要获取某列数据,这一列的数据类型
    释放资源:void close();

三、PreparedStatement预编译对象

 1.使用Statement的弊端 

使用Statement完成用户登录---------->有一张user表  
										id   username   password
	键盘录入用户名和密码,
	User类:private int id;
		  private String username;
		  private String password;
	定义一个UserDao接口---->boolean isLogin(String username,String password) ;
	userDaoImpl接口实现类----->实现这个业务
						select * from user where username = 'xxx' and passwod='xxxx'  ; 
纯sql拼接会出现安全漏洞!						
select * from user where username = 'xxx' and passwod='xxxx' or '1'='1' ;
						如果查询到了数据---->结果集对象.next()--->返回true
	--- 效率低
    --- 造成sql注入(用户名和随便输入,依然登录成功)

2.PreparedStatement

为了避免出现Statement造成的sql注入漏洞,所以我们使用PreparedStatement

预编译sql语句的执行者对象。在执行sql语句之前,将sql语句进行提前编译
    明确sql语句的格式后,就不会改变了;剩余的内容都会认为是参数
    参数使用?作为占位符
    为参数赋值的方法:setXxx(参数1,参数2);
    参数1:?的位置编号(编号从1开始)
    参数2:?的实际参数
执行sql语句的方法
    执行insert、update、delete语句:int executeUpdate();
    执行select语句:ResultSet executeQuery();

3.核心步骤

1.获取数据库连接对象
Connection conn = JdbcUtils.getConnection();
2.准备sql---参数化的sql(预编译sql语句)(参数使用?占位符)
String sql = "select * from user where username = ? and password = ?" ; //英文符号
3.通过数据库的连接对象获取预编译对象
PreparedStatement stmt = conn.prepareStatement(sql) ;
4.使用预编译对象给参数进行赋值
stmt.setString(1,user.getUsername()) ;
stmt.setString(2,user.getPassword()) ;
5.通过预编译对象执行这些参数(在预编译对象中执行参数化的sql)
ResultSet resultSet = stmt.executeQuery();
6.关闭释放资源

4.Statement和PreparedStatement的区别?

1)共同点:
	都是可以发送sql到数据库的,都是执行对象,后者继承前者(java.sql.包下的接口)
2)不同点:
2.1)是否会造成sql注入
	Statement永远执行的是静态sql语句:语句中存在"硬编码",存在SQL的字符串拼接,就造成sql注入,不安全!
	PreparedStatement:永远执行的是参数化的sql语句,全部参数都是"?",占位符号,有效防止sql的拼接,预防sql注入,提高执行sql的安全性!
2.2)是否会提高sql执行效率
	Statement:不会提高sql执行效率,
	获取执行对象,然后将sql语句发送数据库(没写一个sql,发一次!),频繁的操作访问数据库
	PreparedStatement:大大提高SQL执行效率
参数化sql是在获取PreparedStatement,就已经发送给数据库了,然后在PreparedStatement赋值不同的值;

四、数据库的连接池

1.图解

2. 自定义连接池

/**
 * Druid连接池的使用步骤:
 *      1)导包 druid-1.1.10.jar包
 *      2)准备好连接池的配置文件
 *      3)从连接池获取连接对象
 *          提供jar包--->com.alibaba.druid.pool.DruidDataSource--->本质实现了一个接口javax.sql.DataSource
 *              --->Connection getConnection()
 *
 */

2.1导包

 

2.2 连接池的配置文件(druid.properties)

driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/myee_2302
username=root
password=123456
initialSize=5
maxActive=10
maxWait=3000

2.3配置文件参数说明

#这些名称都是DruidDataSoure提供的参数
#连接数据库的驱动类
driverClassName=com.mysql.jdbc.Driver   
#连接数据库的url地址:统一资源定位符
url=jdbc:mysql://localhost:3306/myee2302_db_2
#用户名
username=root
#密码
password=123456
#连接池一旦创建,初始化5个连接数量
initialSize=5
#最大连接数量值:默认值8个,自己设定值,和maxIdel:最大空闲数量相等
maxActive=10
#最大等待时间:为毫秒值,一旦连接池中创建连接对象超过了最大连接数量,等待3秒中,如果还连接不上,连接池会产生错误日志,提示"连接超时"
maxWait=3000

2.4 具体代码体现 

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

        //3)创建数据源DruidDataSource对象
        //德鲁伊提供的数据源工厂:DruidDataSourceFactory提供静态方法,返回值就是DataSource
        //public static DataSource createDataSource(Properties properties)
        //创建属性集合列表
        Properties prop = new Properties() ;

        //读取src下配置文件
        InputStream inputStream = DruidDemo.class.getClassLoader().getResourceAsStream("druid.properties");
        //将字节输入流加载进来
        prop.load(inputStream) ;

        DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);
        for(int x = 1 ; x <=11 ; x++){
            //System.out.println(dataSource.getConnection());
            Connection conn = dataSource.getConnection() ;
            if(x==3){
                conn.close(); //暂时释放,归还连接池中
            }
            System.out.println(conn);
        }

        /**
         * 上面这个方法底层已经集成好了
         *  public static DataSource createDataSource(Map properties) throws Exception {
         *         DruidDataSource dataSource = new DruidDataSource(); //创建德鲁伊的数据源
         *         config(dataSource, properties); //封装数据:将配置文件的内容封装到dataSource数据源对象汇总
         *         return dataSource;//返回
         *     }
         */
    }
}

五、JDBC工具类

1.工具类的抽取

  • 配置文件(在src下创建config.properties)
driverClass=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/db1
username=root
password=root
  • 工具类:com.test.utils.JdbcUtils
package com.qf.utils;

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

/**
 * 将jdbc步骤优化
 *       自定义工具类,将获取连接对象,释放资源都放在静态方法中,方便去使用!
 */
public class JdbcUtils {
    //统一资源定位符
    private static String url = null ;
    //用户名
    private static String user = null ;
    //密码
    private static String password = null ;
    //驱动类
    private static String driverClassName = null ;

    //定义静态代码块
    static{
        try {
            //1)读取src下面的jdbc.properties文件
            //创建一个属性集合列表
            Properties prop = new Properties() ;
            //System.out.println(prop) ;
            InputStream inputStream = JdbcUtils.class.getClassLoader().
                    getResourceAsStream("jdbc.properties");
            //将字节输入流加载到属性集合列表中
            prop.load(inputStream) ;
            //System.out.println(prop) ;
            //2)通过key获取value
            driverClassName = prop.getProperty("driverClassName");
            url = prop.getProperty("url");
            user = prop.getProperty("user");
            password = prop.getProperty("password");

            //3)注册驱动
            Class.forName(driverClassName) ;

        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    //对外私有,不让外界new
    private JdbcUtils(){}


    //定义公共的静态方法,返回值就是Connection
    //public static Connection getConnection(String url,String user,String password){ //一会还得需要传入参数,
    public static Connection getConnection(){ //一会还得需要传入参数,
        Connection conn = null ;
        try {
           conn = DriverManager.getConnection(url,user,password) ;//url,user,password
            return  conn;
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return  null ;
    }


    //释放资源

    //public static void  close(ResultSet rs,Statement stmt,Connection conn){
    public static void  close(ResultSet rs,PreparedStatement stmt,Connection conn){
        if(rs!=null){
            try {
                rs.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
        if(stmt!=null){
            try {
                stmt.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
        if(conn!=null){
            try {
                conn.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
    }

    //主要针对DDL/DML语句操作释放资源
   /* public static void close(Statement stmt,Connection conn){
        close(null,stmt,conn);
    }*/
    public static void close(PreparedStatement stmt,Connection conn){
        close(null,stmt,conn);
    }

    public static void main(String[] args) {

        Connection conn = JdbcUtils.getConnection();
        System.out.println(conn);
    }
}

2.工具类优化 (使用数据库连接池并加入事务开启回滚提交

package com.qianfeng.day37.test01.utils;


import com.alibaba.druid.pool.DruidDataSourceFactory;

import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;

    /**
     * Jdbc方式---加入Druid连接池,----自动的封装配置文件的所有数据
     * 封装一个静态方法--->获取Connection(从连接池获取)
     * 获取DataSource:数据源----> 连接参数(数据库的信息)以及初始化数量,最大激活数量,最大等待时间
     * 释放资源
     */
    public class DruidJdbcUtils {

        //静态实例--->java.lang.ThreadLocal<T>  模拟线程,每一个用户都有自己的Connection
        private static ThreadLocal<Connection> tl = new ThreadLocal<>() ; //里面没有连接对象
        //声明一个DataSource接口类型 变量
        private static DataSource ds ;

        //构造方法私有化
        private DruidJdbcUtils(){}

        //静态代码块
        static{
            try {
                //1)读取德鲁伊的配置文件,让德鲁伊自己封装配置文件参数
                InputStream inputStream = DruidJdbcUtils.class.getClassLoader().getResourceAsStream("druid.properties");
                //创建属性集合列表
                Properties prop = new Properties() ;
                //加载属性集合列表
                prop.load(inputStream) ;
                //2)创建DruidDataSource(连接池)
                ds =  DruidDataSourceFactory.createDataSource(prop);
            } catch (IOException e) {
                e.printStackTrace();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        //获取DataSource数据源信息 (连接池的所有参数)
        public static DataSource getDataSource(){
            return  ds ;
        }

        //从数据源(连接池) 获取连接对象
        public static Connection getConnection(){
            //1)线程本地线程中获取连接对象---ThreadLocal<T>--->T get():从当前线程中获取存储的内容
            Connection conn = tl.get() ;
            try {

                //2)判断
                //如果当前conn对象为null,说明当前线程中没有要操作的连接对象
                if(conn==null){
                    //3)从数据源(连接池中)获取Connection
                    conn = ds.getConnection();
                    //4)将从数据源中获取到的conn连接对象,绑定当当前线程中
                    //ThreadLocal<T>--->public void set(T t):绑定
                    tl.set(conn) ;
                }

            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
            return conn ;
        }

        //释放资源
        public static void  close(ResultSet rs, PreparedStatement stmt, Connection conn){
            if(rs!=null){
                try {
                    rs.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
            if(stmt!=null){
                try {
                    stmt.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
            if(conn!=null) {
                try {
                    conn.close();
                    //从当前线程解绑
                    tl.remove();  //ThreadLocal<T> :从线程中移出
                } catch (SQLException throwables) {
                    throwables.printStackTrace();

                }
            }
        }


        //主要针对DDL/DML语句操作释放资源
   /* public static void close(Statement stmt,Connection conn){
        close(null,stmt,conn);
    }*/
        public static void close(PreparedStatement stmt,Connection conn){
            close(null,stmt,conn);
        }

        /**
         * 开启事务
         *
         */
        public static void setAutoCommit() throws SQLException {
            //获取连接对象
            Connection conn = getConnection();
            //设置手动提交
            conn.setAutoCommit(false) ;
        }

        /**
         * 事务回滚
         */
        public static void rollbackAndClose() throws SQLException {
            //获取连接对象
            Connection conn = getConnection();
            conn.rollback() ;
            //释放连接对象,从当前线程中解绑
            conn.close();
            tl.remove() ;
        }

        /**
         * 提交事务
         */
        public static void commitAndClose() throws SQLException {
            //获取连接对象
            Connection conn = getConnection();
            conn.commit(); ;
            //释放连接对象,从当前线程中解绑
            conn.close();
            tl.remove() ;
        }


        public static void main(String[] args) {


            System.out.println(DruidJdbcUtils.getDataSource());
            System.out.println(DruidJdbcUtils.getConnection());
        }
    }

六、commons-dbutils的使用步骤

1)导包 commons-dbutils-1.6.jar
2)创建执行器 QueryRunner---> 底层PreparedStatement
     public QueryRunner(DataSource ds) 参数就是数据源--->自定义工具获取到了数据源 (自动提交)
     public QueryRunner():创建执行器,手动提交


3)准备好sql语句
        DML语句---添加/修改/删除
                  insert into
                  update
                  delete from...

        QueryRunner提供通用的更新操作:
        public int update(Connection conn, String sql, Object... params) throws SQLException  :手动提交
        public int update(String sql, Object... params):自动提交

        DQL语句--- 查询语句
        QueryRunner提供的通用查询操作
        public <T> T query(String sql, ResultSetHandler<T> rsh, Object... params) throws SQLException
        第一个参数:查询的sql语句
        第二个参数:ResultSetHandler结果集的处理
                    它的子实现类:BeanHandler---->将查询的某一条记录封装到实体了中(JavaBean:是具体类,属性私有,对外提供setXXX()/getXXX)
                    public BeanHandler(Class<T> type) --->  参数针对查询的记录--封装到类名.class中

                    子实现类:BeanListHandler<T>    ---将查询的多条记录封装到List集合中,List集合都是当前类对象

                     public BeanListHandler(Class<T> type)
                    子实现类:

                        ScalarHandler:通过聚合函数(count(列名称),其他max(xx),avg(xxx))查询单行单的列的数据
                        的结果封装到Object类中
        第三个参数:就是赋值的实际参数params,没有参数可以不写


注意事项:

    使用commons-dbutils工具库:无论添加/删除/修改/查询数据,
        必须保证实体类的属性名称和表的字段名称一一对应,否则数据封装不上去的,永远是null!
        如果不对应,可以在(查询语句)--->给这字段给别名(保证别名和实体类的属性名称一致)
        实体类的属性名称不要出现大写字母,否则也可能是null值!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值