数据库实现了数据的长久化,但咱们最终要在程序里解决数据啊,那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数据库接口。

如有问题能够观看视频:

https://www.bilibili.com/vide...

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

调用形式有三种:

Statement语句、PreparedStatement预处理语句、CallableStatement存储过程,举荐应用第二种PreparedStatement,避免SQL注入,其也是预编译性能高。

应用步骤

  • 导入jar包(丰盛的工具类)
  • 获取和数据库的连贯(用户名、明码)
  • 通过程序执行SQL
  • 通过程序处理后果

idea 创立我的项目并导入jar包

  • 创立stage2 Java工程
  • 创立lib目录,拷贝驱动objbc6-11.1.0.7.0到lib目录下
  • 我的项目援用这个内部jar包

入门案例

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文件中找启动类。

驱动版本
不同版本的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
谬误起因:

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