小白入门之JDBC 绝地灬酷狼 2021-09-11 02:16 443阅读 0赞 ### 文章目录 ### * * JDBC * * 概念 * 使用步骤 * idea 创建项目并导入jar包 * 入门案例 * SQL注入 * SQL注入的解决方案 * JDBC常见问题 * * Class.forName这句话有用没? * 驱动版本 * 中文乱码 * SQL注入 * PreparedStatement 语句 * 常见错误 ## 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)\]][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-TN6AXbLJ-1623158031207_RackMultipart20210608-4-1h5920r_html_afc26e401e1f7f7d.png] ![\[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-r0J1eG5r-1623158031209)(RackMultipart20210608-4-1h5920r\_html\_8d1915863207cc39.png)\]][img-r0J1eG5r-1623158031209_RackMultipart20210608-4-1h5920r_html_8d1915863207cc39.png] ![\[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3r26m7Ea-1623158031212)(RackMultipart20210608-4-1h5920r\_html\_5a42c6d871847882.png)\]][img-3r26m7Ea-1623158031212_RackMultipart20210608-4-1h5920r_html_5a42c6d871847882.png] ![\[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-D5uftrWu-1623158031215)(RackMultipart20210608-4-1h5920r\_html\_a544f200ecc9ea1a.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)\]][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"; ### 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语句。 ### 常见错误 ### Exception in thread "main" 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 **错误原因:** 表名写错了 [img-SC5BTs9w-1623158031193_RackMultipart20210608-4-1h5920r_html_10fb1dcdf23d273.png]: /images/20210911/9249b34131eb43f386291de508fb8311.png [img-TN6AXbLJ-1623158031207_RackMultipart20210608-4-1h5920r_html_afc26e401e1f7f7d.png]: /images/20210911/27dceef9ded344c5951c7b36413966f9.png [img-r0J1eG5r-1623158031209_RackMultipart20210608-4-1h5920r_html_8d1915863207cc39.png]: /images/20210911/9bb98f2e7a3b4991849dcfbcd2eb769a.png [img-3r26m7Ea-1623158031212_RackMultipart20210608-4-1h5920r_html_5a42c6d871847882.png]: /images/20210911/b030078eabb5451f8cfed6342e39917d.png [img-D5uftrWu-1623158031215_RackMultipart20210608-4-1h5920r_html_a544f200ecc9ea1a.png]: /images/20210911/1763d53ac7dd49cc948fccf79fcc84ae.png [img-u3dNtFPv-1623158031218_RackMultipart20210608-4-1h5920r_html_c56d22250b83c666.png]: /images/20210911/0a233b9796cf401d8e881ad7ab2d069c.png
相关 JDBC 注册(小白起步1) 1.用户信息 import java.io.Serializable; / 用户信息类 和数据库表一一对应 小灰灰/ 2022年05月25日 02:35/ 0 赞/ 140 阅读
相关 小白入门之 Springboot整合SSM 文章目录 1.1 创建SSM模块 1.1.1 系统架构图 1.1.2 项目结构 1.1.3 需 深藏阁楼爱情的钟/ 2021年09月11日 02:20/ 0 赞/ 422 阅读
相关 小白入门之Hello Spring Boot 文章目录 SpringBoot介绍 定义 特点 SpringBoot全新的pom.xml 深藏阁楼爱情的钟/ 2021年09月11日 02:14/ 0 赞/ 347 阅读
还没有评论,来说两句吧...