JDBC笔记记录

1、JDBC 是什么?

​ Java Database connectivity(java语言连接数据库)

2、JDBC本质是什么?

​ JDBC是sun公司制定的一套接口(interface)

​ 接口都有调用者和实现者

​ 面向接口调用、面向接口写实现类、这都属于面向接口编程

​ 为什么要有面向接口编程?

​ 解耦合:降低程序的耦合度,提高程序的扩展力

​ 多态机制就是非常典型的:面向抽象编程(不需要面向具体编程)

JDBC编程6步

import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.SQLException;
//1:注册驱动 2:获取链接 3:获取数据库操作对象 4:执行sql 5:处理查询结果集 6:释放资源
public class JDBCTest01{
        public static void main(String[] args){
            try{
            //1、注册驱动
           //由于Driver是一个接口无法创建对象,所以需要new实现它的类
 java.sql.Driver driver = new com.mysql.jdbc.Driver();
            DriverManager.registerDriver(driver);
             //获取连接
                String url = "jdbc:mysql://127.0.0.1:3306/bjpowernode";
                String user = "root";
                String password = "333"
            Connection conn = DriverMabager.getConnection(url,user,password);
                system.out.println("数据库连接对象 = " + conn)
            }catch(SQLException e){
                e.printStackTrace();
            }

        }
    }

删除操作

import java.sql.*;
public class Test02{
    public static void main(String[] args){
        Connection conn = null;
        Statement stmt = null;
        try{
            //注册驱动
            DriverManager.registerDriver(new com.mysql.jdbc.Driver());
            //获取链接
            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/bjpiwernode","root","333");
            //获取数据库操作对象
            stmt = conn.createStatement();
            //执行sql JDCB sql语句不需要写分号。
            String sql = "delete from dept where deptno = 40";
            int count = stmt.excuteUpdate(sql);
            System.out.print(connt ==1 ? "删除成功":"删除失败")
            
        }catch(SQLException e){
            e.printStackTrace();
        }finally{
            //关闭资源
            if(stmt !=null){
                try{
                    stmt.close();
                }catch(SQLException e){
            	e.printStackTrace();
        }
                if(conn !=null){
                try{
                    conn.close();
                }catch(SQLException e){
            	e.printStackTrace();
        }
                
            }
        }
    }
    
}

P14(笔记)

* 实现功能
*   1:需求:模拟用户登录功能
*   2:描述:程序运行的时候,提供一个输入的入口,能让用户输入账户和密码
*           用户输入用户名和密码后,提交信息,Java程序收集到信息。
*           java程序连接数据库,验证用户名和密码是否正确
*           合法显示成功,不合法显示不成功。
*   3:数据的准备
*   在实际开发中,表的设计会使用专业的建模工具,安装powerde'signer
*   使用pd工具来进行数据库的表设计。(参考user-login.sql)

PowerDesigner (用于建模型)

键表的步骤在视频观看。

主要碰到的问题是 修改记事本的编码,在cmd’->mysql没有生效。

修改步骤: 首先查看表的编码格式 show create table t_user;

​	[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-G8JDdBNm-1624890369149)(C:\Users\xxacy\AppData\Roaming\Typora\typora-user-images\image-20210625000123428.png)]

修改的命令:alter table t_user default character set utf8;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Z5TdCLQv-1624890369151)(C:\Users\xxacy\AppData\Roaming\Typora\typora-user-images\image-20210625000225050.png)]

但是发现还是报错。

还要修改每一条语句:alter table t_user change loginPwd loginPwd varchar(255) character set utf8; 其他一样

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PPwGYmlq-1624890369154)(C:\Users\xxacy\AppData\Roaming\Typora\typora-user-images\image-20210625002153837.png)]

修改后再插入数据

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Hi7uirWI-1624890369157)(C:\Users\xxacy\AppData\Roaming\Typora\typora-user-images\image-20210625002257704.png)]


P17(笔记)

今天一整天在处理报错问题。切记mysql6一下的数据库版本不需要在url地址加上时区。

程序代码

package com.bjpowernode.jdbc;


import java.sql.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;

/*
* 实现功能
*   1:需求:模拟用户登录功能
*   2:描述:程序运行的时候,提供一个输入的入口,能让用户输入账户和密码
*           用户输入用户名和密码后,提交信息,Java程序收集到信息。
*           java程序连接数据库,验证用户名和密码是否正确
*           合法显示成功,不合法显示不成功。
*   3:数据的准备
*   在实际开发中,表的设计会使用专业的建模工具,安装powerdesigner
*   使用pd工具来进行数据库的表设计。(参考user-login.sql)
*
*
* */
public class JDBCTest06 {
    public static void main(String[] args) {
        //初始化一个界面
       Map<String,String> userLoginInfo = initUI();
        //验证用户名和密码
        boolean loginSuccess = login(userLoginInfo);
        //最后输出结果
        System.out.println(loginSuccess ? "登录成功" : "登录失败");

    }

    private static boolean login(Map<String, String> userLoginInfo) {
        //打标记意识
        boolean loginSuccess = false;
        //单独定义变量
        String loginName = userLoginInfo.get("loginName");
        String loginPwd = userLoginInfo.get("loginPwd");

        //JDBC代码1
        Connection conn = null;
        Statement stmt = null;
        ResultSet rs = null;
        try {
            //注册驱动
            Class.forName("com.mysql.jdbc.Driver");
            //获取连接
            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/bjpowernode","root","333");
            //获取数据库操作对象
            stmt = conn.createStatement();
            //执行sql
            String sql = "select * from t_user where loginName = '"+loginName+"' and loginPwd = '"+loginPwd+"'";
            rs = stmt.executeQuery(sql);
            //处理数据结果集
            if(rs.next()){
                loginSuccess = true;
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            //释放资源
            if (rs !=null){
                try{
                    rs.close();
                }catch (SQLException e){
                    e.printStackTrace();
                }
            }
            if (stmt !=null){
                try{
                    stmt.close();
                }catch (SQLException e){
                    e.printStackTrace();
                }
            }
            if (conn !=null){
                try{
                    conn.close();
                }catch (SQLException e){
                    e.printStackTrace();
                }
            }
        }
        return loginSuccess;
    }

    /*
        * 初始化用户界面
        * @return 用户输入的用户名和 密码等信息
        *
        * */
    private static Map<String, String> initUI() {
        Scanner s = new Scanner(System.in);
        System.out.print("用户名:");
        String loginName = s.nextLine();

        System.out.print("密码:");
        String loginPwd = s.nextLine();
        Map<String,String> userLoginInfo = new HashMap<>();
        userLoginInfo.put("loginName",loginName);
        userLoginInfo.put("loginPwd",loginPwd);
        return userLoginInfo;
    }
}

主要问题。程序启动无法正常执行;

​ 原因:开启了两个数据库 一个是5.5版本 一个是5.7版本。 同时占用这3306端口

而且5.5版本的数据库在最开始的时候也做了jdbc练习,所以里面有同名同姓的数据库和表。系统默认是走的5.5版本的,实际上idea的程序是要走5.7,数据无法匹配所以无法成功。 关闭了5.5重新导入数据。测试成功。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-w7ma3HZr-1624890369159)(C:\Users\xxacy\AppData\Roaming\Typora\typora-user-images\image-20210625232501172.png)]


SQL注入(黑客经常使用)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Qy2ywUNr-1624890369160)(C:\Users\xxacy\AppData\Roaming\Typora\typora-user-images\image-20210625232742675.png)]

导致sql注入的原因是什么?

用户输入的信息中含有sql语句的关键字,并且这些关键字参与sql语句的编译过程导致sql语句的原本的意思被扭曲,从而达到sql注入。

代码

package com.bjpowernode.jdbc;

import java.sql.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;

public class JDBCTest07 {
    //解决sql注入的问题
    public static void main(String[] args) {
        //初始化一个界面
        Map<String,String> userLoginInfo = initUI();
        //验证用户名和密码
        boolean loginSuccess = login(userLoginInfo);
        //最后输出结果
        System.out.println(loginSuccess ? "登录成功" : "登录失败");

    }

    private static boolean login(Map<String, String> userLoginInfo) {
        //打标记意识
        boolean loginSuccess = false;
        //单独定义变量
        String loginName = userLoginInfo.get("loginName");
        String loginPwd = userLoginInfo.get("loginPwd");

        //JDBC代码1
        Connection conn = null;
//        Statement stmt = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        try {
            //注册驱动
            Class.forName("com.mysql.jdbc.Driver");
            //获取连接
            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/bjpowernode","root","333");
            //获取预编译的数据库操作对象
            //sql语句中。一个?代表一个占位符,一个?将来接收一个”值“,注意。占位符不能用单引号括起来。
            String sql = "select * from t_user where loginName = ? and loginPwd = ?";
            //程序执行到这里。会发送sql语句给DBMS,然后DBMS在进行sql预先编译。
            ps = conn.prepareStatement(sql);
            //给占位符传值,JDBC下标从1开始。
            ps.setString(1,loginName);
            ps.setString(2,loginPwd);
            //执行sql
            rs = ps.executeQuery();
            //处理数据结果集
            if(rs.next()){
                loginSuccess = true;
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            //释放资源
            if (rs !=null){
                try{
                    rs.close();
                }catch (SQLException e){
                    e.printStackTrace();
                }
            }
            if (ps !=null){
                try{
                    ps.close();
                }catch (SQLException e){
                    e.printStackTrace();
                }
            }
            if (conn !=null){
                try{
                    conn.close();
                }catch (SQLException e){
                    e.printStackTrace();
                }
            }
        }
        return loginSuccess;
    }

    /*
     * 初始化用户界面
     * @return 用户输入的用户名和 密码等信息
     *
     * */
    private static Map<String, String> initUI() {
        Scanner s = new Scanner(System.in);
        System.out.print("用户名:");
        String loginName = s.nextLine();

        System.out.print("密码:");
        String loginPwd = s.nextLine();
        Map<String,String> userLoginInfo = new HashMap<>();
        userLoginInfo.put("loginName",loginName);
        userLoginInfo.put("loginPwd",loginPwd);
        return userLoginInfo;
    }
}

解决sql注入:

​ 只要用户提供信息不参与sql语句编译就能解决问题。

​ 即便是有sql语句关键字。但是没用参与,不起作用。

要想用户信息不参与sgz语句的编译,那么必须使用java.sql.PreparedStatementPreparedstatement接口继承了java.sql.statement

Preparedstatement是属于预编译的数据库操作对象。
reparedstatement的原理是:预先对sql语句的框架进行编译,然后再给sql语句传值。


对比点:statement和preparedstatement?

statement 有sql注入问题。preparedstatement解决了sql注入问题/

执行效率方面:

​ statement是编译一次执行一次,preparedstatement是编译一次,执行N次,且会在编译阶段做类型安全检查

​ preparedstatement 执行效率高

注意:当业务需求SQL注入的话 必须使用statement 用来拼接。


PreparedStatement完成增删改

package com.bjpowernode.jdbc;

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

public class JDBCTest09 {
    public static void main(String[] args) {
        //第一步 搭架子
        Connection conn = null;
        PreparedStatement ps = null;
        try {
            //第二步 注册驱动
            Class.forName("com.mysql.jdbc.Driver");
            //第三步 获取连接
            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/bjpowerbode","root","333");
            //第四步 获取预编译的数据库操作对象
//            String sql = "insert into dept(delete,dname,loc) value(?,?,?)";
//            //编译sql语句
//            ps = conn.prepareStatement(sql);
//            //给编译语句传值
//            ps.setInt(1,60);
//            ps.setString(2,"销售部");
//            ps.setString(3,"上海");

//            String sql = "update dapt set dname =?, loc = ? where deptno = ?";
//            //编译sql语句
//            ps = conn.prepareStatement(sql);
//            //给编译语句传值
//            ps.setInt(1,60);
//            ps.setString(2,"销售部");
//            ps.setString(3,"上海");
            String sql = "delete from dept where = deptno = ?";
            ps = conn.prepareStatement(sql);
            ps.setInt(1,60);
            //第五步 执行sql
            int count = ps.executeUpdate();
            System.out.println(count);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //释放资源
            if (ps != null) {
                try {
                    ps.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (conn != null) {
                try {
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}


JDBC事务机制

什么是自动提交?

​ 只要任意一条DML语句(数据操纵语句: 插入:INSERT、更新:UPDATE、删除:DELETE),则自动提交一次。这是JDBC的默认行为,但是在实际业务中,通常都是N条DML语句共同联合来完成的,必须保证他们这些DML语句在同一个事务中同步成功或者失败。

以下程序来验证JDBC的事务是否自动提交机制(结果:JDBC只要执行任意一条DML语句就提交一次)

Class public JDBCTest10{
    public static void main(String[] args){
        //搭架子
       Connection conn = null;
        PreparedStatement ps = null;
     try{   
        //注册驱动
        Class.forName("com.mysql.jdbc.Driver");
        //获取连接
        conn.DriverManager.getConnection("jdbc:mysql://localhost:3306:/bjpowernode","root","333");
        //获取预编译数据库操作对象(1:写入sql语句 2:编译sql 3:传值)
         String sql = "update dept set dname = ? where deptno = ?";
         
         //第一次给占位符传值
         ps.conn.preparedStatement(sql);
         ps.setString(1,"xx部门");
         ps.setInt(2,30);
         //执行sql语句
         int count = ps.executeUpdate();
         
      	 // 重新给占位符传值(第二次执行)
          ps.setString(1,"yy部门");
          ps.setInt(2,20);
          int count = ps.executeUpdate();
        }catch(Exception e){
         e.printStackTrece();
     }finally{
        //释放资源
         if(ps != null){
             ps.close();
         }catch(SQLException e){
             e.printStackTrece();
         }
         if(conn != null){
             conn.close();
         }catch(SQLException e){
             e.printStackTrece();
         }
      }    
    }
}

转账演示事务

package com.bjpowernode.jdbc;

import java.sql.*;

/*
* sql 脚本
*  drop table if exists t_act;
*  create table t_act(
*       actno int,
*       balance double(7,2) //7表示有效数字,2表示小数位个数
*  );
*  insert into t_act(actno,balance) values(111,20000);
*  insert into t_act(actno,balance) values(222,0);
*  commit;
*  select * from t_act;
*
*
*
*
* */
public class JDBCTest11 {
    public static void main(String[] args) {
        Connection conn = null;
        PreparedStatement ps = null;

        try {
            Class.forName("com.mysql.jdbc.Driver");
            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/bjpowernode","root","333");

            //开启事务
            conn.setAutoCommit(false);

            String sql = "update t_act set balance = ? where actno = ?";
            ps = conn.prepareStatement(sql);

            //故意制造空指针异常。
            String s = null;
            s.toString();

            //给第一个?传值
            ps.setDouble(1,10000);
            ps.setInt(2,111);
            int count = ps.executeUpdate();

            //给第二个?传值
            ps.setDouble(1,10000);
            ps.setInt(2,222);
            count += ps.executeUpdate();

            System.out.println(count ==2 ? "转账成功" : "转账失败");
            conn.commit();

        } catch (Exception e) {
            //回滚事务
            if (conn != null){
                try{
                    conn.rollback();
                } catch (SQLException ex) {
                    ex.printStackTrace();
                }
            }
            e.printStackTrace();
        }finally {
            if (ps != null) {
                try {
                    ps.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (conn != null) {
                try {
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}


通过空指针异常,如果没加事务 commit rollback 会发现数据丢失

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-h6hxn5N7-1624890369161)(C:\Users\xxacy\AppData\Roaming\Typora\typora-user-images\image-20210628143252533.png)]

添加事务操作,要么一起完成,要么一起失败。保证数据的完整性


for update;(行级锁又叫悲观锁) 保证数据的准确性

select ename,job,sal from emp where job=‘MANAGER’ for update;(行级锁)

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值