JDBC学习笔记8.18

1.JDBC是什么?

Java DataBase Connectivity

2.JDBC本质

SUN公司的一套接口,面向接口编程。
java.sql.*包下的
在这里插入图片描述
注: 各大厂家对JDBC接口的实现类被称为驱动。
java程序员不需要知道JDBC接口是怎么实现的,只需要面向接口编程。
SUN公司负责定义JDBC接口,
各大数据库公司负责接口的实现。
程序员程序:

package com.guigu.JDBC;

import java.util.ResourceBundle;

public class JavaProgrammer {

    public static void main(String[] args) throws Exception{
        ResourceBundle bundle=ResourceBundle.getBundle("com.guigu.JDBC.prop");
        String className=bundle.getString("ClassName");
        Class c=Class.forName("com.guigu.JDBC."+className);
        JDBC jdbc=(JDBC)c.newInstance();
        jdbc.getConnection();
    }
}

SUN公司写的JDBC接口:

package com.guigu.JDBC;

public interface JDBC {
    public void getConnection();
}

MySQL公司写的实现类:

package com.guigu.JDBC;

import javax.xml.bind.SchemaOutputResolver;

public class MySQL implements JDBC{
    @Override
    public void getConnection() {
        System.out.println("开始运行MySQL");
    }
}

准备:官网下载驱动jar包,配置路径到classpath中。
变量名:classpath 配置时,前面要加 .; 表示在原路径上添加。
classpath=.;F:\工作\cs自学资料\mysql\JDBC\mysql-connector-java-5.1.23-bin.jar

3.JDBC编程六步:

在这里插入图片描述
在这里插入图片描述
url:在这里插入图片描述
各部分意义:
在这里插入图片描述
IP是计算机的代号,端口代表某个软件
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
注: 要从小到大依次释放。JDBC中的sql语句不需要写分号。
完整:
在这里插入图片描述
注册驱动的第二种方法:
在这里插入图片描述
.executequarry()方法:
在这里插入图片描述
查询结果保存在ResaultSet类中:
在这里插入图片描述
ResaultSet中取数据:
在这里插入图片描述
上述用列名也可以(推荐):
在这里插入图片描述
注:列名为查寻结果的列名,不是原表中的列名。
除了以getString()取出,还可以getInt(),getDouble()。
导入数据库驱动:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
先apply再ok。
在这里插入图片描述

4.登录程序实例:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 当前程序存在的问题:
    用户名:fdsa
    密码:fdsa’ or ‘1’='1
    登录成功
    这种现象被称为SQL注入(黑客经常使用)

  • 原因:
    由于输入的非法字符有sql关键字,并且这些关键字参与了DBMS编译,导致sql语句被扭曲(where语句中的值恒为1, 默认查找所有数据),进而达到sql注入。

  • 如何解决sql注入:
    用户提供的sql信息不参与SQL编译,问题就解决了。
    要实现该功能必须使用java.sql.PreparedStatement。
    PreparedStatement继承了java.sql.Statement。
    PreparedStatement原理:预编译SQL框架,之后再给SQL语句传“值”。
    注意PreparedStatement和Statement的区别:
    第三步:
    String sql=“select * from t_log where username=? and password=?”;
    ps=conn.prepareStatement(sql);
    ps.setString(1,username);
    ps.setString(2,password);
    rs=ps.executeQuery();

package com.bjpowernode.jdbc;

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

public class JdbcTest02 {
    public static void main(String[] args) {
        Map<String,String> map=input();
        login(map);
    }

    public static Map<String,String> input(){
        Scanner s=new Scanner(System.in);
        System.out.println("请输入账户名:");
        String username=s.nextLine();
        System.out.println("请输入密码:");
        String password=s.nextLine();

        Map<String,String> map=new HashMap<String, String>();
        map.put("username",username);
        map.put("password",password);
        return map;
    }

    public static void login(Map<String,String> map){
        String username=map.get("username");
        String password=map.get("password");
        String url="jdbc:mysql://localhost:3306/bjpowernode";
        String usernamedb="root";
        String passworddb="******";
        boolean log=false;

        Connection conn=null;
        PreparedStatement ps=null;
        ResultSet rs=null;

        try {
            Class.forName("com.mysql.jdbc.Driver");
            conn=DriverManager.getConnection(url,usernamedb,passworddb);
            String sql="select * from t_log where username=? and password=?";
            ps=conn.prepareStatement(sql);
            ps.setString(1,username);
            ps.setString(2,password);
            rs=ps.executeQuery();
            if(rs.next()){
                log=true;
            }
            System.out.println(log ? "登陆成功":"登录失败");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            if (rs != null) {
                try {
                    rs.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
            if (ps != null) {
                try {
                    ps.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
            if (conn != null) {
                try {
                    conn.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
        }
    }
}

  • 对比PreparedStatement和Statement:
    在这里插入图片描述
    PreparedStatement使用较多。
  • 什么时候需要使用Statement:
    业务要求必须使用SQL注入情况下。(Statement支持SQL注入)

5.JDBC事务机制

默认自动提交。
在这里插入图片描述
java.sql.Connection包中方法:开启事务—手动提交—回滚事务

conn.setAutoCommit(false);//开启事务
...
...
...
conn.commit();//手动提交

最后,有异常就回滚:

try{}
catch{
	if(conn!=null){
		conn.rollback();//回滚事务
	}
}

在这里插入图片描述

6.JDBC工具类封装

1.私有化构造方法(防止别人new对象)
在这里插入图片描述
2.构造 获取连接和释放资源方法:

package com.bjpowernode.jdbc;

import java.sql.*;

public class DBUtil {
    static {
        try {
            Class.forName("com.mysql.jdbc.Driver");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    private DBUtil(){}

    public static Connection getConnection() throws SQLException {
        return DriverManager.getConnection("jdbc:mysql://localhost:3306/bjpowernode", "root","****");
    }

    public static void close(Connection conn, Statement stmt, ResultSet rs){
        if (rs == null) {
            try {
                rs.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
        if (stmt == null) {
            try {
                stmt.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
        if (conn == null) {
            try {
                conn.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
    }
}

执行测试:

package com.bjpowernode.jdbc;

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

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

        try {
            conn=DBUtil.getConnection();
            String sql="select * from emp where ename like ?";
            ps=conn.prepareStatement(sql);
            ps.setString(1,"_A%");
            rs=ps.executeQuery();
            while (rs.next()){
                System.out.println(rs.getString("ename"));
            }
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            DBUtil.close(conn,ps,rs);
        }
    }
}

7.行级锁(悲观锁)

select 语句后边+for update;

select ename,job,deptno from emp where job = 'manager' for update;
+-------+---------+--------+
| ename | job     | deptno |
+-------+---------+--------+
| JONES | MANAGER |     20 |
| BLAKE | MANAGER |     30 |
| CLARK | MANAGER |     10 |
+-------+---------+--------+

锁住原表中被选中三行的所有字段,只要当前事务未结束,就无法被修改:

+-------+-------+---------+------+------------+---------+------+--------+
| EMPNO | ENAME | JOB     | MGR  | HIREDATE   | SAL     | COMM | DEPTNO |
+-------+-------+---------+------+------------+---------+------+--------+
|  7566 | JONES | MANAGER | 7839 | 1981-04-02 | 2975.00 | NULL |     20 |
|  7698 | BLAKE | MANAGER | 7839 | 1981-05-01 | 2850.00 | NULL |     30 |
|  7782 | CLARK | MANAGER | 7839 | 1981-06-09 | 2450.00 | NULL |     10 |
+-------+-------+---------+------+------------+---------+------+--------+

悲观锁: 事务必须排队执行,数据锁住了,不允许多线程并发。(行级锁:for update;)
乐观锁: 允许多线程并发,事务不需要排队,只不过需要一个版本号, 每个线程操作完成之后版本号会变化,如果一个线程执行完之后发现版本号与线程开始时不同,意味着这期间其他线程对该数据进行过修改,则原线程执行回滚。

悲观锁效果演示,第一个例子:事务查询,存在行级锁,断点处等待,不提交。
第二个例子:在第一个事务执行期间,进行数据修改。
效果:第一个例子调试一结束,第二个例子马上可以输出3。

package com.bjpowernode.jdbc;

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

public class JDBCTest04 {
    public static void main(String[] args) {
        Connection conn=null;
        PreparedStatement ps=null;
        ResultSet rs=null;
        try {
            conn=DBUtil.getConnection();

            conn.setAutoCommit(false);
            String sql="select * from emp where job=? for update";
            ps=conn.prepareStatement(sql);
            ps.setString(1,"manager");
            rs=ps.executeQuery();
            while(rs.next()){
                System.out.println(rs.getString("ename")+","+
                        rs.getString("job")+","+rs.getString("sal"));
            }

            conn.commit();
        } catch (SQLException throwables) {
            try {
                conn.rollback();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            throwables.printStackTrace();
        }finally {
            DBUtil.close(conn,ps,rs);
        }
    }
}
package com.bjpowernode.jdbc;

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

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

        try {
            conn=DBUtil.getConnection();
            conn.setAutoCommit(false);
            String sql ="update emp set sal=sal*1.1 where job=?";
            ps=conn.prepareStatement(sql);
            ps.setString(1,"manager");
            int n=ps.executeUpdate();

            conn.commit();
            System.out.println(n);
        } catch (SQLException throwables) {
            try {
                conn.rollback();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            throwables.printStackTrace();
        }
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值