JDBC学习笔记

1.前言

(1)JDBC概念:Java DataBase Connectivity(Java语言连接数据库)

(2)本质:是SUN公司制定的一套接口

2. JDBC编程六步骤

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

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

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

(4)执行SQL语句(DQL,DML)

(5)处理查询结果集(只有当第四步执行的是select语句的时候才有这第五步处理查询结果集)

(6)释放资源(使用完资源以后一定要关闭资源。Java和数据库属于进程间的通信,使用完一定要关闭)

2.1示例

import java.sql.*;

public class JDBCTest {
    public static void main(String[] args) {
        Connection conn = null;
        Statement stmt = null;
        try{
            //1.注册驱动
            Driver driver = new com.mysql.jdbc.Driver();
            DriverManager.registerDriver(driver);
            //2.获取连接
            /**
             * url:统一资源定位符
             * 比如一个网址就是url
             * URL由协议、IP、Port、资源名字 组成
             *
             * http://182.61.200.7:80/index.html
             *      http://:通信协议
             *      182.61.200.7:80:是IP地址
             *      80:是端口号
             *      index.html:是服务器上的某个资源名
             *
             * jdbc:mysql://127.0.0.1:3306/bjpowernode
             *      jdbc:mysql://:是协议
             *      127.0.0.1是本机IP地址
             *      3306是MySQL服务端口号
             *      bjpowernode是需要访问的资源
             *
             * 所谓通信协议就是组织好的数据传输格式
             *
             * */
            String url = "jdbc:mysql://127.0.0.1:3306/bjpowernode";
            String user = "root";
            String password = "1017";
            conn = DriverManager.getConnection(url,user,password);

            //3.获取数据库操作对象,Statement专门执行sql语句。
            stmt = conn.createStatement();
            //4.执行sql语句
            String sql = "insert into dept(deptno,dname,loc) values(50,'人事部','北京')";
            /**
             * 专门执行DML语句(update,delete,insert)
             * 返回值是影响数据库中的数据条数(比如插入三条就返回3)
             * */
            int count = stmt.executeUpdate(sql);
            System.out.println(count == 1?"保存成功":"保存失败");

            //5.处理查询结果集

        }catch (SQLException e){
            e.printStackTrace();

        }finally {
            //6.释放资源
            /**
             * 为了保证资源一定释放,在finally中释放资源
             * 释放资源要保证从小到大依次释放。比如statement是由connection对象产生的,我们要先关闭statement再关闭connection对象
             * 释放资源要写在try...catch块里
             * */
            try {
                if (stmt!=null)
                    stmt.close();
            }catch (SQLException e){
                e.printStackTrace();
            }
            try {
                if (conn!=null)
                    conn.close();
            }catch (SQLException e){
                e.printStackTrace();
            }
        }
    }
}

3.进阶写法

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ResourceBundle;

public class JDBCTest02 {

    /**
     * 注册驱动最常用的一种方法
     *
     * 在实际开发中,不建议把连接数据库的信息写死到程序里面去
     * */

    public static void main(String[] args) {
        //使用资源绑定器绑定属性配置文件
        ResourceBundle bundle = ResourceBundle.getBundle("jdbc");
        String driver = bundle.getString("driver");
        String url = bundle.getString("url");
        String user = bundle.getString("user");
        String password = bundle.getString("password");

        Connection conn = null;
        Statement stmt = null;
        try {
            //1.注册驱动
            /**
             * 这种方式常用是因为参数是字符串,字符串可以写入xxx.properties文件中
             * */
            Class.forName(driver);//使用反射机制将驱动加载到内存当中。
            //2.获取连接
            conn = DriverManager.getConnection(url,user,password);
            //3.获取数据库操作对象,Statement专门执行sql语句。
            stmt = conn.createStatement();
            //4.执行sql语句
            String sql = "insert into dept(deptno,dname,loc) values(50,'人事部','北京')";
            int count = stmt.executeUpdate(sql);
            System.out.println(count == 1?"保存成功":"保存失败");

            //5.处理查询结果集

        }catch (SQLException e){
            e.printStackTrace();
        }catch (ClassNotFoundException e){
            e.printStackTrace();
        }finally {
            //6.释放资源
            try {
                if (stmt!=null)
                    stmt.close();
            }catch (SQLException e){
                e.printStackTrace();
            }
            try {
                if (conn!=null)
                    conn.close();
            }catch (SQLException e){
                e.printStackTrace();
            }
        }
    }
}

4.处理查询结果集

import java.sql.*;

public class JDBCTest03 {
    public static void main(String[] args) {
        Connection conn = null;
        Statement stmt = null;
        ResultSet rs = null;
        try {
            //1.注册驱动
            Class.forName("com.mysql.jdbc.Driver");
            //2.获取连接
            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/bjpowernode",
                    "root","1017");
            //3.获取数据库操作对象,Statement专门执行sql语句。
            stmt = conn.createStatement();
            //4.执行sql语句
            String sql = "select empno,ename,sal from emp";
            //int count = stmt.executeUpdate(sql);<---专门处理DML语句的方法
            rs = stmt.executeQuery(sql);

            //5.处理查询结果集
            boolean flag1 = rs.next();
                /**
                 * getString()方法的特点是不管数据库中的数据类型是什么,都是以String的形式取出.
                 * 并且其中要求的参数是列的下标(getString(1))或者是列名(getString("ename"),如果列名被重写必须要使用被重写的列名)
                 *
                 * 除了可以以String类型取出之外,还可以以特定的类型取出
                 * 比如:int empno = rs.getInt("empno")
                 *
                 * 不过要注意的是,jdbc中的下标从1开始不是从0开始
                 * */
            while (rs.next()){
                String empno = rs.getString(1);
                String ename = rs.getString(2);
                String sal = rs.getNString(3);

                System.out.println(empno+","+ename+","+sal);
            }

        }catch (SQLException e){
            e.printStackTrace();
        }catch (ClassNotFoundException e){
            e.printStackTrace();
        }finally {
            //6.释放资源
            try {
                if (rs!=null)
                    rs.close();
            }catch (SQLException e){
                e.printStackTrace();
            }
            try {
                if (stmt!=null)
                    stmt.close();
            }catch (SQLException e){
                e.printStackTrace();
            }
            try {
                if (conn!=null)
                    conn.close();
            }catch (SQLException e){
                e.printStackTrace();
            }
        }
    }
}

5.关于SQL注入

5.1代码展示

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

/**
 * 如何解决SQL注入的问题:
 *
 * 使用java.sql.PreparedStatement
 * 该类继承了statement,其属于预编译的数据库操作对象。
 * 其原理是:预先对SQL语句的框架进行编译,然后再给sql语句传值。
 *
 * */
public class JDBCTest05 {
    public static void main(String[] args) {
        Map<String, String> userLoginInfo = init();
        boolean loginSuccess = login(userLoginInfo);
        System.out.println(loginSuccess?"登录成功":"登录失败");

    }

    private static boolean login(Map<String,String> userLoginInfo) {
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        String userName = userLoginInfo.get("userName");
        String passWord = userLoginInfo.get("passWord");
        boolean loginSuccess = false;

        try {
            Class.forName("com.mysql.jdbc.Driver");

            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/bjpowernode",
                    "root","1017");

            String sql = "select * from t_user where loginName=? and loginPwd=?";

            ps = conn.prepareStatement(sql);
            ps.setString(1,userName);
            ps.setString(2,passWord);

            rs = ps.executeQuery();

            if (rs.next()){
                loginSuccess = true;
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            if (rs!=null){
                try {
                    rs.close();
                }catch (Exception e){
                    e.printStackTrace();
                }
            }
            if (ps!=null){
                try {
                    ps.close();
                }catch (Exception e){
                    e.printStackTrace();
                }
            }
            if (conn!=null){
                try {
                    conn.close();
                }catch (Exception e){
                    e.printStackTrace();
                }
            }

        }
        return loginSuccess;
    }

    private static Map<String, String> init() {
        Scanner in = new Scanner(System.in);
        System.out.println("用户名:");
        String userName = in.nextLine();
        System.out.println("密码:");
        String passWord = in.nextLine();
        Map<String, String> userLoginInfo = new HashMap<>();
        userLoginInfo.put("userName",userName);
        userLoginInfo.put("passWord",passWord);
        return userLoginInfo;
    }
}

5.2关于Statement和PreparedStatement的区别

Statement存在注入问题;而PreparedStatement存在注入问题。

Statement是编译一次执行一次;而PreparedStatement是编译一次执行N次。

PreparedStatement会在编译阶段做类型的安全检查。

大多数情况下使用PreparedStatement,只有在业务要求SQL注入的时候才会使用Statement。

6.JDBC事务自动提交机制

6.1代码演示

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

/**
 * JDBC事务机制:
 *  1.JDBC中的事务是自动提交,什么是自动提交?
 *      只要执行任意一条DML语句,则自动提交一次。这是JDBC默认的事务行为。
 *      但是在实际的业务当中,通常都是N条DML语句共同联合才能完成的,必须
 *      保证他们这些DML语句在同一个事务当中同时成功或者同时失败。
 * */
public class JDBCTest06 {
    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","1017");

            String sql = "update dept set dname = ? where deptno=?";
            ps = conn.prepareStatement(sql);
			
			//操作1
            ps.setString(1,"X部门");
            ps.setInt(2,30);
            int count = ps.executeUpdate();
            System.out.println(count);
			//操作2
            ps.setString(1,"Y部门");
            ps.setInt(2,30);
            int count2 = ps.executeUpdate();
            System.out.println(count2);
            
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            if (ps!=null){
                try {
                    ps.close();
                }catch (Exception e){
                    e.printStackTrace();
                }
            }
            if (conn!=null){
                try {
                    conn.close();
                }catch (Exception e){
                    e.printStackTrace();
                }
            }
        }
    }
}

我们可以对以上代码进行Debug,不难发现,当操作1代码执行完毕以后我们的数据库就已经发生了改变。

6.2手动修改事务

//将Connection对象禁用自动提交机制。
conn.setAutoCommit(false);

//在操作完成以后我们使用commit()方法手动提交。
conn.commit();

//为了保证数据安全,最后还要在catch块中手动调用事务回滚
 catch (Exception e) {
            conn.rollback();
            e.printStackTrace();
        }

7.JDBC工具类的封装

7.1封装代码

public class DBUtil {

    private DBUtil(){}
    static {
        try {
            Class.forName("com.mysql.jdbc.Driver");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
    public static Connection getConnection() throws SQLException {
        return DriverManager.getConnection("jdbc:mysql://localhost:3306/bjpowernode",
                "root","1017");
    }
    public static void close(Connection conn, Statement ps, ResultSet rs){
        if (rs != null){
            try {
                rs.close();
            }catch (Exception e){
                e.printStackTrace();
            }
        }
        if (ps != null){
            try {
                ps.close();
            }catch (Exception e){
                e.printStackTrace();
            }
        }
        if (conn != null){
            try {
                conn.close();
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }


}

7.2使用JDBC实现模糊查询

public class DBUtil {

    private DBUtil(){}
    static {
        try {
            Class.forName("com.mysql.jdbc.Driver");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
    public static Connection getConnection() throws SQLException {
        return DriverManager.getConnection("jdbc:mysql://localhost:3306/bjpowernode",
                "root","1017");
    }
    public static void close(Connection conn, Statement ps, ResultSet rs){
        if (rs != null){
            try {
                rs.close();
            }catch (Exception e){
                e.printStackTrace();
            }
        }
        if (ps != null){
            try {
                ps.close();
            }catch (Exception e){
                e.printStackTrace();
            }
        }
        if (conn != null){
            try {
                conn.close();
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }


}

8.悲观锁和乐观锁的概念

8.1悲观锁(行级锁)

select ename,job,sal from emp where job="MANAGER" for update;

在sql语句末尾加上for update表示悲观锁,在事务结束之前,其他线程无法对悲观锁锁上的数据进行操作,所有事务都必须排队执行,不允许并发。

8.2乐观锁

支持并发,事务也不需要排队,只不过需要一个版本号

比如说一条记录具有版本号1.1。
有两个事务分别是:A、B

其中事务A先进行修改,完成以后版本号变为1.2,
事务B是后进行修改的,修改以后准备提交发现版本号变为1.2,和他最初读的版本号不一样,所以它选择回滚。
  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

少不入川。

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

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

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

打赏作者

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

抵扣说明:

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

余额充值