JDBC操作数据库详解

十、JDBC

10.1、数据库驱动

  1. 驱动:声卡、显卡、数据库
  2. 我们的程序会通过数据库驱动,再和数据库连接

10.2、JDBC

  1. SUN公司为了简化开发人员的(对数据库的统一)操作,提供了一个java操作数据库的规范,俗称JDBC

  2. 这些规范的实现由具体的厂商去做,对于开发人员来说,我们只需要掌握JDBC接口的操作即可

  3. jdbc需要的jar包


<dependency>
    <groupId>mysqlgroupId>
    <artifactId>mysql-connector-javaartifactId>
    <version>5.1.47version>
dependency>





<dependency>
    <groupId>com.mchangegroupId>
    <artifactId>mchange-commons-javaartifactId>
    <version>0.2.19version>
dependency>




<dependency>
    <groupId>commons-poolgroupId>
    <artifactId>commons-poolartifactId>
    <version>1.6version>
dependency>



<dependency>
    <groupId>commons-dbcpgroupId>
    <artifactId>commons-dbcpartifactId>
    <version>1.4version>
dependency>



<dependency>
    <groupId>com.mchangegroupId>
    <artifactId>c3p0artifactId>
    <version>0.9.5.5version>
dependency>

10.3、第一个JDBC程序

  1. 创建一个数据库,导入数据
CREATE DATABASE `jdbcStudy` CHARACTER SET utf8 COLLATE utf8_general_ci;

USE `jdbcStudy`;

CREATE TABLE `users`(
 `id` INT PRIMARY KEY,
 `NAME` VARCHAR(40),
 `PASSWORD` VARCHAR(40),
 `email` VARCHAR(60),
 birthday DATE
);

INSERT INTO `users`(`id`,`NAME`,`PASSWORD`,`email`,`birthday`)
VALUES(1,'zhangsan','123456','[email protected]','1980-12-04'),
(2,'lisi','123456','[email protected]','1981-12-04'),
(3,'wangwu','123456','[email protected]','1979-12-04')
  1. 创建一个普通项目,导入jar包
  2. 编写java代码(和sql yog中的可视化操作是一一对应的)
package com.qian.jdbc;

import java.sql.*;

//我的第一个jdbc程序
public class jdbcFirst {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        //1.加载驱动
        Class.forName("com.mysql.jdbc.Driver");  // 固定写法,加载驱动

        //2.用户信息和url
        String url = "jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true";
        String username="root";
        String password="123456";

        //3.连接成功,数据库对象 connection代表数据库
        Connection connection = DriverManager.getConnection(url, username, password);


        //4.执行SQL对象  Statement 执行SQL的对象
        Statement statement = connection.createStatement();


        //5.用执行SQL的对象执行SQL,可能存在结果,查看返回结果
        String sql = "SELECT *FROM users";
        ResultSet resultSet = statement.executeQuery(sql);//返回的结果集,结果集中封装了我们全部查询出来的结果
        while (resultSet.next()){
            System.out.println("id="+resultSet.getObject("id"));
            System.out.println("name="+resultSet.getObject("NAME"));
            System.out.println("pwd="+resultSet.getObject("PASSWORD"));
            System.out.println("email="+resultSet.getObject("email"));
            System.out.println("birth="+resultSet.getObject("birthday"));
            System.out.println("====================================================");
        }
        //6.释放连接
        resultSet.close();
        statement.close();
        connection.close();
    }
}

  1. 运行,拿到数据

  2. 步骤总结:

  • 加载驱动
  • 连接数据库 DriveManager
  • 获取执行sql的对象 statement
  • 获得返回的结果集 resultset
  • 释放连接

10.4、JDBC中对象的解释

  1. DriverManager
 Class.forName("com.mysql.jdbc.Driver");  // 固定写法,加载驱动
Connection connection = DriverManager.getConnection(url, username, password);  //连接到数据库
//connection --数据库
 connection.rollback();  // 事务回滚
connection.commit(); //事务提交
connection.setAutoCommit(); // 数据库设置自动提交
  1. URL
String url = "jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true";

//jdbc:mysql://主机地址:3306/数据库名?参数1&参数2&参数3
//mysql--3306
//oralce --1521
  1. Statement
// 执行SQL的对象  ,preparestatement也是执行sql的对象
String sql = "SELECT *FROM users";//编写SQL
statement.executeQuery();//查询操作返回 resultset
        statement.execute();//执行任何SQL
        statement.executeUpdate();//更新、插入、删除,都是用这个,返回一个受影响的行数

4.ResultSet

//只有查询才会返回的结果集,封装了所有查询出来的数据
resultSet.getObject();  //不知道列类型的情况下使用
resultSet.getInt(); //知道列的类型就使用指定的类型
resultSet.getBoolean();
resultSet.getFloat();
resultSet.getDate();

resultSet.beforeFirst();//移动到最前面
resultSet.afterLast();//移动到最后面
resultSet.next(); //移动到下一个数据
resultSet.previous();//移动到前一行
resultSet.absolute(row);//移动到指定行

  1. 释放资源
//6.释放连接
        resultSet.close();
        statement.close();
        connection.close();

10.5、Statement对象

  1. JDBC中的statement对象用于向数据库发送SQL语句,想完成对数据库的增删改查,只需要通过这个对象向数据库发送增删改查语句即可
  2. statement对象的executeUpdate方法,用于向数据库发送增删改的sql语句,执行完成后,会返回一个整数(即增删改语句导致了数据库几行数据发生了变化);executeQuery方法用于向数据库发送查询语句,执行完毕返回查询出来的全部数据结果ResultSet
  3. 使用executeUpdate方法进行增删改
  • 添加
Statement st = conn.createStatement();
String sql = "insert into user()values()";
int num = st.excuteUpdate(sql);
if(num>0){
  system.out.println("插入成功");
}  // 只要影响的数据发生变化则插入成功
  • 删除
Statement st = conn.createStatement();
String sql = "delete from user where id=1";
int num = st.excuteUpdate(sql);
if(num>0){
  system.out.println("删除成功");
}  

  • 修改
Statement st = conn.createStatement();
String sql = "update user set name=''where name=''";
int num = st.excuteUpdate(sql);
if(num>0){
  system.out.println("修改成功");
}  
  1. 使用excuteQuery查询
Statement st = conn.createStatement();
String sql = "SELECT *FROM users";
ResultSet resultSet = st.executeQuery(sql)
 while (resultSet.next()){
            System.out.println("id="+resultSet.getObject("id"));}

10.6、 SQL注入问题

  1. 例如我后台的sql语句为
"select * from s_student where loginName = '"+loginName+"' and loginPwd = '"+loginPwd+"'";
1

然后我随便输入一个用户名,但是只要密码输入的有讲究点

loginName = fasd;
loginPwd = fasd' or '1'='1;
12

因为1=1这条语句是一个永真式,且逻辑连接词使用的or,这样一来无论前面是什么loginPwd这个值一定为1,这样就将前面select语句的where条件恒为1,就相当于将前面的select语句给废了。

String Sql="select * from s_student where loginName = '"+fasd+"' and loginPwd = '"+fasd' or '1'='1+"'";
1

这样子我们可以绕过登录,去做一些危害网站的事情。

  1. SQL注入的根本原因

其实发生SQL注入的根本原因并非 是我们编写了loginPwd = fasd’ or ‘1’=‘1这条语句,究其根本是因为fasd’ or ‘1’='1这条语句被当作了sql语句的一部分被编译进去了

rs = stam.executeQuery(sql);
1

程序在执行到上面这行语句时,会将sql语句发送给DBMS(数据库管理系统),然后DBMS会将sql语句进行编译,但此时已经晚了,因为此时用户已经将一些非法语句拼接进了sql语句当中去,这样就会发生SQL注入。

10.7、 PreparedStatement对象(解决SQL注入问题)

PreparedStatement可以防止SQL注入,效率更好

  • 在JDBC中,使用Statement的子类PreparedStatement进行预编译

我们可以事先将sql语句传入PreparedStatement中,将要传入到sql语句中的参数使用?(占位符)来代替,那么该sql语句就会进行预编译,之后将获取的参数通过PreparedStatement中的set(类型)方法传入编译后的sql语句中,这样sql语句就会先被编译再进行传值,用户输入的信息不会直接参与到sql语句的编译当中,就防止了sql注入的问题。

 ps = conn.prepareStatement("select * from s_student where name = ? and password = ?");//先预编译
            //一个问号表示一个占位符将来接收一个值
            ps.setString(1,loginName);
            ps.setString(2,loginPwd);
            rs = ps.executeQuery();    // 执行查询

  • 插入
//把配置以及关闭资源放在一个java类里utils.jdbcUtils

private   static   String   url="jdbc:mysql://localhost:3306/test";
private   static   String   username="root";
private   static   String   password="root";
static{
	      Class.forName("com.mysql.jdbc.Driver");
	}
	
public static   Connection   getConn(){
		Connection   connection=DriverManager.getConnection(url,username,password);
		return  connection;
	}

//关闭资源
public  static   void     close(ResultSet rs,Perparedstment perparedstment,Connection conn){
		if(!Objects.isNull(rs)){rs.close();}
        			if(!Objects.isNull(perparedstment)){perparedstment.close()}
		if(!Objects.isNull(conn)){conn.close();}
	}
}	

//插入操作

package com.qian;
import com.qian.utils.jdbcUtils;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class Test01 {
    public static void main(String[] args) throws SQLException {
        Connection connection= null;
        PreparedStatement pstm=null;
        try {
            connection = jdbcUtils.getConnection();
            //区别
            //使用问好占位符代替参数
            String sql = "insert into users(id,`NAME`) values(?,?)";
            
            pstm = connection.prepareStatement(sql);//预编译sql,先写sql然后不执行
            
            //手动赋值
            pstm.setInt(1,6);
            pstm.setString(2,"SANJIN");
            
            //执行
            int i = pstm.executeUpdate();
            if (i>0){
                System.out.println("插入成功");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {

                jdbcUtils.release(connection,pstm,null);

        }
    }
}

10.8、 使用IDEA连接数据库

  • 在数据库中添加mysql
  • 和使用可视化工具一样
  • 也可以编写执行sql

10.9、 JDBC操作事务

  1. ACID原则

原子性、一致性、隔离性、持久性

  1. 隔离性的问题:
  • 脏读:一个事务读取了另一个没有提交的事务
  • 不可重复读:在同一个事务内,重复读取表中的数据,表数据发生了改变
  • 虚读:在同一个事务内,读取到了别人插入的数据,导致前后读出来结果不一致
  1. 代码
package com.qian.jdbc;

import com.qian.utils.JdbcUtils;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;


public class TestTransaction {
    public static void main(String[] args) throws SQLException {
        Connection conn1 =null;
        PreparedStatement st=null;
        ResultSet rs = null;
        try {
             conn1 = JdbcUtils.getConn();
            //关闭数据库的自动提交功能,自动会开启事务
            conn1.setAutoCommit(false);
            //
            String sql1 ="update account set money-100 where name ='A'";
            st = conn1.prepareStatement(sql1);
            st.executeUpdate();


            String sql2 ="update account set money+100 where name ='B'";
            st = conn1.prepareStatement(sql2);
            st.executeUpdate();
            //业务完毕,提交事务
            conn1.commit();
            System.out.println("成功");


        } catch (SQLException e) {
            try {
                conn1.rollback();//如果失败则回滚事务
            } catch (SQLException e1) {
                e1.printStackTrace();
            }
            e.printStackTrace();
        }finally {
           JdbcUtils.close(rs,st, conn1);
        }

    }
}

10.10、 数据库连接池

  1. 数据库连接—执行完毕—释放
  • 连接–释放 十分浪费系统资源
  • 池化技术 :准备一些预先的资源,过来就连接预先准备好的

-----开门–业务员:等待 – 服务—

常用连接数 10个

最小连接数:10

最大连接数 15 业务最高承载上限

排队等候,等待超时:…

编写连接池,实现一个接口 DataSource

  1. 开源数据源实现
  • DBCP
  • C3P0
  • Druid:阿里巴巴

使用了这些数据库连接池之后,我们在项目开发中就不需要编写连接数据库的代码了!

  1. DBCP 连接池
  • 需要的jar包(Maven依赖导入jar包)

<dependency>
    <groupId>commons-poolgroupId>
    <artifactId>commons-poolartifactId>
    <version>1.6version>
dependency>



<dependency>
    <groupId>commons-dbcpgroupId>
    <artifactId>commons-dbcpartifactId>
    <version>1.4version>
dependency>



  1. C3P0连接池
  • 需要的jar包(用maven依赖导入jar包)

<dependency>
    <groupId>com.mchangegroupId>
    <artifactId>mchange-commons-javaartifactId>
    <version>0.2.19version>
dependency>



<dependency>
    <groupId>com.mchangegroupId>
    <artifactId>c3p0artifactId>
    <version>0.9.5.5version>
dependency>
  1. 结论
  • 无论使用什么数据源,本质还是一样的,DataSource接口不会变,方法就不会变

你可能感兴趣的:(数据库,数据库)