JDBC学习

1.介绍

由于每一个数据库的底层实现原理不一样,Oracle数据库有自己的实现原理,Mysql数据库有自己的实现原理,MS(SqlServer)有自己的实现原理,所以sun公司制定了一套接口,由各大数据库厂家去实现,程序员只需要去调用这套接口即可,这套接口就是JDBC;

Java DataBase Connective--Java与数据库的连接;

JDBC本质是sun公司制定的一套接口,java.sql.*;

2.JDBC编程六步

①注册驱动(告诉java程序,即将要连接的是哪个品牌的数据库)

②获取连接(表示jvm进程和数据库进程之间的通道打开了,这属于进程之间的通信,重量级的,使用后一定要关闭)

③获取数据库操作对象(专门执行sql语句的对象)

④执行sql语句(DQL,DML...)

⑤处理查询结果集(只有第四步是select的时候才需要)

⑥释放资源

public class JDBC {

    public static void main(String[] args) {
        Statement stmt = null;
        Connection conn = null;
        ResultSet rs = null;
        try {
            // 注册驱动第一种方式
            // DriverManager.registerDriver(new com.mysql.jdbc.Driver());
            // 注册驱动第二种方式,因为参数是字符串,字符串可以写到配置文件中,所以这种方式更常用
            // 实际开发中不建议把数据库信息写死在java代码中
            ResourceBundle rb = ResourceBundle.getBundle("jdbc");
            Class.forName(rb.getString("driver"));
            // 连接数据库,打开通道
            // conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/movie",
            // "root", "root");
            conn = DriverManager.getConnection(rb.getString("connect"), rb.getString("username"),
                    rb.getString("password"));
            // System.out.println(conn);
            // 获取数据库操作对象
            stmt = conn.createStatement();
            // 执行sql语句
            String sql = "insert into y_movie (m_name,m_up_year,m_director) values('后天',2018,'诺兰')";
            String sql2 = "select * from y_movie";
            String sql3 = "delete from y_movie where m_id=5";
            String sql4 = "update y_movie set m_name='阿凡达8' where m_id=4;";
            // 返回值是影响表的数据记录的条数
            // int count = stmt.executeUpdate(sql4);
            rs = stmt.executeQuery(sql2);
            while (rs.next()) {
                System.out.print((rs.getInt("m_up_year") + 1000) + rs.getString("m_name") + rs.getString("m_director"));
                System.out.println();
            }
        } catch (Exception e) {
            // TODO: handle exception
            System.out.println(e.getMessage());
        } finally {
            // 为了保证通道一定关闭,在finnaly语句中执行
            // 并且遵循从小到大原则

            if (rs != null) {
                try {
                    rs.close();
                } catch (Exception e) {
                    // TODO: handle exception
                }
            }

            if (stmt != null) {
                try {
                    stmt.close();
                } catch (Exception e) {
                    // TODO: handle exception
                }
            }

            if (conn != null) {
                try {
                    conn.close();
                } catch (Exception e) {
                    // TODO: handle exception
                }
            }
        }
    }
}

3.PreparedStatement-预编译数据库操作对象

由于Statement存在sql注入风险,所以用PreparedStatement代替Statement;

PreparedStatement的原理是:预先对sql语句的框架进行编译,然后再给sql语句传值;

private static boolean isLogin(HashMap<String, String> map) {
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        try {
            ResourceBundle rb = ResourceBundle.getBundle("db");
            // 注册驱动
            Class.forName(rb.getString("driver"));
            // 连接数据库
            conn = DriverManager.getConnection(rb.getString("connector"), rb.getString("username"),
                    rb.getString("password"));
            // 获取数据库操作对象
            // sql语句框架,其中一个?代表一个占位符,一个?将来接收一个值,将来接收的整个值会被单作一个字符串处理,占位符不能用单引号括起来
            String sql = "select * from login where l_username= ? and l_pwd=?";
            // 发送sql语句框架给DBMS,DBMS进行sql语句的预编译
            ps = conn.prepareStatement(sql);
            // 给占位符?传值,第一个?下标是1,第二个是2,JDBC中所有下标从1开始
            ps.setString(1, map.get("username"));
            ps.setString(2, map.get("password"));

            // 执行sql语句
            rs = ps.executeQuery();
            if (rs.next()) {
                System.out.println("您好:" + rs.getString("l_nick"));
                return true;
            }
        } catch (Exception e) {
            // TODO: handle exception
            System.out.println(e.getMessage());
        } finally {
            if (rs != null) {
                try {
                    rs.close();
                } catch (SQLException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }

            if (ps != null) {
                try {
                    ps.close();
                } catch (SQLException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }

            if (conn != null) {
                try {
                    conn.close();
                } catch (SQLException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
        return false;
    }

解决SQL注入的关键是:用户提供的信息中虽然含有sql语句的关键字,但这些关键字并没有参与编译,不起作用;

mysql不会对相同的语句做重复编译,如果当条语句与之前编译过的相同,则会之间执行,只有不同的sql语句才会重新编译,再执行;由于Statement需要每次传入不同的参数,sql语句每次也是不同的语句,所以Statement是编译一次执行一次,PreparedStatement是编译一次可供后续多次执行,后者执行效率更高;

PreparedStatement会在编译阶段做数据类型的安全检查;

实际开发中PreparedStatement使用较多,只有j较少数情况下使用Statement,例如业务方面必须要求sql注入的时候,就只能用Statement;

以下情况只能使用Statement:

"select * from login order by l_id " + str;

4.事务

JDBC中的事务是自动提交的,即只要执行一条DML语句,则自动提交一次,这是JDBC默认的事务行为;

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

        ResourceBundle rb = ResourceBundle.getBundle("db");
        try {
            Class.forName(rb.getString("driver"));
            conn = DriverManager.getConnection(rb.getString("connector"), rb.getString("username"),
                    rb.getString("password"));
            // 取消自动提交,改为手动提交
            conn.setAutoCommit(false);
            String sql = "insert into login (l_username,l_pwd,l_nick) values(?,?,?)";
            ps = conn.prepareStatement(sql);
            ps.setString(1, "twx");
            ps.setString(2, "twx111");
            ps.setString(3, "海王星");
            int count = ps.executeUpdate();
            // int a = 10 / 0;
            String sql3 = "update login set l_nick=? where l_id=?";
            ps = conn.prepareStatement(sql3);
            ps.setString(1, "猎户座");
            ps.setInt(2, 1);
            count += ps.executeUpdate();

            System.out.println(count);
            // 手动提交
            conn.commit();

        } catch (ClassNotFoundException e) {
            // 事务回滚
            if (conn != null) {
                try {
                    conn.rollback();
                } catch (SQLException ex) {
                    ex.printStackTrace();
                }
            }
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            if (conn != null) {
                try {
                    conn.rollback();
                } catch (SQLException ex) {
                    ex.printStackTrace();
                }
            }
            e.printStackTrace();
        } finally {
            if (rs != null) {
                try {
                    rs.close();
                } catch (SQLException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }

            if (ps != null) {
                try {
                    ps.close();
                } catch (SQLException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }

            if (conn != null) {
                try {
                    conn.close();
                } catch (SQLException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
    }

5.封装JDBC

package com.idea.jdbc;

import java.sql.*;
import java.util.ResourceBundle;

public class DBUtils {
    static ResourceBundle rb = ResourceBundle.getBundle("db");
    // 静态代码块在类加载的时候执行,并且只执行一次
    static {
        try {
            Class.forName(rb.getString("driver"));
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    private DBUtils() {
    }

    /**
     * 连接数据库
     * 
     * @return 数据库连接通道
     * @throws SQLException
     */
    public static Connection connect() throws SQLException {
        return DriverManager.getConnection(rb.getString("connector"), rb.getString("username"),
                rb.getString("password"));
    }

    /**
     * 释放数据库资源
     * 
     * @param conn
     * @param ps
     * @param rs
     */
    public static void close(Connection conn, Statement ps, ResultSet rs) {
        if (rs != null) {
            try {
                rs.close();
            } catch (SQLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

        if (ps != null) {
            try {
                ps.close();
            } catch (SQLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

        if (conn != null) {
            try {
                conn.close();
            } catch (SQLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
}

PreparedStatement模糊查询:

            String sql = "select * from login where l_nick like ?";
            ps = conn.prepareStatement(sql);
            ps.setString(1, "%星%");
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

y_w_x_k

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

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

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

打赏作者

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

抵扣说明:

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

余额充值