10、JDBC(重点)

10.1 数据库驱动

驱动:声卡,显卡,数据库

10.2 JDBC

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

这些规范的实现由具体的厂商去做

对于开发人员来说,我们只需要掌握JDBC的接口操作即可

java.sql

javax.sql

还需要导入数据库驱动包

10.3 第一个JDBC程序

创建测试数据库

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,'zhansan','123456','zs@sina.com','1980-12-04'),
(2,'lisi','123456','lisi@sina.com','1981-12-04'),
(3,'wangwu','123456','wangwu@sina.com','1979-12-04')

  1. 创建一个普通项目

  2. 导入数据库驱动

  3. 编写测试代码

package jdbcdemo1;
 
import java.sql.*;
 
public class jdbcdemo2 {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        //1. 加载驱动
        Class.forName("com.mysql.jdbc.Driver");//固定写法
        //2. 用户信息和url
        //useUnicode=true&characterEncoding=utf8&&useSSL=true
        String url ="jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&&useSSL=false";
        String username = "root";
        String password = " ";
        //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("password:"+resultSet.getObject("PASSWORD"));
            System.out.println("email:"+resultSet.getObject("email"));
            System.out.println("birthday:"+resultSet.getObject("birthday"));
            System.out.println("====================================");
        }
        //6. 释放连接
        resultSet.close();
        statement.close();
        connection.close();
    }
}

步骤总结:

  1. 加载驱动

  2. 连接数据库 DriverManager

  3. 获取执行SQL的对象 Statement

  4. 获得返回的结果集

  5. 释放连接

DriverManager

//DriverManager.registerDriver(new com.mysql.jdbc.Driver());
Class.forName("com.mysql.jdbc.Driver");//固定写法
Connection connection= DriverManager.getConnection(url,name,password);

//connection代表数据库
//数据库设置自动提交
//事务提交
//事务回滚
connection.rollback();
connection.commit();
connection.setAutoCommit();

URL

String url ="jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&&useSSL=false";

//mysql 默认3306
//协议://主机地址:端口号/数据库名?参数1&参数2&参数3

//Oracle   1521
//jdbc:oralce:thin:@localhost:1521:sid

statement 执行SQL的对象 pPrepareStatement 执行SQL的对象

String sql="SELECT * FROM users";//编写Sql

statement.executeQuery();
statement.execute(); 
statement.executeUpdate(); //更新,插入,删除,返回一个受影响的行数

ResultSet 查询的结果集,封装了所以的查询结果

  • 获得指定的数据类型

    ResultSet resultSet = statement.executeQuery(sql);//返回的结果集,结果集中封装了我们全部查询的结果
            resultSet.getObject();//在不知道列类型下使用
            resultSet.getString();//如果知道则指定使用
            resultSet.getInt();
    
  • 遍历,指针

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

释放内存

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

10.4 statement对象

  • Jdbc中的statement对象用于向数据库发送SQL语句,想完成对数据库的增删改查,只需要通过这个对象向数据库发送增删改查语句即可。

  • Statement对象的executeUpdate方法,用于向数据库发送增、删、改的sq|语句, executeUpdate执行完后, 将会返回一个整数(即增删改语句导致了数据库几行数据发生了变化)。

  • Statement.executeQuery方法用于向数据库发生查询语句,executeQuery方法返回代表查询结果的ResultSet对象。

//CRUD操作-create
//使用executeUpdate(String sql)方法完成数据添加操作,示例操作:
 
 Statement statement = connection.createStatement();
        String sql = "insert into user(...) values(...)";
        int num = statement.executeUpdate(sql);
        if(num>0){
            System.out.println("插入成功");
        }
//CRUD操作-delete
//使用executeUpdate(String sql)方法完成数据删除操作,示例操作:
 
Statement statement = connection.createStatement();
        String sql = "delete from user where id =1";
        int num = statement.executeUpdate(sql);
        if(num>0){
            System.out.println("删除成功");
        }
//CURD操作-update
 //使用executeUpdate(String sql)方法完成数据修改操作,示例操作:
 
Statement statement = connection.createStatement();
        String sql = "update user set name ='' where name = ''";
        int num = statement.executeUpdate(sql);
        if(num>0){
            System.out.println("修改成功");
        }
//CURD操作-read
//使用executeUpdate(String sql)方法完成数据查询操作,示例操作:
 
Statement statement = connection.createStatement();
        String sql = "select * from  user where id =1";
        ResultSet rs= statement.executeQuery(sql);
        if(rs.next()){
            System.out.println("");
        }

10.4.1 代码实现

  • 提取工具类

    package com.kuang.lesson02.utils;
     
    import java.io.IOException;
    import java.io.InputStream;
    import java.sql.*;
    import java.util.Properties;
     
    public class JdbcUtils {
        private static String driver = null;
        private static String url = null;
        private static String username = null;
        private static String password = null;
        static {
            try{
                InputStream in = JdbcUtils.class.getClassLoader().getResourceAsStream("db.properties");
                Properties properties = new Properties();
                properties.load(in);
                driver=properties.getProperty("driver");
                url=properties.getProperty("url");
                username=properties.getProperty("username");
                password=properties.getProperty("password");
     
        //1.驱动只用加载一次
                Class.forName(driver);
     
            } catch (IOException e) {
                e.printStackTrace();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
    
        //2.获取连接
        public static Connection getConnection() throws Exception{
            return DriverManager.getConnection(url, username, password);
        }
        //3.释放资源
        public static void release(Connection conn, Statement st, ResultSet rs) throws SQLException {
     
            if(rs!=null){
                rs.close();
            }
            if (st!=null){
                st.close();
            }
            if(conn!=null){
                conn.close();
            }
     
        }
    }
    
  • 编写增删改的方法,exectueUpdate

    package com.kuang.lesson02.utils;
     
    import java.sql.Connection;
    import java.sql.ResultSet;
    import java.sql.Statement;
    import static com.kuang.lesson02.utils.JdbcUtils.*;
     
    public class TestInnsert {
        public static void main(String[] args){
            Connection conn =null;
            Statement st = null;
            ResultSet rs =null;
            try {
                 conn = getConnection();//获取连接
                st = conn.createStatement();//获取SQL执行对象
                String sql = "INSERT INTO users(id,`NAME`,`PASSWORD`,`email`,`birthday`)" +
                        "VALUES(5,'sanjin','123456','233223@qq.com','2020-01-01')";
     
                int i = st.executeUpdate(sql);
                if(i>0){
                    System.out.println("插入成功");
                }
            JdbcUtils.release(conn,st,rs);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    
  • 查询 executeQuery

    package jdbcdemo1;
    
    import jdbcdemo1.utis.jdbcutis;
    import java.sql.Connection;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.sql.Statement;
    import static jdbcdemo1.utis.jdbcutis.*;
     
    public class TestInnsert {
        public static void main(String[] args) throws SQLException {
            Connection conn =null;
            Statement st = null;
            ResultSet rs =null;
            try {
                 conn = getConnection();//获取连接
                st = conn.createStatement();//获取SQL执行对象
                String sql = "select * from users";
                rs=st.executeQuery(sql);//查询完毕返回结果集
     
                while (rs.next()){
                    System.out.println(rs.getString("NAME"));
                }
            JdbcUtils.release(conn,st,rs);
            } catch (Exception e) {
                e.printStackTrace();
            }finally {
                JdbcUtils.release(conn,st,rs);
            }
        }
    }
    

10.4.2 SQL注入问题

sql存在漏洞,会被攻击导致数据泄露 SQL会被拼接

package jdbcdemo1;
 
import jdbcdemo1.utis.jdbcutis;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import static jdbcdemo1.utis.jdbcutis.*;
 
public class SQL注入 {
    public static void main(String[] args) {
        //SQL注入
 login("' or '1=1","123456");
    }
    public static void login(String name,String password){
        Connection conn =null;
        Statement st = null;
        ResultSet rs =null;
        try {
            conn = getConnection();//获取连接
            st = conn.createStatement();//获取SQL执行对象
            String sql = "select * from users where `NAME`='"+ name +"'  AND `PASSWORD`='"+ password +"'" ;
            rs=st.executeQuery(sql);//查询完毕返回结果集
 
            while (rs.next()){
                System.out.println(rs.getString("NAME"));
            }
            JdbcUtils.release(conn,st,rs);
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            try {
                JdbcUtils.release(conn,st,rs);
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
    }
}

10.5 PreparedStatement对象

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

新增

package jdbcdemo1;
 
import jdbcdemo1.utis.jdbcutis;
import java.sql.*;
import java.util.Date;
import static jdbcdemo1.utis.jdbcutis.*;
 
public class preparestatement {
    public static void main(String[] args) {
        Connection conn=null;
        PreparedStatement st=null;
 
        try {
 
                conn=jdbcutis.getConnection();
            String sql="INSERT INTO users(id,`NAME`,`PASSWORD`,`email`,`birthday`) values (?,?,?,?,?)";
            st= conn.prepareStatement(sql);
 
            st.setInt(1,7);
            st.setString(2,"fulang");
            st.setString(3,"123456");
            st.setString(4,"fulang@sina.com");
            st.setDate(5,new java.sql.Date(new Date().getTime()));
            //zhixing
            
            int i = st.executeUpdate();
 
            if(i>0)
            {
                System.out.println("Insert Success");
            }
            jdbcutis.release(conn,st,null);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
package jdbcdemo1;
 
import jdbcdemo1.utis.jdbcutis;
import java.sql.*;
import java.util.Date;
import static jdbcdemo1.utis.jdbcutis.*;
 
public class preparestatement {
    public static void main(String[] args) {
        Connection conn=null;
        PreparedStatement st=null;
        ResultSet rs=null;
 
        try {
                conn=jdbcutis.getConnection();
            String sql="select * from users where id=?";
            st= conn.prepareStatement(sql);
            st.setInt(1,6);
            //zhixing
           rs= st.executeQuery();
           while (rs.next()){
               System.out.println("id:"+rs.getObject("id"));
               System.out.println("name:"+rs.getObject("NAME"));
               System.out.println("password:"+rs.getObject("PASSWORD"));
               System.out.println("email:"+rs.getObject("email"));
               System.out.println("birthday:"+rs.getObject("birthday"));
           }
            jdbcutis.release(conn,st,null);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

防止SQL注入本质,传递字符 带有“ ”,转义字符会被转义

package jdbcdemo1;
 
 
import jdbcdemo1.utis.jdbcutis;
 
import java.sql.*;
 
import static jdbcdemo1.utis.jdbcutis.*;
 
public class zhuru {
    public static void main(String[] args) {
        login("fulang","123456");
 
    }
 
    public static void login(String username,String password) {
        Connection conn=null;
        PreparedStatement st=null;
        ResultSet rs=null;
 
        try {
            conn = jdbcutis.getConnection();//获取连接
 
            String sql="select * from users where `NAME`=?  AND `PASSWORD`=?" ;
 
            st= conn.prepareStatement(sql);
 
            st.setString(1,username);
            st.setString(2,password);
 
            rs = st.executeQuery();
           while (rs.next()){
               System.out.println(rs.getString("NAME"));
               System.out.println(rs.getString("password"));
           }
            jdbcutis.release(conn,st,rs);
 
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

10.6 使用IDEA连接数据库

  1. 连接成功后,可以选择数据库
  2. 双击数据库
  3. 更新数据
  4. 编写sql代码的地方

10.7 JDBC事务

要么都成功,要么都失败

ACID原则

  • 原子性:要么全部完成,要么都不完成

  • 一致性:结果总数不变

  • 隔离性:多个进程互不干扰

  • 持久性:一旦提交不可逆,持久化到数据库了

  • 隔离性的问题:

  • 脏读: 一个事务读取了另一个没有提交的事务

  • 不可重复读:在同一个事务内,重复读取表中的数据,表发生了改变

  • 虚读(幻读):在一个事务内,读取到了别人插入的数据,导致前后读出来的结果不一致

代码实现

  1. 开启事务conn.setAutoCommit(false);
  2. 一组业务执行完毕,提交事务
  3. 可以在catch语句中显示的定义回滚,但是默认失败会回滚
package com.kuang.lesson04;

import com.kuang.lesson02.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class Action {
    public static void main(String[] args) {
        Connection conn =null;
        PreparedStatement ps = null;
        ResultSet rs = null;

        try {
            conn = JdbcUtils.getConnection();
            //关闭数据库的自动提交功能, 开启事务
            conn.setAutoCommit(false);
            //自动开启事务
            String sql = "update account set money = money-500 where id = 1";
            ps =conn.prepareStatement(sql);
            ps.executeUpdate();
            String sql2 = "update account set money = money-500 where id = 2";
            ps=conn.prepareStatement(sql2);
            ps.executeUpdate();

            //业务完毕,提交事务
            conn.commit();
            System.out.println("操作成功");
        } catch (Exception e) {
            try {
                //如果失败,则默认回滚
                conn.rollback();//如果失败,回滚
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
            e.printStackTrace();
        }finally {
            try {
                JdbcUtils.release(conn,ps,rs);
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
    }
}

10.8 数据库连接池

数据库连接–执行完毕–释放

连接–释放 十分浪费资源

池化技术: 准备一些预先的资源,过来就连接预先准备好的

常用连接数 100

最少连接数:100

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

排队等待,

等待超时:100ms

编写连接池,只需要实现一个接口 DateSource

开源数据源实现(拿来即用)

DBCP

C3P0

Druid: 阿里巴巴

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

DBCP(需要用到的jar包)

-- 配置文件
#DBCP数据源中定义好的名字
driverClassName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/jdbcstudy?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8&useSSl=true
username=root
password=123456
#初始化连接数
initialSize=10
#最大连接数
maxActive=50
#最大空闲连接
maxIdle=20
#最小空闲连接
minIdle=5
#最长等待超时时间 以毫秒为单位
maxWait=60000
 
connectionProperties=useUnicode=true;characterEncoding=UTF8
defaultAutoCommit = true
defaultReadOnly = defaultTransactionIsolation=READ_UNCOMMITTED
//工具类
package jdbcdemo1.utis;
 
import org.apache.commons.dbcp.BasicDataSource;
import org.apache.commons.dbcp.BasicDataSourceFactory;
import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
 
public class jdbcutisDbcp {
    private static DataSource datasource=null;
        static {
 
            try{
                InputStream in = jdbcutis.class.getClassLoader().getResourceAsStream("dbcpconfig.properties");
                Properties properties = new Properties();
                properties.load(in);
                //创建数据源   工厂模式
                datasource=BasicDataSourceFactory.createDataSource(properties);
 
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        //2.获取连接
        public static Connection getConnection() throws Exception{
            return datasource.getConnection();//数据源中获取连接
        }
        //3.释放资源
        public static void release(Connection conn, Statement st, ResultSet rs) throws SQLException {
 
            if(rs!=null){
                rs.close();
            }
            if (st!=null){
                st.close();
            }
            if(conn!=null){
                conn.close();
            }
        }
}
//TestDBCP
package jdbcdemo1;
 
import jdbcdemo1.utis.jdbcutisDbcp;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
 
public class TestDBCP {
    public static void main(String[] args) {
        Connection conn=null;
        PreparedStatement st=null;
        ResultSet rs=null;
 
        try {
 
            conn=jdbcutisDbcp.getConnection();
            String sql="select * from users where id=?";
            st= conn.prepareStatement(sql);
            st.setInt(1,1);
            //zhixing
            rs= st.executeQuery();
            while (rs.next()){
                System.out.println("id:"+rs.getObject("id"));
                System.out.println("name:"+rs.getObject("NAME"));
                System.out.println("password:"+rs.getObject("PASSWORD"));
                System.out.println("email:"+rs.getObject("email"));
                System.out.println("birthday:"+rs.getObject("birthday"));
            }
            jdbcutisDbcp.release(conn,st,rs);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

结论

无论使用什么数据源,本质(使用DataSource接口)是不变的,DateSource接口不会变,方法就不会变

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

秃头酱酱

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值