JDBC? Java Database Connectivity(Java语言连接数据库)

1、什么是JDBC?

Java DataBase Connectivity
在java语言中编写sql语句,对mysql数据库中的数据进行CRUD操作。增加(Create)、读取查询(Retrieve)、更新(Update)和删除(Delete)

2、JDBC相关的类库在哪里?

java.sql.*;

3、JDBC本质上是一堆什么呢?

java.sql.*;
这个包下都是JDBC的接口,SUN公司制定的!
JDBC是体现“接口作用”的非常经典的例子。
JDBC降低了耦合度,提高了扩展力。
对于java程序员来说,不需要关心数据库是哪个品牌。只要面向JDBC接口编程就行!

JDBC整个程序的结构当中有三波人????

	第一波:SUN公司,负责制定JDBC接口。这些接口已经写好了,在java.sql.*;

	第二波:java.sql.*下面的所有接口都要有实现类,这些实现类是数据库厂家编写的。
				我们连接的是mysql数据库,mysql数据库厂家的实现类在哪里呢?
					mysql-connector-java-5.1.23-bin.jar
					jar包中很多.class字节码文件,这是mysql数据库厂家写的接口实现!

					注意:如果连接的是oracle数据库,你需要从网上下载oracle的jar包。

					mysql-connector-java-5.1.23-bin.jar 这个jar包有一个专业的术语,
					大家记住就行:mysql的驱动。

					如果是oracle的jar,被称为oracle的驱动。
	
	第三波:我们java程序员,面向JDBC接口写代码就行!

4、编程描述JDBC本质

JDBC? Java Database Connectivity(Java语言连接数据库)_第1张图片
JDBC? Java Database Connectivity(Java语言连接数据库)_第2张图片
JDBC? Java Database Connectivity(Java语言连接数据库)_第3张图片
JDBC? Java Database Connectivity(Java语言连接数据库)_第4张图片

5、JDBC开发之前的准备工作?

mysql的驱动jar包,需要配置到classpath当中吗?
	mysql-connector-java-5.1.23-bin.jar里是字节码,是class文件。
	Java虚拟机的类加载器会去加载class文件,类加载器怎么能够
	找到这些class文件呢?
		classpath没有配置的情况下,默认从当前路径下加载class。
		classpath如果配置死了,例如:classpath=D:\abc,则表示固定只从d:\abc目录下找class

		classpath=.;D:\course\04-JDBC\resources\MySql Connector Java 5.1.23\mysql-connector-java-5.1.23-bin.jar

		. 代表什么?当前路径。
		以上的classpath什么意思?
			类加载器从当前路径下加载class,如果当前路径下没找到,
			则去D:\course\04-JDBC\resources\MySql Connector Java 5.1.23\mysql-connector-java-5.1.23-bin.jar
			找class文件。

	jar包需要解压吗?
		不需要解压,java虚拟机的类加载器有这个能力找到class文件。

6、JDBC编程六步

JDBC编程六部概述

JDBC? Java Database Connectivity(Java语言连接数据库)_第5张图片

注册驱动与获取连接

package jdbc;

import java.sql.Driver;
import java.sql.*;

public class jdbc01 {
    public static void main(String[] args) {
        Connection conn=null;
        Statement stmt=null;
        try {
            //1、注册驱动//告诉java程序我们连接的是那类数据库
            Driver driver = new com.mysql.cj.jdbc.Driver();//多态,父类型引用指向子类型对象
            //Driver driver=new oracle.jdbc.driver.OracleDriver();//oracle的驱动
            DriverManager.registerDriver(driver);
            //↑static void registerDriver(Driver driver)向DriverManager注册给定应用程序

            //2、获取连接
            /*
              url:统一资源定位符(网络中某个资源的绝对路径)
              http://www.baidu.com/ 这就是URL。
              URL包括哪几部分?
                协议
                IP
                PORT
                资源名
                http:// 182.61.200.7:80/index.html

                http:// 通信协议
                182.61.200.7服务器ip地址
                80服务器上软件的端口
                index.html是服务器上某个资源名

                ip是计算机的代号,端口是软件应用的代号

               jdbc:mysql://127.0.0.1:3306/bjpowernode
               jdbc:mysql://协议
               127.0.0.1 IP地址
               3306  mysql数据库端口号
               bjpowernode  具体的数据库实例名

               说明localhost 和127.0.0.1都是本机ip地址。
               什么是通信协议,有什么用?
                    通信协议是通信之前就提前定好的数据传送格式。
                    数据包具体怎么传数据,格式提前定好的。
             oracle的url:
               jdbc:oracle:thin:@localhost:1521:orcl

             */

            String url = "jdbc:mysql://127.0.0.1:3306/bjpowernode";
            String user = "root";
            String password = "123456";
            //获取连接 是个流
            //public static Connection getConnection(String url,String user,String password) throws SQLException
            //试图建立到给定数据库URL的连接,DriverManager试图从已注册的JDBC驱动程序集 中选择一个适当的驱动程序。
             conn = DriverManager.getConnection(url, user, password);
            System.out.println("数据库连接对象=" + conn);

            //3、获取数据库操作对象(statement专门执行sql语句的)
            //Statement createStatement()
            //创建一个Statement对象来将SQL语句发送到数据库
            stmt=conn.createStatement();//
            //4、执行sql
            String sql="insert into dept(deptno,dname,loc) values(40,'人事部','北京')";
            //专门执行DML语句的(insert delete update)
            //返回值是"影响数据库中的记录条数",删除三条返回3,更新两条返回2
            int count=stmt.executeUpdate(sql);
            //int executeUpdate(String sql)
            // 执行给定的sql语句,该语句可能为insert,update或delete语句,或者不返回任何内容的sql语句(sql ddl数据库定义)
            System.out.println(count==1?"保存成功":"保存失败");

            //5、处理查询结果集
           //这个只是个插入语句

        } catch (SQLException e) {
            e.printStackTrace();
        }finally{
            //6、释放资源
            //为了保证资源一定释放,在finally语句块中关闭资源
            //并且要遵循从小到大依次关闭
            //分别对其try..catch
            try{
                if(stmt!=null){
                    stmt.close();
                }
            }catch(SQLException e){
                e.printStackTrace();
            }
            try{
                if(conn!=null){
                    conn.close();
                }
            }catch(SQLException e){
                e.printStackTrace();
            }
        }
    }
}



执行sql与释放资源 与 JDBC执行删除和更新

package jdbc;

import java.sql.*;
/*
 JDBC完成delete update
*/
public class jdbc02 {
    public static void main(String[] args) {
        Connection conn=null;
        Statement stmt=null;
        try {
            //1、注册驱动

            DriverManager.registerDriver(new com.mysql.cj.jdbc.Driver());
            //2、获取连接

            conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/bjpowernode","root","123456");
            System.out.println("数据库连接对象=" + conn);

            //3、获取数据库操作对象
            stmt=conn.createStatement();//
            //4、执行sql
            String sql="delete from dept where deptno=40";
            //JDBC中的sql语句不需要提供分号结尾,否则报错
            //String sql="update dept set dname='销售部",loc='天津'where deptno=20";
            int count=stmt.executeUpdate(sql);
            System.out.println(count==1?"删除成功":"删除失败");

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


注册驱动的第二种方式 类加载的方式注册驱动

package jdbc;

import com.sun.javaws.IconUtil;

import java.sql.*;
public class jdbc03 {
    public static void main(String[] args) {

        try{
            //1、注册驱动
            //这是注册驱动的第一种写法
            //DriverManager.registerDriver(new com.mysql.cj.jdbc.Driver());
            //注册驱动的第二种方式:常用的
            //为什么这种方式常用?因为参数是一个字符串,字符串可以写到xxx.properties文件中。
            //以下方法不需要接收返回值,因为我们只想用它的类加载动作。
            Class.forName("com.mysql.cj.jdbc.Driver");

            // 2、获取连接
            Connection conn=DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/bjpowernode","root","123456");
            System.out.println(conn);

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

    }
}

从属性资源文件中读取连接数据库信息

jdbcc.properties

driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/bjpowernode
user=root
password=123456
package jdbc;

import java.sql.*;
import java.util.ResourceBundle;
/*
实际开发中不建议把连接数据库的信息写死在java程序中。
 */
public class jdbc04 {
    public static void main(String[] args) {
        // 使用资源绑定器绑定属性配置文件
        ResourceBundle bundle =ResourceBundle.getBundle("jdbcc");
        String driver=bundle.getString("key");
        String url=bundle.getString("url");
        String user=bundle.getString("user");
        String password=bundle.getString("password");

        Connection conn=null;
        Statement stmt=null;
        try {
            //1、注册驱动(只需要改这个)
            Class.forName(driver);
            //2、获取连接
            conn = DriverManager.getConnection(url,user,password);
            //3、获取数据库操作对象
            stmt=conn.createStatement();//
            //4、执行sql
            String sql="update dept set dname='销售部2',loc='天津'where deptno=20";
            int count=stmt.executeUpdate(sql);
            System.out.println(count==1?"修改成功":"修改失败");

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

处理查询结果集

ResultSet rs 存的是执行sql语句后的查询结果 集
JDBC? Java Database Connectivity(Java语言连接数据库)_第6张图片

package jdbc;

import javax.swing.*;
import java.sql.*;
/*
处理查询结果集
*/
public class jdbc05 {
    public static void main(String[] args) {
        Connection conn=null;
        Statement stmt=null;
        ResultSet rs=null;
        try {
            //1、注册驱动
            DriverManager.registerDriver(new com.mysql.cj.jdbc.Driver());
            //2、获取连接
            conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/bjpowernode","root","123456");
            //3、获取数据库操作对象
            stmt=conn.createStatement();//
            //4、执行sql
            String sql="select empno,ename,sal from emp";
            //ResultSet executeQuery(String sql) throws SQLEXception
            //执行给定的SQL语句,该语句返回单词ResultSet对象。
            // 参数sql 为要发送给数据库的SQL语句,通常为静态SQL select语句。
            //int executeUpdate(insert/delete/update)
            //ResultSet executeQuery(select)//ResultSet是执行sql语句后的查询结果集
            rs=stmt.executeQuery(sql);
            //5、处理查询结构集
/*理解过程
            boolean flag1=rs.next();//本来在第0行,现在next到了第一行,如果有数据就返回true
            // System.out.println(flag1); //true
            if(flag1){
                //光标指向的行有数据
                //取数据
                //getString()方法的特点是:不管数据库中的数据类型是什么,都以String的形式取出
                String empno=rs.getString(1);//跟的是下标,第一列,第二列,第三列
                String ename=rs.getString(2);//jdbc中所有的下标从1开始,不是从0开始的
                String sal=rs.getString(3);
                System.out.println(empno+","+ename+","+sal);
            }

            //rs.next();
            //boolean next() throws SQLException将光标从当前位置向前移一行。
            // ResultSet 光标最初位于第一行之前;第一次调用 next
            // 方法使第一行成为当前行;第二次调用使第二行成为当前行,依此类推。
            // 返回:如果新的当前行有效,则返回 true;如果不存在下一行,则返回 false
            //抛出:SQLException - 如果发生数据库访问错误或在关闭的结果集上调用此方法
*/
          while(rs.next()){
              /*
              String empno=rs.getString(1);
              String ename=rs.getString(2);
              String sal=rs.getString(3);
              System.out.println(empno+","+ename+","+sal);
              */

              /*另一种写法,不是以列的下标获取,以列的名字获取
              String empno=rs.getString("empno");
              String ename=rs.getString("ename");
              String sal=rs.getString("sal");
              System.out.println(empno+","+ename+","+sal);
              */

              int empno=rs.getInt(1);//之所以这能用int 是因为底层数据是int类型的,不然要以String类型
              String ename=rs.getString(2);
              double sal=rs.getDouble(3);
              System.out.println(empno+","+ename+","+(sal-100));//double类型 方便进行运算

          }


        } catch (SQLException e) {
            e.printStackTrace();
        }finally{
            //6、释放资源
            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();
                }
            }
        }
    }
}


模拟sql注入

package jdbc;

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

public class jdbc06 {
    public static void main(String[] args) {
        //初始化一个界面,可以让用户输入用户名和密码
      Map<String,String>userLoginInfo=initUI();
        //连接数据库验证用户和密码是否正确
      boolean ok=checkNameAndPwd(userLoginInfo.get("loginName"),userLoginInfo.get("loginPwd"));
        System.out.println(ok?"登陆成功":"登陆失败");

    }

    private static boolean checkNameAndPwd(String loginName, String loginPwd) {
         boolean ok=false;//默认登录是失败的,
        Connection conn = null;
        Statement stmt = null;
        ResultSet rs = null;

            // 1、注册驱动
            try {
                Class.forName("com.mysql.cj.jdbc.Driver");
                // 2、获取连接
                conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/bjpowernode", "root", "123456");
                // 3、获取数据库操作对象
                stmt = conn.createStatement();
                // 4、执行sql语句
                String sql = "select * from t_user where login_name='"+loginName+"'and login_pwd='"+loginPwd+"'";
                System.out.println(sql);
                //程序执行到此处,才会将以上的sql语句发送到DBMS上,DBMS进行sql语句的编译。
                rs = stmt.executeQuery(sql);//sql处理后会返回一个处理集,
                //如果以上sql语句中用户名和密码是正确的,那么结果集最多也就查询出一条记录,所以以下不需要while循环。if就够了
                if(rs.next()){//此条件如果成立,表示登录成功
                  ok=true;
                }
                // 5、处理结果集
            } catch (Exception e) {
                e.printStackTrace();
            }finally {
                // 6、释放资源
                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();
                    }
                }
            }

             return ok;
        }


    private static Map<String, String> initUI(){
         System.out.println("欢迎使用该系统,请输入用户名和密码进行身份认证");
         Scanner s=new Scanner(System.in);
         System.out.println("用户名:");
         String loginName=s.nextLine();
         System.out.println("密码:");
         String loginPwd=s.nextLine();
         //将用户名和密码放在map集合中
         Map<String,String> useLoginInfo=new HashMap<>();
         useLoginInfo.put("loginName",loginName);
         useLoginInfo.put("loginPwd",loginPwd);
         //返回map
         return useLoginInfo;

     }

/*
随便输入一个用户名的密码,登录成功了,这种现象被称为SQL注入现象!
导致SQL注入的根本原因是:用户不是一般的用户,用户是懂程序的,输入的用户名信息以及密码信息中,
含有SQL语句的关键词,这个SQL语句的关键字和底层的SQL语句进行“字符串拼接”,导致原SQL语句的含义
被扭曲了。最最主要的原因是:用户提供的信息参与了SQL语句的编译。

主要因素,这个程序是先进行字符串的拼接,然后再进行sql语句的编译,正好彼注入。
用户名:
fdsa
密码:
fdsa' or '1'='1
select * from t_user where login_name='fdsa'and login_pwd='fdsa' or '1'='1'
 */


}

解决sql注入问题

package jdbc;

import java.sql.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
/*
 怎么避免sql注入?
 sql注入的根本原因是,先进行了字符串的拼接,然后在进行的编译。

  java.sql.Statement接口的特点,先进行字符串的拼接。然后再进行sql语句的编译。
  优点:使用Statement可以进行sql语句的拼接。
  缺点:因为拼接的存在,导致可能给不法分子机会。

  java.sql.PreparedStatement接口的特点,先进行sql语句的编译,然后在进行sql语句的传值。
   优点:避免sql注入。
   缺点:没有办法进行sql语句的拼接,只能给sql语句传值。
   PreparedStatement预编译的数据库操作对象
*/

public class jdbc07 {
    public static void main(String[] args) {
        //初始化一个界面,可以让用户输入用户名和密码
        Map<String,String>userLoginInfo=initUI();
        //连接数据库验证用户和密码是否正确
        boolean ok=checkNameAndPwd(userLoginInfo.get("loginName"),userLoginInfo.get("loginPwd"));
        System.out.println(ok?"登陆成功":"登陆失败");

    }

    private static boolean checkNameAndPwd(String loginName, String loginPwd) {
        boolean ok=false;//默认登录是失败的,
        Connection conn = null;
        PreparedStatement stmt = null;
        ResultSet rs = null;

        // 1、注册驱动
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
            // 2、获取连接
            conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/bjpowernode", "root", "123456");
            // 3、获取预编译的数据库操作对象
            //一个问号是一个占位符,一个占位符只能接收一个值/数据
            String sql = "select * from t_user where login_name=? and login_pwd=?";
             stmt=conn.prepareStatement(sql);//此时会发送sql给DBMS,进行sql语句的编译
            //给占位符?传值
            //怎么解决sql注入的?即使用户信息中有sql关键字,但是不参加编译就没事。
            //stmt.setInt(1,100);//这样必须是填数字,↓下面那个必须填字符串。
            stmt.setString(1,loginName);//给第一个占位符传值
            stmt.setString(2,loginPwd);//给第二个占位符传值
            // 4、执行sql语句
            rs = stmt.executeQuery();//这个方法不需要将sql语句传递进去,不能是这样:rs = stmt.executeQuery(sql);因为上面已经把sql传过去了。
            if(rs.next()){//此条件如果成立,表示登录成功
                ok=true;
            }
            // 5、处理结果集
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            // 6、释放资源
            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();
                }
            }
        }

        return ok;
    }


    private static Map<String, String> initUI(){
        System.out.println("欢迎使用该系统,请输入用户名和密码进行身份认证");
        Scanner s=new Scanner(System.in);
        System.out.println("用户名:");
        String loginName=s.nextLine();
        System.out.println("密码:");
        String loginPwd=s.nextLine();
        //将用户名和密码放在map集合中
        Map<String,String> useLoginInfo=new HashMap<>();
        useLoginInfo.put("loginName",loginName);
        useLoginInfo.put("loginPwd",loginPwd);
        //返回map
        return useLoginInfo;

    }


}

Statement使用场景

//先使用PreparedStatement-

这个程序输入desc或者asc会出错,因为
select ename,sal from emp order by sal ?会被换成select ename,sal from emp order by sal 'desc’而不是select ename,sal from emp order by sal desc ,

PreparedStatement比较适合传值,Statement比较适合进行字符串的拼接。

京东升降序那不让用户输入,就是不给你注入的机会。

package jdbc;

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

/*
*需求:用户再控制台上输入desc则降序,输入asc则升序。
*思考以下,这个应该选择Statement还是PreparedStatement
选Statement,y因为PreparedStatement只能传值,不能进行sql语句的拼接。
 */
public class jdbc08 {
     public static void main(String[] args){
         Scanner s=new Scanner(System.in);
         System.out.print("请输入desc或asc[desc是表示降序,asc表示升序]:");
            //用户输入的
         String orderKey=s.next();
         //先使用PreparedStatement
         Connection conn = null;
         PreparedStatement ps = null;
         ResultSet rs = null;
         try {
             //1、注册驱动
             Class.forName("com.mysql.cj.jdbc.Driver");
             //2、获取连接
             conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/bjpowernode", "root", "123456");
             //3、获取预编译的数据库操作对象
             String sql="select ename,sal from emp order by sal ?";
             ps=conn.prepareStatement(sql);
             //给?传值
             ps.setString(1,orderKey);
             //4、执行sql语句
             rs=ps.executeQuery();
             while(rs.next()){
                 String ename=rs.getString("ename");
                 String sal=rs.getString("sal");
                 System.out.println(ename+","+sal);
             }


         } 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();
                 }
             }
         }


     }
}

//再使用statement
此时可以执行了

package jdbc;

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

/*
 *需求:用户再控制台上输入desc则降序,输入asc则升序。
 *思考以下,这个应该选择Statement还是PreparedStatement
 */
public class jdbc09 {
    public static void main(String[] args){
        Scanner s=new Scanner(System.in);
        System.out.print("请输入desc或asc[desc是表示降序,asc表示升序]:");
        //用户输入的
        String orderKey=s.next();
        //再使用Statement
        Connection conn = null;
        Statement stmt = null;
        ResultSet rs = null;
        try {
            //1、注册驱动
            Class.forName("com.mysql.cj.jdbc.Driver");
            //2、获取连接
            conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/bjpowernode", "root", "123456");
            //3、获取数据库操作对象
            stmt = conn.createStatement();
            //4、执行sql语句
            String sql="select ename,sal from emp order by sal "+orderKey;
            rs=stmt.executeQuery(sql);
            while(rs.next()){
                String ename=rs.getString("ename");
                String sal=rs.getString("sal");
                System.out.println(ename+","+sal);
            }


        } 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();
                }
            }
        }


    }
}

使用PreparedStatement完成增删改

package jdbc;

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

public class jdbc10 {
    public static void main(String[] args) {
        Connection conn=null;
        PreparedStatement ps=null;
        try {
            //1、注册驱动
            Class.forName("com.mysql.cj.jdbc.Driver");
            //2、获取连接
            conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/bjpowernode", "root", "123456");
            //3、获取预编译的数据库操作对象
           //增加操作
            /*String sql="insert into dept(deptno,dname,loc) values(?,?,?)";
            ps=conn.prepareStatement(sql);
            //给?传值
            ps.setInt(1,50);
            ps.setString(2,"销售部");
            ps.setString(3,"天津");*/

            //更新操作
          /*  String sql="update dept set dname=?,loc=? where deptno = ?";
            ps=conn.prepareStatement(sql);
            ps.setString(1,"软件研发部");
            ps.setString(2,"北京");
            ps.setInt(3,50);*/
           //删除操作
            String sql="delete from dept where deptno = ?";
            ps=conn.prepareStatement(sql);
            ps.setInt(1,50);
            // 4、执行sql
            int count=ps.executeUpdate();
            System.out.println(count);
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            //6、释放资源
            if(ps!=null){

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


    }
}

模糊查询

package jdbc;

import java.sql.*;

public class jdbc11 {
    public static void main(String[] args) {
        Connection conn=null;
        PreparedStatement ps=null;
        ResultSet rs=null;
        try {
            //1、注册驱动
            Class.forName("com.mysql.cj.jdbc.Driver");
            //2、获取连接
            conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/bjpowernode", "root", "123456");
            //3、获取预编译的数据库操作对象
            //找出名字中含有O的
            //以下第一种方法是错误的,因为?不能放在单引号内
            /*String sql="select ename from emp where ename like '%?%'";
            ps=conn.prepareStatement(sql);
            ps.setString(1, "O");*/
            String sql="select ename from emp where ename like ?";
            ps=conn.prepareStatement(sql);
            ps.setString(1, "%O%");
            // 4、执行sql
            rs=ps.executeQuery();
             while (rs.next()){
               System.out.println(rs.getString("ename"));
           }

        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            //6、释放资源
            if(ps!=null){

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


    }
}

JDBC事务

package jdbc;
/*
JDBC默认情况下对事务是怎么处理的?
 模拟一个银行账户转账,A账户向B账户转账10000元。
 从A账户减去10000,向B账户加上10000
 必须同时成功,或者同时失败

 转账需要执行两条update语句

 //jdbc默认执行自动提交:
       就是执行一条语句就提交一次语句。
   在实际开发中必须将jdbc的自动提交机制关闭掉,改为手动提交,
 当一个完整的事务结束之后,再提交。
  conn.setAutoCommit(false);关闭自动提交机制
  conn.commit();手动提交;
  conn,rollback();手动回滚;


 */

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

public class jdbc12 {
    public static void main(String[] args) {
        Connection conn=null;
        PreparedStatement ps=null;
        try {
            //1、注册驱动
            Class.forName("com.mysql.cj.jdbc.Driver");
            //2、获取连接
            conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/bjpowernode", "root", "123456");
            //拿到连接对象后立即开启事务。开启事务:将自动提交机制关闭掉
           //void setAutoCommit(boolen autoCommit) throws SQLException
            // 参数autoCommit为true表示启动自动提交模式,为false表示禁用自动提交模式
            conn.setAutoCommit(false);

            //3、获取预编译的数据库操作对象

            String sql=" update t_act set balance =? where actno= ?";
            ps=conn.prepareStatement(sql);
            //给?传值
            ps.setDouble(1,10000);
            ps.setString(2,"A");
            int count=ps.executeUpdate();
            //模拟异常(验证回滚)
            //String s=null;
            //s.toString();//空指针异常

            //给?传值
            ps.setDouble(1,10000);
            ps.setString(2,"B");
            count+=ps.executeUpdate();

            System.out.println(count==2?"转账成功":"转账失败");
            //代码能执行到此处,说明上面的代码没有出现任何异常,表示都成功了,手动提交
            //手动提交,事务结束。
             conn.commit();

        } catch (Exception e) {
            //出现异常的话,为了保险起见,这里要回滚!

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

            e.printStackTrace();
        }finally {
            //6、释放资源
            if(ps!=null){

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


    }
}


JDBC工具类的封装

外部文件

driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/bjpowernode
user=root
password=123456

封装类

package jdbc.utils;
//在一个没有结束的程序中,DBUtil这个类只加载一次

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

/*
数据库工具类,便于JDBC的代码编写
*/
public class DBUtil {
   //静态变量和静态代码块的执行时候是一样的,先出现的先执行
    //构造方法私有化是为了防止new对象,为什么要防止用对象?
    //因为工具类中的方法都是静态的,不需要new对象,直接用“类名.”的方式调用
    private DBUtil(){};//工具类的构造方法私有化的
    //类加载时绑定属性资源文件
    private static ResourceBundle bundle=ResourceBundle.getBundle("jdbcc");

    //保证注册驱动在类加载的时执行且只执行一次,则使用静态代码块
   static{
        try {
            Class.forName(bundle.getString("driver"));
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }


     //获得数据库连接对象
     public static Connection getConnection() throws SQLException {
       String url=bundle.getString("url");
       String user=bundle.getString("user");
       String password=bundle.getString("password");
       Connection conn=DriverManager.getConnection(url,user,password);
        return conn;
     }
    /**
     * 释放资源
     * conn 连接对象
     * stmt 数据库操作对象
     * rs 查询结果集
     */
    public static void close(Connection conn, Statement stmt,ResultSet rs){
          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();
              }
          }


      }




}

测试类

package jdbc;

import java.sql.*;

public class jdbc11 {
    public static void main(String[] args) {
        Connection conn=null;
        PreparedStatement ps=null;
        ResultSet rs=null;
        try {
            //1、注册驱动
            Class.forName("com.mysql.cj.jdbc.Driver");
            //2、获取连接
            conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/bjpowernode", "root", "123456");
            //3、获取预编译的数据库操作对象
            //找出名字中含有O的
            //以下第一种方法是错误的,因为?不能放在单引号内
            /*String sql="select ename from emp where ename like '%?%'";
            ps=conn.prepareStatement(sql);
            ps.setString(1, "O");*/
            String sql="select ename from emp where ename like ?";
            ps=conn.prepareStatement(sql);
            ps.setString(1, "%O%");
            // 4、执行sql
            rs=ps.executeQuery();
             while (rs.next()){
               System.out.println(rs.getString("ename"));
           }

        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            //6、释放资源
            if(ps!=null){

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


    }
}

行级锁for update(此知识点为sql语句知识)

关于DQL语句的悲观锁
对于一个DQL语句来说,末尾是可以添加这样一个关键字的:for update

select ename,sal from emp where job=‘MANAGER’ for update ;
以上sql语句的含义是:
在本次事务的执行过程中,job='MANAGER’的记录被查询,
这些记录在我查询的过程中,任何人,任何事务都不能对
这些记录进行修改操作,直到我当前事务结束。

这种机制被称为:行级锁机制(又叫做悲观锁!)

在mysql中是这样的,
当使用select…where…for updare…时,mysql进行row lock(行锁)还是table lock(表锁)只取决于是否能使用索引(例如主键,unique字段),能则为行锁,否则为表锁:
未查到数据则无锁,而使用’<>’,'like’等操作时,索引会失效,自然进行的是table lock。

所以慎用for update。

整个表锁住的时候会导致性能性能降低,谨慎使用。

使用for update的时候,最好是锁主键值,或者具有unique约束的字段,
锁别的字段可能会导致整个表锁住。

你可能感兴趣的:(JDBC,1024程序员节)