JDBC从入门到精通

JDBC从入门到精通JDBC概念我们学习了数据库,数据库实现了数据的持久化,但我们最终要在程序里处理数据啊,那java代码中怎么去访问数据库读写数据呢?这就要用到sun公司设定的一套数据库标准了,这套标准就是JDBC(JavaDatabaseConnectivity)。但它只是规范,不做具体实现。于是数据库厂商又根据JDBC标准,实现自家的驱动Driver。如:mysql驱动com.mysql.cj.jdbc.Driver,Oracle的驱动oracle.jdbc.OracleDriver。有了这套解决方案,java

大家好,又见面了,我是你们的朋友全栈君。

JDBC

概念

我们学习了数据库,数据库实现了数据的持久化,但我们最终要在程序里处理数据啊,那java代码中怎么去访问数据库读写数据呢?

这就要用到sun公司设定的一套数据库标准了,这套标准就是JDBC(Java Database Connectivity)。但它只是规范,不做具体实现。于是数据库厂商又根据JDBC标准,实现自家的驱动Driver。如:mysql驱动com.mysql.cj.jdbc.Driver,Oracle的驱动oracle.jdbc.OracleDriver。有了这套解决方案,java就可以访问数据库中的数据了。

public interface Connection extends Wrapper, AutoCloseable { 
   }

public interface Statement extends Wrapper, AutoCloseable { 
   }

public interface PreparedStatement extends Statement { 
   }

public interface CallableStatement extends PreparedStatement { 
   }

public interface ResultSet extends Wrapper, AutoCloseable { 
   }

Java中提倡面向接口开发,而最经典的接口设计莫过于JDBC数据库接口。

Connection链接、Statement语句、PreparedStatement预处理语句、CallableStatement存储过程、ResultSet结果集。

调用方式有三种:Statement语句、PreparedStatement预处理语句、CallableStatement存储过程,推荐使用第二种PreparedStatement,防止SQL注入,其也是预编译性能高。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SC5BTs9w-1623158031193)(RackMultipart20210608-4-1h5920r_html_10fb1dcdf23d273.png)]

使用步骤

导入jar包(丰富的工具类)

获取和数据库的连接(用户名、密码)

通过程序执行SQL

通过程序处理结果

idea 创建项目并导入jar包

  • 创建stage2 Java工程
  • 创建lib目录,拷贝驱动objbc6-11.1.0.7.0到lib目录下
  • 项目引用这个外部jar包

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TN6AXbLJ-1623158031207)(RackMultipart20210608-4-1h5920r_html_afc26e401e1f7f7d.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-r0J1eG5r-1623158031209)(RackMultipart20210608-4-1h5920r_html_8d1915863207cc39.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3r26m7Ea-1623158031212)(RackMultipart20210608-4-1h5920r_html_5a42c6d871847882.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-D5uftrWu-1623158031215)(RackMultipart20210608-4-1h5920r_html_a544f200ecc9ea1a.png)]

入门案例

package cn.tedu.jdbc;

import java.sql.*;

//测试 jdbc
//需求:查询cgb2104库里的students表里的所有数据
public class Test1 { 
   
    public static void main(String[] args) throws Exception { 
   
        //1,注册驱动
        Class.forName("com.mysql.jdbc.Driver");
        //2,获取和数据库的连接
//String url= "jdbc:mysql://localhost:3306/cgb2104?characterEncoding=utf8";//指定要连接哪个数据库
String url= "jdbc:mysql:///cgb2104?characterEncoding=utf8";//指定要连接哪个数据库
        String user= "root" ; //使用的用户名
        String pwd= "root" ; //使用的密码
        Connection conn = DriverManager.getConnection(url, user, pwd);
        //3,获取传输器,执行SQL
        Statement st = conn.createStatement();
        //4,执行SQL
        ResultSet rs = st.executeQuery("select * from students");
        //5,解析结果集
        while( rs.next() ){ 
   //next()判断结果集中是否有数据
            for (int i = 1; i <= 5 ; i++) { 
   
                //获取每列的值并打印
                System.out.println( rs.getString(i) );
            }
        }
        //6,释放资源
        rs.close(); //关闭结果集
        st.close();//关闭传输器
        conn.close();//关闭连接
    }
}

SQL注入

/*自己准备user2表(id/name/password),准备数据 CREATE TABLE `user2` ( `id` int(11) PRIMARY KEY auto_increment, `name` varchar(10) default NULL, `password` varchar(10) default NULL ) ; */
//需求:利用jdbc,根据用户名和密码查询cgb2104库里的user表
//SQL注入攻击问题
private static void login() { 
   
    try{ 
   
        Class.forName("com.mysql.jdbc.Driver");
        String url="jdbc:mysql:///cgb2104?characterEncoding=utf8";
        Connection conn = DriverManager.getConnection(url, "root", "root");
        Statement st = conn.createStatement();
// String sql ="select * from user2 where name='jack' and password='123456'";//写死了

        String user = new Scanner(System.in).nextLine();//用户输入jack'#
        String pwd = new Scanner(System.in).nextLine();
        //SQL注入攻击问题:本质上是因为SQL语句中出现了特殊符号#,改变了SQL语义
String sql ="select * from user2 where name='"+user+"' and password='"+pwd+"'";
        ResultSet rs = st.executeQuery(sql);//执行查询的SQL,返回结果集
        if(rs.next()){ 
   
            System.out.println("登录成功~");
        }else{ 
   
            System.out.println("登录失败~");
        }
        st.close();
        conn.close();
    }catch(Exception e){ 
   
        e.printStackTrace();//有异常,直接打印异常信息
        //System.out.println("执行失败。。。");//上线
    }

}

SQL注入的解决方案

//解决SQL注入攻击的方案
private static void login2() { 
   
    try{ 
   
        Class.forName("com.mysql.jdbc.Driver");
        String url="jdbc:mysql:///cgb2104?characterEncoding=utf8";
        Connection conn = DriverManager.getConnection(url, "root", "root");
// Statement st = conn.createStatement();不行,不安全,会被SQL攻击

        String user = new Scanner(System.in).nextLine();//用户输入jack'#
        String pwd = new Scanner(System.in).nextLine();
        //?叫占位符 ,SQL的骨架
String sql ="select * from user2 where name=? and password=?";
        //先把SQL骨架发给数据库执行
        PreparedStatement ps = conn.prepareStatement(sql);
        //给SQL里的? 设置参数
        ps.setString(1,user);//给第一个?设置值是user
        ps.setString(2,pwd);//给第二个?设置值是pwd
        
        ResultSet rs = ps.executeQuery();//执行拼接好的SQL,返回结果集

        if(rs.next()){ 
   
            System.out.println("登录成功~");
        }else{ 
   
            System.out.println("登录失败~");
        }
        ps.close();
        conn.close();
    }catch(Exception e){ 
   
        e.printStackTrace();//有异常,直接打印异常信息
        //System.out.println("执行失败。。。");//上线
    }
}

JDBC常见问题

Class.forName这句话有用没?

Class.forName可以指定class类路径进行动态创建对象实例,可JDBC这句话没有返回对象啊,那写这句有什么作用呢?看看java.sql.Driver.class的源码就找到真相了,原来它用了静态代码块创建对象。

    static { 
   
        try { 
   
            DriverManager.registerDriver(new Driver());
        } catch (SQLException var1) { 
   
            throw new RuntimeException("Can't register driver!");
        }
    }

写了创建了,那不写呢?怎么不写也能执行呢?

Java提供了SPI机制,用户可以自行配置类,JDBC高版本驱动就都引入了这个支持。如果用户使用了Class.forName方式就自己指定了驱动,如果未写这句话,则Java自动去META-INF/services/java.sql.Driver文件中找启动类。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-u3dNtFPv-1623158031218)(RackMultipart20210608-4-1h5920r_html_c56d22250b83c666.png)]

驱动版本

不同版本的mysql需要不同版本的驱动

Mysql5.0x mysql-connector-java-5.1.32.jar

Mysql8.0x mysql-connector-java-8.0.21.jar
  • Driver变成了: com.mysql.cj.jdbc.Driver,中间多了cj
  • url必须加时区参数: serverTimezone=Asia/Shanghai

中文乱码

url增加参数:characterEncoding=utf8防止中文乱码

String url ="jdbc:mysql://localhost:3306/mydb?characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false";

SQL注入

String condition = "陈强";
String condition = "陈强' or 1=1 or '";
String condition = "陈强' or true or '";

String sql = "select * from teachers where tname='" + condition+"'";

利用sql中’单撇是字符串的结束符,or只要一个条件成立其它就不用再判断,而恶意造成sql查询失效,本应该只展示一条数据,结果全部展现。

注入后形成的SQL:

SELECT * FROM teachers WHERE tname='陈强' OR 1=1 OR ''

大家试想如果是一个财务表,本你只能看自己的信息,结果你看了所有人的信息。结果新员工比你工资高,你说气人不。

PreparedStatement 语句

SQL注入解决方案:

Statement对象换为PreparedStatement对象

sql = "select * from teachers where tname=?";			#参数使用问号
PreparedStatement stat = cn.prepareStatement(sql); 		#对象换掉
stat.setString(1, condition);					#对应参数类型,第几个问号
ResultSet rs = stat.executeQuery();			#去掉sql参数

PS后的结果:

SELECT * FROM teachers WHERE tname='陈强\' or 1=1 or \''

利用转义字符,屏蔽了SQL中的恶意字符。不仅解决了sql注入问题,使系统变的安全,PreparedStatement还有个极大的好处,它是预编译的语句,其主干部分mysql进行预编译后缓存,下次这部分就无需在解析,只把条件拼入,这样执行效率远高于statement每次都要编译sql语句。

常见错误

java.lang.ClassNotFoundException: com.mysql.jdbc.Driver

错误原因:

1)jar没有导入,没有builder path

2)Class.forName(“com.mysql.jdbc.Driver”); 字符串拼写错误

Unknown database mydb;

错误原因:

数据库名称拼写错误

Access denied for user ‘root123’@‘localhost’ (using password: YES)

错误原因:

数据库用户名或者密码错误

Table ‘py-school-db.mydb’ doesn’t exist

错误原因:

表不存在,也可能表名写错了

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/152239.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • centos查看端口占用情况和开启端口命令_查看80端口占用情况

    centos查看端口占用情况和开启端口命令_查看80端口占用情况Centos查看端口占用情况命令,比如查看80端口占用情况使用如下命令:lsof-itcp:80列出所有端口netstat-ntlp结束进程:kill进程代码

  • 数字货币的旁观者:我们为什么说区块链商业化时机还未到来?「建议收藏」

    数字货币的旁观者:我们为什么说区块链商业化时机还未到来?

  • 2020熔化焊接与热切割作业模拟考试_熔化焊接与热切割考试题与答案

    2020熔化焊接与热切割作业模拟考试_熔化焊接与热切割考试题与答案题库来源:安全生产模拟考试一点通公众号小程序2022年熔化焊接与热切割考试题系熔化焊接与热切割判断题上机考试练习题!2022熔化焊接与热切割考试题库及模拟考试根据熔化焊接与热切割新版考试题库。熔化焊接与热切割全部考试题库随时根据安全生产模拟考试一点通上模拟考试。1、【单选题】CO2气体保护内圆孔自动立堆焊机不能用于修复()。(C)A、机车摇连杆孔B、机车车轮轮毂孔C、火车车轮轮缘2、【单选题】不属于低真空电子束焊的应用的是()。(B)A、变速箱B、导弹…

  • MATLAB GUI设计之弹出式菜单的使用

    MATLAB GUI设计之弹出式菜单的使用弹出式菜单在MATLABGUI设计中常常出现。比如串口助手、绘制图形等经常见到弹出式菜单如下图所示:使用方法:一、准备工作1、从MATLABGUIDE中拖出一个弹出式菜单2、双击这个弹出式菜单,出现检查器:将注意力放在途中红线位置处,点击string处的图标将其中的内容修改为你想要显示的内容:tag处的内容修改为自己想管这个弹出式菜单的名字。这里就按照原来

  • 5分钟,6行代码教你写爬虫!(python)[通俗易懂]

    5分钟,6行代码教你写爬虫!(python)[通俗易懂]5分钟,6行代码教你写会爬虫!适用人士:对数据量需求不大,简单的从网站上爬些数据。好,不浪费时间了,开始!先来个例子:输入以下代码(共6行)importrequestsfromlxmlimporthtmlurl=’https://movie.douban.com/’#需要爬数据的网址page=requests.Session().get(url)tree=html.f

  • 图像尺度空间理论_金字塔内部空间有多大

    图像尺度空间理论_金字塔内部空间有多大文章目录尺度空间什么是尺度空间(scalespace)为什么需要尺度空间高斯核图像金字塔什么是分辨率为什么需要多分辨率多尺度和多分辨率图像金字塔高斯金字塔SIFTOctavesandScalesBlurringAmountofblurring参考尺度空间什么是尺度空间(scalespace)图像的尺度是指图像内容的粗细程度。尺度的概念是用来模拟观察者距离物体的远近的程度。具体…

    2022年10月14日

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号