JDBC操作笔记

步骤记录:

  1. 加载驱动
  2. 链接数据库,获取数据库对象 DriverManager
  3. 获取执行SQL的对象 Statement
  4. 获得返回的结果集
  5. 释放连接

关键词:
Connection 数据库链接对象
Statement 执行SQL语句的对象
ResultSet 返回的结果集对象

加载驱动DriverManager

//        1.加载驱动
//        com.mysql.jdbc.Driver,
//        Class.forName("com.mysql.jdbc.Driver");
//        报错
//        /*
//         Loading class `com.mysql.jdbc.Driver'. This is deprecated. The new driver class is `com.mysql.cj.jdbc.Driver'.
//         The driver is automatically registered via the SPI and manual loading of the driver class is generally unnecessary.
//         */
//       改成
        Class.forName("com.mysql.cj.jdbc.Driver");

URL


//2.用户信息和url
        //useUniconde = true&characterEncoding= utf8&useSSL=true
        String url = "jdbc:mysql://localhost:3306/jdbcstudy?useUniconde=true&characterEncoding= utf8&useSSL=true";
        String username = "root";
        String password = "1234";
//3.连接成功,数据库对象 (对象不为空代表数据库对象已经取得) Connection表示数据库对象
        Connection connection = DriverManager.getConnection(url, username, password);
//第二种合并写法
//链接数据库对象
        Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbcstudy","root","1234");
  		//mysql -- 3306
        //协议://jdbc:mysql://主机地址:端口号/数据库名?参数1&参数2&参数3;
		//oralce -- 1521
		//jdbc:oracle:thin:@localhost:1521:sid
		

链接数据库

 //3.连接成功,数据库对象 (对象不为空代表数据库对象已经取得) Connection表示数据库对象
        Connection connection = DriverManager.getConnection(url, username, password);
        //connection 代表数据库
       
        connection.rollback();//撤消在当前事务中所做的所有更改,并释放此 Connection对象当前持有的任何数据库锁。
        connection.commit();//
        connection.setAutoCommit();

执行SQL的对象 Statement /prepareStatement

//4.执行SQL的对象
        Statement statement = connection.createStatement();
//        PreparedStatement preparedStatement = connection.prepareStatement();
        //执行查询操作返回结果集
        statement.executeQuery("");
        //执行任何sql语句;
        statement.execute("");
        //执行更新,插入,删除操作,返回一个受影响的行数(int类型)
        statement.executeUpdate("");
	    //执行多个语句
        statement.executeBatch();

查询结果集 ResultSet

 		String sql = "SELECT * FROM users";
        //返回的结果集合(封装了所有查询结果)
        ResultSet resultSet = statement.executeQuery(sql);
        //不清楚类型的
        resultSet.getObject();
        //有类型的
        resultSet.getString();
        resultSet.getInt();
        resultSet.getFloat();
        resultSet.getDate();
        //移动到最前面
        resultSet.beforeFirst();
        //移动到最后面
        resultSet.afterLast();
        //移动到下一个
        resultSet.next();
        //移动到上一个
        resultSet.previous();
        //移动指定行
        resultSet.absolute(2);
        //遍历输出数据
        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"));
        }

释放资源(链接十分消耗资源)

  		resultSet.close();
        statement.close();
        connection.close();

statement对象

jdbc中的statement对象用于向数据库发送SQL语句,想完成对数据库的增删改查,只需要通过这个对象向数据库发送增删改查语句即可。
配置文件:
配置日志文件名:db.properties

driver = com.mysql.cj.jdbc.Driver
url =jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf-8&useSSL=true
username=root
password=1234

工具类:

package com.kuang.lesson02;

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");
            //加载驱动
            Class.forName(driver);

        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }

    }

    //获取连接
    public static Connection getConnection() throws SQLException {
        return DriverManager.getConnection(url, username, password);
    }

    public static void relese(Connection conn, Statement st, ResultSet rs) {

        if (rs != null) {
            try {
                rs.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }

            if (st != null) {
                try {
                    st.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }

            if (conn != null) {
                try {
                    conn.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
        }
    }
}

CRUD操作- create 添加/插入

package com.kuang.lesson02;

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

public class TestInsert {
    public static void main(String[] args) {
        Connection conn = null;
        Statement st = null;
        ResultSet rs = null;
        try {
            //数据库链接
            conn = JdbcUtils.getConnection();
            //获得SQL 的执行对象
            st = conn.createStatement();
            String sql = "INSERT INTO users(id,NAME,PASSWORD,email,birthday)" +
                    "VALUES(4,'kuangshen','123456','247367430@qq.com','2020-01-01')";

            int i = st.executeUpdate(sql);
            if (i > 0) {
                System.out.println("添加成功");
            }
            System.out.println(i);
        } catch (SQLException e) {
            e.printStackTrace();

        } finally {
            JdbcUtils.relese(conn, st, rs);
        }
    }
}

使用executeUpdate(String sql)方法进行数据操作

CRUD操作- delete 删除

package com.kuang.lesson02;

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

public class TestDelete {
    public static void main(String[] args) {
        Connection conn = null;
        Statement st = null;
        ResultSet rs = null;
        try {
            //数据库链接
            conn = JdbcUtils.getConnection();
            //获得SQL 的执行对象
            st = conn.createStatement();
            String sql = "DELETE FROM users WHERE id = 4";

            int i = st.executeUpdate(sql);
            if (i > 0) {
                System.out.println("删除成功");
            }
            System.out.println(i);
        } catch (SQLException e) {
            e.printStackTrace();

        } finally {
            JdbcUtils.relese(conn, st, rs);
        }
    }
}


CRUD操作- update 修改

package com.kuang.lesson02;

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

public class TestUpdate {
    public static void main(String[] args) {
        Connection conn = null;
        Statement st = null;
        ResultSet rs = null;
        try {
            //数据库链接
            conn = JdbcUtils.getConnection();
            //获得SQL 的执行对象
            st = conn.createStatement();
            String sql = "UPDATE users SET NAME = 'df',email = 'gg@qq.com' WHERE id = 1";

            int i = st.executeUpdate(sql);
            if (i > 0) {
                System.out.println("修改呢");
            }
            System.out.println(i);
        } catch (SQLException e) {
            e.printStackTrace();

        } finally {
            JdbcUtils.relese(conn, st, rs);
        }
    }
}

CRUD操作- read 查询

使用executeQuery(String sql)方法进行数据操作

package com.kuang.lesson02;

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

public class TestSelect {
    public static void main(String[] args) {
        Connection conn = null;
        Statement st = null;
        ResultSet re = null;
        try {
            //从工具类 JdbcUtils 获取 数据库链接对象 赋值给conn
            conn = JdbcUtils.getConnection();
            //获取执行sql语句的对象
            st = conn.createStatement();
            String sql = "SELECT * FROM users";
            re = st.executeQuery(sql);
            while (re.next()) {
                //查询大小写随意
                System.out.println("ID为" + re.getObject("id") + "名字为 " + re.getObject("name"));
            }
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            JdbcUtils.relese(conn,st,re);
            System.out.println("资源关闭成功");
        }
    }
}


SQL注入问题

sql存在都懂,会被攻击数据泄露 原因有sql会被拼接 or 等判断条件

package com.kuang.lesson02;

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

public class SQL注入 {
    public static void main(String[] args) {
        String username = "kuangshen";
        String password = "123456";
    login(username,password);
    }
    public static void login(String username ,String password){
        Connection conn = null;
        Statement st = null;
        ResultSet rs = null;
        try {
            conn = JdbcUtils.getConnection();
            st = conn.createStatement();
            //因为条件 1=1 永远满足,所以查询的时候匹配任何数据都是可以显示的.
                    String sql = "SELECT * FROM users WHERE NAME = 'kuangshen'OR 1=1 AND  PASSWORD = '123456' OR 1=1";
//                    String sql = "SELECT * FROM users WHERE NAME = 'kuangshen' AND  PASSWORD = '123456' ";
            rs = st.executeQuery(sql);
            while (rs.next()){
                System.out.println(rs.getString("name"));
                System.out.println(rs.getString("password"));
            }
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            JdbcUtils.relese(conn,st,rs);
        }
    }
}

PreparedStatement对象

可以防止SQL注入并且效率更高.

使用statement对象后进行sql注入导致数据泄露的例子:

package com.kuang.lesson03;


import com.kuang.lesson02.JdbcUtils;

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

public class SQL注入 {
    public static void main(String[] args) {
        String username = "kuangshen";
        String password = "123456";
    login(username,password);
    }
    public static void login(String username ,String password){
        Connection conn = null;
        Statement st = null;
        ResultSet rs = null;
        try {
            conn = JdbcUtils.getConnection();
            st = conn.createStatement();
            //因为条件 1=1 永远满足,所以查询的时候匹配任何数据都是可以显示的.
                    String sql = "SELECT * FROM users WHERE NAME = 'kuangshen'OR 1=1 AND  PASSWORD = '123456' OR 1=1";
//                    String sql = "SELECT * FROM users WHERE NAME = 'kuangshen' AND  PASSWORD = '123456' ";
            rs = st.executeQuery(sql);
            while (rs.next()){
                System.out.println(rs.getString("name"));
                System.out.println(rs.getString("password"));
            }
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            JdbcUtils.relese(conn,st,rs);
        }
    }

}

使用PreparedStatement的例子

package com.kuang.lesson03;


import com.kuang.lesson02.JdbcUtils;

import java.sql.*;

public class SQL注入 {
    public static void main(String[] args) {
        String username = "kuangshen";
        String password = "123456";
//    login(username,password);
        //查询出空结果;
        login("'' or 1=1", "123456");
    }

    public static void login(String username, String password) {
        Connection conn = null;
        PreparedStatement st = null;
        ResultSet rs = null;
        try {
            conn = JdbcUtils.getConnection();

            //因为条件 1=1 永远满足,所以查询的时候匹配任何数据都是可以显示的.
            String sql = "SELECT * FROM users WHERE NAME = ? AND  PASSWORD = ?";
            //PreparedStatement 能防止sql注入的本事,就是吧传递进来的参数当做字符
            //如果存在转义字符,就直接被忽略掉,从而防止sql注入
//            String sql = "SELECT * FROM users WHERE NAME = 'kuangshen' AND  PASSWORD = '123456' ";
            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"));
            }
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        } finally {
            JdbcUtils.relese(conn, st, rs);
        }
    }

}

增加数据

package com.kuang.lesson03;

import com.kuang.lesson02.JdbcUtils;

import java.sql.Connection;
import java.util.Date;
import java.sql.PreparedStatement;
import java.sql.SQLException;

public class TestInsert {
    public static void main(String[] args) {
        Connection conn = null;
        PreparedStatement st = null;

        try {
            conn = JdbcUtils.getConnection();
            //使用 ? 占位符代替参数
            String sql = "insert into users(id,NAME,PASSWORD,email,birthday) values (?,?,?,?,?)";
            //区别为需要一个预编译的操作;
            //手动给参数
            st = conn.prepareStatement(sql);
            st.setInt(1,1);
            st.setString(2,"qiangjian");
            st.setString(3,"1232456");
            st.setString(4,"787com");
            //setDate方法需要java.sql.Date 类型
            st.setDate(5,new java.sql.Date(new Date().getTime()));
            int i = st.executeUpdate();
            if(i>0){
                System.out.println("成功");
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally{
            JdbcUtils.relese(conn,st,null);
        }
    }
}

删除数据

package com.kuang.lesson03;

import com.kuang.lesson02.JdbcUtils;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Date;

public class TestDelete {
    public static void main(String[] args) {
        Connection conn = null;
        PreparedStatement st = null;

        try {
            conn = JdbcUtils.getConnection();
            //使用 ? 占位符代替参数
            String sql = "delete from users where id = ?";
            //区别为需要一个预编译的操作;
            st = conn.prepareStatement(sql);
            //手动给参数
            st.setInt(1, 1);
            int i = st.executeUpdate();
            if (i > 0) {
                System.out.println("删除");
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            JdbcUtils.relese(conn, st, null);
        }
    }
}

修改数据

package com.kuang.lesson03;

import com.kuang.lesson02.JdbcUtils;

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

public class TestUpdate {
    public static void main(String[] args) {
        Connection conn = null;
        PreparedStatement st = null;

        try {
            conn = JdbcUtils.getConnection();
            //使用 ? 占位符代替参数
            String sql = "update users set name = ? where id = ?;";
            //区别为需要一个预编译的操作;
            st = conn.prepareStatement(sql);
            //手动给参数
            st.setString(1,"erzi");
            st.setInt(2, 2);
            int i = st.executeUpdate();
            if (i > 0) {
                System.out.println("更新");
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            JdbcUtils.relese(conn, st, null);
        }
    }

}

查询数据

package com.kuang.lesson03;

import com.kuang.lesson02.JdbcUtils;

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

public class TestSelect {
    public static void main(String[] args) {
        Connection conn = null;
        PreparedStatement st = null;
        ResultSet rs = null;
        try {
            conn = JdbcUtils.getConnection();
            String sql = "select * from users";
            //预编译
            st = conn.prepareStatement(sql);
            //传递参数
//            st.setInt(1,1);
            //执行
            rs = st.executeQuery();
            while (rs.next()){
                System.out.println(rs.getString("name"));
            }
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            JdbcUtils.relese(conn,st,rs);
        }
    }
}

事务

//要么都成功,要么都失败

acid原则

  • 原子性 : 要么全部完成,要么都不完成
  • 一致性 : 总数不变
    - 隔离性 : 多个进程互不干扰
  • 持久性 : 一旦提交不可逆,就持久化到数据库了
    隔离性的问题:
    脏读 : 一个事务内读取了另一个没有提交的事务
    不可重复读 : 在同一个事务内,重复读取表中的数据,表数据发生改变.
    虚读(幻读) : 在一个事务内 ,读取到了别人插入的数据,导致前后结果不一致

开启事务

业务执行完毕,提交事务

在catch语句中显式调用


package com.kuang.lesson04;

import com.kuang.lesson02.JdbcUtils;

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

public class TestTransaction1 {
    public static void main(String[] args) {
        Connection conn = null;
        PreparedStatement st = null;
        ResultSet rs = null;
        try {
            conn = JdbcUtils.getConnection();
            String sql1 = "update jdbcstudy.acconut set money = money-100 where name = 'A'";
            st = conn.prepareStatement(sql1);
            st.executeUpdate();
            System.out.println("ok1");
            
            //在使用这种语句表名 在运行中SQL语句的运行失败.
            int x = 1/0;
            //如果不使用事务的情况下在运行sql1语句后报错,从而导致整个事务没有运行完毕,造成数据丢失
            
            String sql2 = "update jdbcstudy.acconut set money = money+100 where name = 'B'";
            st = conn.prepareStatement(sql2);
            st.executeUpdate();
            // 业务完毕,提交事务
            System.out.println("ok2");
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            JdbcUtils.relese(conn,st,rs);
        }
    }
}

原始数据
原始数据
如果不使用事务,在运行到中间的时候就会因为int x = 1/0而报错,从而只运行了sql语句,没有运行sql2语句,在实际使用情况下.会造成数据的损失.
损失后的数据

package com.kuang.lesson04;

import com.kuang.lesson02.JdbcUtils;

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

public class TestTransaction1 {
    public static void main(String[] args) {
        Connection conn = null;
        PreparedStatement st = null;
        ResultSet rs = null;
        try {
            conn = JdbcUtils.getConnection();
            //事务要关闭数据库的自动提交,也会同时开启事务
            conn.setAutoCommit(false);
            String sql1 = "update jdbcstudy.acconut set money = money-100 where name = 'A'";
            st = conn.prepareStatement(sql1);
            st.executeUpdate();
            System.out.println("ok1");
            //在使用这种语句表名 在运行中SQL语句的运行失败.
            int x = 1/0;
            //如果不使用事务的情况下在运行sql1语句后报错,从而导致整个事务没有运行完毕,造成数据丢失


            String sql2 = "update jdbcstudy.acconut set money = money+100 where name = 'B'";
            st = conn.prepareStatement(sql2);
            st.executeUpdate();
            // 业务完毕,提交事务
             conn.commit();;
            System.out.println("ok");
        } catch (SQLException throwables) {
//           如果失败也会默认回滚
//            try {
//                conn.rollback();
//            } catch (SQLException e) {
//                e.printStackTrace();
//            }
            throwables.printStackTrace();
        }finally {
            JdbcUtils.relese(conn,st,rs);
        }
    }
}

报错提示
在这里插入图片描述
可以发现数据并没有变化在这里插入图片描述

数据库链接池

数据库链接 — 执行完毕 — 释放
但是链接 到 释放这个过程十分消耗系统资源.
所以我们要是用 池化技术 : 将数据库链接预留下来放入池中,以备下次使用.
参数:
最小连接数 : 10(多与常用连接数相同)
最大连接数 : 15 通常为最高承载上限
等待超时 : 100ms
编写连接池 实现一个接口 DayeSource

开源数据库
DBCP
C3P0
Druid : 阿里巴巴
使用了这些数据库连接池之后,我们在项目开发就不需要编写链接数据库的代码!
DBCP
需要用到的jar包
commonts-dbcp-1.4 , commons-pool-1.6;

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值