• jdbc连接数据库


    JDBC

    JDBC基础

    1、JDBC是什么?
    Java DataBase Connectivity (Java语言连接数据库)

    JDBC不本质是一套接口

    2、JDBC的本质是什么?

    • JDBC是所有关系型数据库的规则,即接口。java.sql.* ;(这个软件包下有很多接口。)
    • 各个数据库厂商去实现这套接口,提供数据库jar包
    • 我们可以使用这套接口(JDBC)编程,真正执行的代码是驱动jar包中的实现类。

    接口都有调用者和实现者。
    面向接口调用、面向接口写实现类,这都属于面向接口编程。

    3.为什么要面向接口编程?
    解耦合:降低程序的耦合度,提高程序的扩展力(不需要针对不同数据库分别开发)。
    多态机制就是非常典型的:面向抽象编程。(不要面向具体编程)
    建议:

    Animal a = new cat() ;
    Animal a = new Dog() ;
    
    //喂养的方法
    public void feed(Animal a){  //面向父类型编程。
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    不建议:

    Dog d = new Dog(); cat c = new cat() ;
    
    • 1

    4.思考:为什么SUN制定一套JDBc接口呢?
    因为每一个数据库的底层实现原理都不一样。oracle数据库有自己的原理;MysQL数据库也有自己的原理;Mssq1server数据库也有自己的原理。…
    每一个数据库产品都有自己独特的实现原理。

    不必为不同的数据库专门编写不同的程序,而只需要加载不同的数据库驱动即可
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UfpiuNis-1663408230028)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\1662635998787.png)]

    JDBC连接数据库步骤(六个步骤)

    创建工程,导入驱动jar包

    **第一步:**加载JDBC驱动(数据库连接器),记得提前将JDBC驱动的jar文件加入类(编译)路径

    Class.forName("com.mysql.cj.jdbc.Driver");
    
    • 1

    **第二步:**获取连接Connection对象,在这一步需给定正确的JDBC url, 数据库用户名,密码

    • DriverManager:注册驱动;连接数据库。工具类里面都是静态方法
    Connection conn=DriverManager.getConnection(url,user,pass);
    
    //---->URL分析:
    "jdbc(这是协议以jdbc开头):mysql(这是子协议,数据库管理系统称)://localhost(数据库来源地址):3306(目标端口)/test(要查询的表)?"
    "useUnicode=true&characterEncoding=UTF8";添加这个是为了防止乱码,指定使用Unicode字符集 ,且使用UTF-8来编辑。
    
    • 1
    • 2
    • 3
    • 4
    • 5

    示例:

    Connection conn =DriverManager.getConnection("jdbc:mysql://localhost:3306/Book?serverTimezone=GMT", "root", "root");
    
    • 1

    **第三步:**获取Statement操作对象(或PreparedStatement)对象,专门执行sql语句的对象

    /* 方法一 */
    Statement stmt = conn.createStatement();
    /* 方法二 */
    PreparedStatement pstmt = conn.PreparedStatement("sql语句") ;
    pstmt.setString(1, "Java编程指北");  //设置参数
    
    • 1
    • 2
    • 3
    • 4
    • 5

    **第四步:**执行Statement对象的executeQuery()方法查询,或执行Statement对象的executeUpdate()方法进行“增、删、改”操作。

    Statement接口下的方法:

    boolean execute(String sql)----执行insert,update,delete语句,如果返回值是结果集则为true,否则为false
    ResultSet executeQuery(String sql)----执行SQL语句,返回值为ResultSet
    int executeUpdate(String sql)----执行insert,update,delete语句,返回值为所影响的行数
    
    • 1
    • 2
    • 3

    **第五步:**处理结果集(只有查询有),循环遍历ResultSet对象

    ResultSet对象的getXxxx方法,取决于数据库中表的字段的类型,例如:varchar2 对应方法是getString ,如果是 integer 对应方法是getInt/getLong

    **第六步:**释放资源,关闭顺序与流一样,先进后关。(Java和数据库属于进程间的通信,一定要关闭)

    if(rs !=null){//1.关闭结果集
        try{
            rs.close();
        } catch (SQLException e){
            e.printStackTrace();
        }
    }
    if(stmt !=null){//2.关闭声明的对象
        try{
            stmt.close();
        }catch(SQLException e){
            e.printStackTrace();
        }
    }
    if(conn !=null){//3.关闭连接 (记住一定要先关闭前面的1.2.然后在关闭连接)
        try{
            conn.close();
        }catch(Exception e){
            e.printStackTrace();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    示例:

    public class jdbcTest {
        public static void main(String[] args) throws Exception {
            Connection conn = null;
            Statement stat = null;
            try {
                //加载驱动  方言
                Class.forName("com.mysql.jdbc.Driver");
                //准备数据库连接路径
                String url = "jdbc:mysql://127.0.0.1:3306/xxshop";
                //用户名与密码
                String username = "xxxx";
                String userpwd = "xxxx";
                //根据路径,用户名,密码 使用DriverManager获取数据库connection连接
                conn = DriverManager.getConnection(url,username,userpwd);
                //准备要执行的SQL语句
                String sql= "select user_id,user_name from sf_user";
                //创建Statement对象  用于执行SQL语句
                stat = conn.createStatement();
                //执行SQL语句
                ResultSet rs =  stat.executeQuery(sql);
                //处理ResultSet结果集
                //rs.next()  返回boolean 值
                while(rs.next()){
                    Long user_id =  rs.getLong(1);
                    String user_name = rs.getString(2);
                    System.out.println("用户ID:"+user_id);
                    System.out.println("用户名:"+user_name);
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                //释放资源
                try {
                    stat.close();
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    JDBC API详解

    ▶DriverManager:
    • 驱动管理类作用:注册驱动;获取数据库连接

    ▶Connection:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vEkqKRB6-1663408164830)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\1662908309696.png)]

    java代码中事务处理方式,用异常处理机制try/catch

    //开启事务
    ……
    try {
        //5. 执行sql
        int count1 = stmt.executeUpdate(sql1);
        System.out.println(count1);
        int count2 = stmt.executeUpdate(sql2);
        System.out.println(count2);
    } catch (SQLException e) {
        //回滚事务
    
        throw new RuntimeException(e);
    }
    //提交事务
    ……
        
    //示例-------------------------------------------:
        try {
                //开启事务
                conn.setAutoCommit(false);
                //5. 执行sql
                int count1 = stmt.executeUpdate(sql1);
                System.out.println(count1);
                int count2 = stmt.executeUpdate(sql2);
                System.out.println(count2);
    
                //提交事务
                conn.commit();
            } catch (SQLException e) {
                //回滚事务
                conn.rollback();
    
                throw new RuntimeException(e);
            }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    ▶Statement:

    执行sql语句:

    int executeUpdate(sql):执行DML、DDL语句
    -- 返回值:
    DML语句影响的行数
    DDL语句执行后,执行成功也可能返回0
    
    • 1
    • 2
    • 3
    • 4
    ResultSet executeQuery(sql):执行DQL语句
    -- 返回值:
    ResultSetj
    
    • 1
    • 2
    • 3
    ▶ResultSet:
    • ResultSet(结果集对象)作用:封装了DQL查询语句的结果

    • 获取查询结果

      boolean next()1.将光标从当前位置向前移动一行 2.判断当前行是否为有效行
      
      • 1
      • 返回值:
        true:有效行,当前行有数据
        false:无效行,当前行无数据
      xxx getXxx(参数):获取数据
      
      • 1
      • xxx:数据类型,int getInt(参数);String getString(参数)

      • 参数(方法的重载):int:列的编号,从1开始

        ​ String:列的名称

    • 使用步骤

      1.游标向下移动一行,并判断该行是否数据:next()

      2.获取数据:getXxx(参数)

      //循环判断游标时候是最后一行末尾
      while(rs.next()){
      	//获取数据
      	re.getXxx(参数);
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
    ▶PreparedStatement:

    PreparedStatement继承Statement

    • PreparedStatement作用:预编译SQL**(性能更高)语句并执行:预防SQL注入(将敏感字符进行转义)**问题

      ①获取PreparedStatement对象

      //SQL语句中参数值,使用?占位符替代
      String sql = "select * from user where username=? and password=?";
      
      //通过Connection对象获取,并传入对应的sql语句
      PreparedStatement pstmt = conn.prepareStatement(sql);
      
      • 1
      • 2
      • 3
      • 4
      • 5

      ②设置参数

      PreparedStatement对象:setXxx(参数1, 参数2):给?赋值

      • Xxx:数据类型;如setlnt(参数1,参数2)

      • 参数:

      参数1:?的位置编号,从1开始

      参数2:?的值

      ③执行sql

      executeUpdate();或 executeQuery();  不需要再传递sql
      
      • 1
    • SQL注入:

      SQL注入是通过操作输入来修改事先定义好的SQL语句,用以达到执行代码对服务器进行攻击的方法。

    指定了特定的sql语句,密码为空或者true(1=1为true):
    特点的sql不止这一种

    ▶解决sql注入问题用PreparedStatement:
    public class Test06_PreparedStatement {
        @Test
        public void testlogin() throws Exception {
            Class.forName("com.mysql.jdbc.Driver");
    
            String url = "jdbc:mysql://127.0.0.1:3306/myschool2";
            String username="xxxx";
            String password="xxxx";
            Connection conn = DriverManager.getConnection(url,username,password);
    
            String name = "张三";
            String pwd = "' or '1' = '1" ;
            //定义sql
            String sql = "select * from user where name = ? and password =?" ;
            //获取pstmt对象
            PreparedStatement pstmt = conn.prepareStatement(sql);
            //设置?的值
            pstmt.setString(1,name);
            pstmt.setString(2,pwd);//对pwd内容进行转义--如下图
            //执行sql
            ResultSet rs = pstmt.executeQuery();
    
            //判断登录是否成功
            if(rs.next()){
                System.out.println("登录成功~");
            }else{
                System.out.println("登录失败~");
            }
    
            rs.close();
            pstmt.close();
            conn.close();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    引号转义变为真正的引号,不在可以连接变为空字符串或条件:

    转义内部原理:


    开启预编译功能 :useServerPrepStmts=true。预编译一次,执行多次:

    String url = "jdbc:mysql:///myschool2?userSSL=false&userServerPrepStmts=true";
    String username="xxxx";
    String password="xxxx";
    Connection conn = DriverManager.getConnection(url,username,password);
    
    • 1
    • 2
    • 3
    • 4

    Mysql执行日志:

    1. 在MySQL目录文件my.ini中加入配置(上图中)
    2. 运行cmd–>services.msc打开服务管理器,将MySQL重新启动。
    3. 目录中会生产两个文件。打开mysql.Log文件可以看到执行过程

    数据库连接池

    ▶数据库连接池简介:

    简介:

    ​ 来一个用户开一个数据库连接,用完就关,再来一个重复过程,资源得不到复用。

    ​ 系统启动之前开一个初始化容器(集合),提前申请多个连接,有用户就从容器拿出来使用,使用完在回到容器。

    • 数据库连接池是个容器,负责分配、管理数据库连接(Connection)

    • 它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个;

    • 释放空闲时间超过最大空闲时间的数据库连接来避免因为没有释放数据库连接而引起的数据库连接遗漏

    • 好处:

      资源重用;提升系统响应速度;避免数据库连接遗漏

    数据库连接池的实现:

    • 标准接口:DataSource

      • 官方(SUN)提供的数据库连接池标准接口,由第三方组织实现此接口。·

      • 功能:获取连接

        Connection getConnection()
        
        • 1
    • 常见的数据库连接池:

      • DBCP
      • C3P0
      • Druid
    • Druid(德鲁伊)

      • Druid连接池是阿里巴巴开源的数据库连接池项目
      • 功能强大,性能优秀,是Java语言最好的数据库连接池之一

    Driud使用步骤:

    1.导入jar包druid-1.1.12.jar

    2.定义配置文件

    3.加载配置文件

    4.获取数据库连接池对象

    5.获取连接

    ▶Druid数据库连接池:

    https://blog.csdn.net/m0_70083523/article/details/126953632:德鲁伊数据库连接池的使用。


    JDBC封装与设计模式

    DAO模式的应用

    Data Access Object(数据存取对象) 持久层

    创建包:
    com.dao ----放接口文件 UserDao
    BaseDao(数据库工具类)
    com.dao.impl----放接口实现类 UserDaoImpl
    com.entity ----放实体类 User

    https://www.zybuluo.com/wangzhuanyun/note/1531060

    工具包BaseDao:

    /**
     * 数据库连接工具类
     * @author Lenovo
     *
     */
    public class BaseDao {
    	
    	protected ResultSet rs = null;
    	protected PreparedStatement ps = null;
    	protected Connection conn = null;
    	
    	//获得数据库连接
    	public boolean getConnection() {
    		try {
    			//加载驱动
    			Class.forName("com.mysql.cj.jdbc.Driver");
    			//准备URL 连接数据库
    			String url = "jdbc:mysql://127.0.0.1:3306/myschool2?useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull";
    			//准备账号密码
    			String uname = "xxxx";
    			String upwd = "xxxx";
    			//通过DriverManager.getConnection获得Connection对象
    			 conn = DriverManager.getConnection(url, uname, upwd);			 
    			 return true;			 
    		} catch (Exception e) {
    			e.printStackTrace();
    			 return false;
    		}		
    	}
        
    	/**
    	 * 公共修改  添加  删除
    	 * @param sql
    	 * @param objs
    	 * @return
    	 */
    	public int executUpdate(String sql,Object[] objs) {
    		int updateRows = 0;
    		try {		
    			ps = conn.prepareStatement(sql);
    			if(objs!=null) {
    				//填充占位符
    				for(int i = 0;i<objs.length;i++)
    				{
    					ps.setObject((i+1), objs[i]);
    				}				
    			}
    			updateRows = ps.executeUpdate();
    			return updateRows;
    			
    		} catch (SQLException e) {
    			e.printStackTrace();
    			return updateRows;
    		}
    	}
    	
    	/**
    	 * 公共查询
    	 * @param sql  携带占位符  ?
    	 * @param objs  参数数组 
    	 * @return
    	 */
    	public ResultSet executeSQL(String sql,Object[] objs) {  
    		try {
    		
    			ps = conn.prepareStatement(sql);
    			if(objs!=null) {
    				//填充占位符
    				for(int i = 0;i<objs.length;i++)  //数组长度为几,就几个?
    				{
    					ps.setObject((i+1), objs[i]);
    				}				
    			}
    			rs = ps.executeQuery();	//没有占位符即查询全部
    			return rs;			
    		} catch (SQLException e) {
    			e.printStackTrace();
    			return null;
    		}
    	}
    	
    	/**
    	 * 释放资源
    	 * @return
    	 */
    	public void closeResources() {
    		if(rs!=null) {
    			try {
    				rs.close();
    			} catch (SQLException e) {
    				// TODO Auto-generated catch block
    				e.printStackTrace();
    			}
    		}
    		
    		if(ps!=null) {
    			try {
    				ps.close();
    			} catch (SQLException e) {
    				// TODO Auto-generated catch block
    				e.printStackTrace();
    			}
    		}
    		
    		if(conn!=null) {
    			try {
    				conn.close();
    			} catch (SQLException e) {
    				// TODO Auto-generated catch block
    				e.printStackTrace();
    			}
    		}
    		
    	}
    }	
    	/**
    	 * 释放资源
    	 * @return
    	 */
    	public void closeResources() {
    		if(rs!=null) {
    			try {
    				rs.close();
    			} catch (SQLException e) {
    				// TODO Auto-generated catch block
    				e.printStackTrace();
    			}
    		}
    		
    		if(ps!=null) {
    			try {
    				ps.close();
    			} catch (SQLException e) {
    				// TODO Auto-generated catch block
    				e.printStackTrace();
    			}
    		}
    		
    		if(conn!=null) {
    			try {
    				conn.close();
    			} catch (SQLException e) {
    				// TODO Auto-generated catch block
    				e.printStackTrace();
    			}
    		}
    		
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
  • 相关阅读:
    判断链表中是否有环
    知物由学 | Android 模拟点击研究,如何突围“黑灰产”的自动化作弊?
    Linux 安装docker-compose 编排工具并启动
    【数据结构】栈和队列的实现(C语言)
    字符设备驱动
    C++三大特性——继承(上篇)
    Vue.js之Vuex的使用
    总有一天,你一定会很棒
    数据分析实战-Python实现博客评论数据的情感分析
    Trie树 复习笔记
  • 原文地址:https://blog.csdn.net/m0_70083523/article/details/126908606