JDBC---java语言连接数据库1

1、JDBC是什么?

Java DataBase Connectivity(Java语言连接数据库)

2、JDBC的本质是什么?

JDBC是SUN公司制定的一套接口(interface)
java.sql.*; (这个软件包下有很多接口。)
接口都有调用者和实现者。各大数据库管理系统厂家去实现这些接口,我们负责调用这些接口
面向接口调用、面向接口写实现类,这都属于面向接口编程。
为什么要面向接口编程?
解耦合:降低程序的耦合度,提高程序的扩展力。
多态机制就是非常典型的:面向抽象编程。(不要面向具体编程)
建议:
Animal a = new Cat();
Animal a = new Dog();
// 喂养的方法
public void feed(Animal a){ // 面向父类型编程。
}
不建议:
Dog d = new Dog();
Cat c = new Cat();

为什么SUN制定一套JDBC接口呢?
因为每一个数据库的底层实现原理都不一样。
Oracle数据库有自己的原理。
MySQL数据库也有自己的原理。
MS SqlServer数据库也有自己的原理。

每一个数据库产品都有自己独特的实现原理。

JDBC的本质到底是什么?
一套接口。

驱动,所有的数据库驱动都是以jar包的形式存在,jar包当中有很多class文件,这些class文件就是对JDBC接口的实现(数据库公司的Java程序员写的,下载驱动jar包需要去数据库官网下载)
驱动就是实现接口的类文件的一个别名
如果没有驱动,就是没有实现类,能编译不能运行,因为底层要new对象

在这里插入图片描述

3、JDBC编程六步

第一步:注册驱动(作用:告诉Java程序,即将要连接的是哪个品牌的数据库)

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

第三步:获取数据库操作对象(专门执行sql语句的对象)

第四步:执行SQL语句(DQL DML…)
DML:executeUpdate,返回值为int,指的是影响数据库内容的条数
DQL:executeQuery返回的是结果集ResultSet

第五步:处理查询结果集(只有当第四步执行的是select语句的时候,才有这第五步处理查询结果集。)
while(rs.next()){}
第六步:释放资源(使用完资源之后一定要关闭资源。Java和数据库属于进程间的通信,开启之后一定要关闭。)
在finally中操作,先判断是否等于空再进行操作,释放查询结果集,释放数据库操作对象,释放连接对象

url:统一资源定位符(网络中某个资源的绝对路径)
https://www.baidu.com/就是一个URL
URL包括哪几部分?
协议
IP
PORT
资源名

百度的ip地址ping出来的(ping www.baidu.com)

http://39.156.66.18:80/index.html
http://,通信协议
39.156.66.18 服务器IP地址
80 服务器上软件的端口,上网端口,
(IP是计算机的代号,端口是计算机上某个软件的代号)
以上内容是把本地计算机和百度服务器(计算机)通道打开了
index.html 服务器(计算机)上某个资源名,(要这个页面)

localhost和127.0.0.1都是本机IP地址

在这里插入图片描述
IDEA配置数据库驱动
就相当于配环境变量了
新建工程之后,新建模块,然后右键模块,F4,打开模块设置
点Libraries(库),加号,点Java

新建模块还要重新导入

JDBC六步

普通
遍历结果集

import java.sql.*;

public class Test01 {
    public static void main(String[] args) {
        Connection conn=null;
        Statement statement=null;
        ResultSet resultSet=null;//如果执行的是查询语句就有这个
        try {
            //第一步,注册驱动
            //Driver这个类有静态代码块
            //类加载Class.forName("com.mysql.jdbc.Driver");
            //因为参数是个字符串,字符串可以写在xxx.properties文件中(属性资源文件)

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


            //第一步,注册驱动

            //DriverManager.registerDriver(new com.mysql.jdbc.Driver());

            //第二步,获取链接
            String url="jdbc:mysql://127.0.0.1:3306/xrh";
            String user="root";
            String password="666";
            conn=DriverManager.getConnection(url,user,password);//面向接口编程,Connection是个接口

            //第三步,获取数据库操作对象(statement负责执行sql语句)
            statement=conn.createStatement();

//            //第四步,执行sql
//
//            String sql ="insert into dept (deptno,dname,loc) values('50','2bu','北京')";//插入数据
//            // String sql1 ="delete from dept where deptno=50";//删除数据
//            String sql2="update dept set dname='3bu',deptno=60 where deptno =50 ";//修改数据
//
//             int count=statement.executeUpdate(sql);
//            //int count1=statement.executeUpdate(sql1);
//            int count2=statement.executeUpdate(sql2);


            //第五步,处理查询结果集
            String sql0="select empno,ename,sal from emp";//列表也可以重命名
            resultSet=statement.executeQuery(sql0);//返回结果集,不是集合
            //遍历结果集
            while (resultSet.next()){
                //resultSet.getString()不管数据库中是什么类型的数据,取出来的都是字符串类型的
                //还有resultSet.getInt(),resultSet.getDouble()但是得看数据库中的数据类型
                
                String empno=resultSet.getString(1);//第1列
                String ename=resultSet.getString(2);
                String sal=resultSet.getString(3);
                System.out.println(empno+","+ename+","+sal);


                String empno1=resultSet.getString("empno");//用列名,数据库中的列名
                String ename1=resultSet.getString("ename");
                String sal1=resultSet.getString("sal");
                System.out.println(empno+","+ename+","+sal);
            }


        } catch (Exception e) {//本来是SQLException,因为类加载所以扩大了范围
            e.printStackTrace();
        }finally {

            //第六步,释放资源
            //为了保证资源一定释放,在finally语块中关闭资源
            //后开先关,因为上边大括号的statement,conn两个变量这里没法用,得挪到括号外边
            //分开try
            if(resultSet!=null){
                try {
                    resultSet.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
            if(statement!=null){
                try {
                    statement.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
            if(conn!=null){
                try {
                    statement.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
        }
    }
}

使用配置文件
这里没成功 ,因为.java程序和配置文件不在一个包下

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

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


        Statement statement=null;
        Connection connection=null;
        try {
           Class.forName(driver);

            connection=DriverManager.getConnection(url,user,password);

             statement=connection.createStatement();

            String sql="insert into dept (deptno,dname,loc) values('50','2bu','北京')";
            statement.executeUpdate(sql);

        } catch (Exception throwables) {
            throwables.printStackTrace();
        }finally {
            if(statement!=null){
                try {
                    statement.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }

            }
            if(connection!=null){
                try {
                    connection.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
        }

    }
}

用户登陆

import java.sql.*;

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

/*
实现功能:
    1,需求:
        模拟用户登录功能
    2,业务描述:
        程序运行时,提供一个输入的入口,输入用户名和密码
        java连接数据库验证是否合法,提示登陆失败或者成功
    3,数据准备:
         PowerDesigner设计表
    4,用户名: 
            sad
       密码: 
            asdd' or '1'='1
            登陆成功

        输入1=1,也会成功,叫sql注入现象,sql语句完成拼接,编译后运行,编译的时候将用户输入的非法信息编译进去了,导致原sql语句被扭曲
        sql注入现象:用户输入的信息中有sql的关键字,并且这些关键字参与sql语句编译,导致被扭曲,导致注入
 */
public class Test02 {
    public static void main(String[] args) {
        //初试化界面,初试化界面这个方法要有个返回值吧就是用户输入的

        Map<String,String> map=initUI();//这个方法返回的值是Map类型的

        boolean b=login(map);
        System.out.println(b?"登陆成功":"登陆失败");
    }
/*
用户登陆是否成功,jdbc
 */
    private static boolean login(Map<String, String> map) {
        //打标记的意识
        boolean loinSuccess=false;
        String u=map.get("用户名");
        String p=map.get("密码");

        Connection conn=null;
        Statement statement=null;
        ResultSet resultSet=null;

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

             conn= DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/xrh","root","666");

             statement=conn.createStatement();
             //数据变量拼接'xxx'-->把xxx删了,加两个双引号在中间加两个加号,在加号之间写变量就行了

             String sql="select * from t_user where loginName='"+u+"' and loginPwd='"+p+"'";
             resultSet= statement.executeQuery(sql);

             if(resultSet.next()){
                 //如果是true,登陆成功,因为上面sql查出来就一条,查不出来就没
                 loinSuccess=true;

             }




        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            if(resultSet!=null){
                try {
                    resultSet.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
            if(statement!=null){
                try {
                    resultSet.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
            if(conn!=null){
                try {
                    resultSet.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
        }

    return  loinSuccess;
    }

    private static Map<String, String> initUI() {
        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<>();
        map.put("用户名",username);
        map.put("密码",password);

        return map;
    }


}

上面存在SQL注入现象
sql注入现象:用户输入的信息中有sql的关键字,并且这些关键字参与sql语句编译,导致被扭曲,导致注入

解决SQL问题
只要用户提供的信息不参与SQL编译的过程

使用java.sql.PreparedStatement继承了java.sql.Statement接口,PreparedStatement原理:将SQL框架预编译,然后传值

import java.sql.*;

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


public class Test02 {
    public static void main(String[] args) {
        //初试化界面,初试化界面这个方法要有个返回值吧就是用户输入的

        Map<String,String> map=initUI();//这个方法返回的值是Map类型的

        boolean b=login(map);
        System.out.println(b?"登陆成功":"登陆失败");
    }
/*
用户登陆是否成功,jdbc
 */
    private static boolean login(Map<String, String> map) {
        //打标记的意识
        boolean loinSuccess=false;
        String u=map.get("用户名");
        String p=map.get("密码");

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

        try {
            //第一步,注册驱动
            Class.forName("com.mysql.jdbc.Driver");

            //第二步,获取连接
             conn= DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/xrh","root","666");

             //第三步,获取预编译的数据库操作对象
            String sql="select * from t_user where loginName=? and loginPwd=? ";//sql是框架,?表示占位符,传值
             ps=conn.prepareStatement(sql);
             //给占位符传值(第一个问号下标是1)
            ps.setString(1,u);
            ps.setString(2,p);

            //第四步,执行sql
             resultSet= ps.executeQuery();

             //第五步,处理结果集
             if(resultSet.next()){
                 //如果是true,登陆成功,因为上面sql查出来就一条,查不出来就没
                 loinSuccess=true;

             }




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

    return  loinSuccess;
    }

    private static Map<String, String> initUI() {
        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<>();
        map.put("用户名",username);
        map.put("密码",password);

        return map;
    }
}

Statement和preStatement
在mysql里面,如果上一条语句跟下一条语句完全一样包括空格,第二次运行的时候就不用编译了。所以Statement执行一次sql编译一次,preStatement是传值之前就编译了,所以只需要编译一次就行。preStatement还会进行传值类型安全检查

只能用statement的时候,就是查询排序升序的时候

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Scanner;

public class StatementTest {
    public static void main(String[] args) {
        Scanner s =new Scanner(System.in);
        System.out.println("请输入desc或者asc: ");
        String keywords =s.nextLine();

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

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

            conn= DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/xrh","root","666");

            String sql="select ename,empno from emp order by ename ?";
            ps=conn.prepareStatement(sql);
            ps.setString(1,keywords);

            rs=ps.executeQuery();

            while (rs.next()){
                String ename =rs.getString("ename");
                String empno=rs.getString("empno");
                System.out.println(ename+" "+empno);
            }



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

    }
}

上面的例子是传值,因为输入的desc被当作字符串传进去了,所以语法错误
经过测试,删除多条数据时,连续写几条删除语句只执行最后一个删除语句,那么怎么同时删除多个数据呢????

如果是PreparedStatement,设置完问号的值,要进行ps.executeUpdate()这个执行sql,有几个这执行几次。Statement也是如此

import java.sql.*;


public class StatementTest {
    public static void main(String[] args) {


        //jdbc
        Connection conn = null;
        PreparedStatement ps = null;


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

            conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/xrh", "root", "666");

//            String sql = "insert into dept(deptno,dname,loc )values(?,?,?)";
//            ps = conn.prepareStatement(sql);
//            ps.setString(1, "112");
//            ps.setString(2, "rensh2ibu");
//            ps.setString(3, "bei2jng");

//String sql="update dept set deptno=? where deptno=?这样为什么不行

//            String sql="update dept set dname=?,loc=? where deptno=?";
//            ps=conn.prepareStatement(sql);
//            ps.setString(1,"110");
//            ps.setString(2,"shanghai");
//            ps.setInt(3,110);

//            String sql="delete from dept where deptno=?";
//            ps=conn.prepareStatement(sql);
//            ps.setInt(1,112);

            String sql1="delete from dept where deptno=?";
            ps=conn.prepareStatement(sql1);
            ps.setInt(1,110);

//            String sql2="delete from dept where deptno=?";
//            ps=conn.prepareStatement(sql2);
//            ps.setInt(1,60);


            int count = ps.executeUpdate();
            System.out.println(count);

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

        }
    }
}

JDBC事务自动提交

JDBC事务默认是自动提交的,执行一次DML语句就自动提交一次。

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
/*
重点三行代码:都是围绕conn的
    conn.setAutoCommit(false);
    conn.commit();
    conn.rollback();

 */

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

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

            conn= DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/xrh","root","666");


            conn.setAutoCommit(false);

            String sql="update t_act set balance=?where acount=?";
             ps =conn.prepareStatement(sql);
             ps.setDouble(1,10000);
             ps.setInt(2,111);
             ps.executeUpdate();

             ps.setDouble(1,10000);
             ps.setInt(2,222);
             ps.executeUpdate();

            conn.commit();
        } catch (Exception e) {
            if (conn != null) {
                try {
                    conn.rollback();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
            e.printStackTrace();
        }finally {
            if (ps != null) {
                try {
                    ps.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
            if (conn != null) {
                try {
                    conn.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
        }

    }
}

JDBC工具类

工具类构造方法一般是私有的,因为工具类的方法都是静态的,通过类名点方法名调用,不需要new对象,私有化之后就构造不了了

import java.sql.*;


public class JDBCS {
    private JDBCS(){}

    //静态代码块,在类加载时执行,只执行一次
    {
        try {
            Class.forName("com.mysql.jdbc.Driver");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
    //获取连接
    //返回连接对象
    public static Connection getConnection() throws SQLException {

            return DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/xrh","root","666");

    }

    //关闭
    public static  void  close(Connection con, Statement statement, ResultSet resultSet ){
        if (resultSet != null) {
            try {
                resultSet.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
        if (statement != null) {
            try {
                resultSet.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }if ( con!= null) {
            try {
                resultSet.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
    }
}

测试工具类,并进行模糊查询

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

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

        try {
            //获取连接
            con=JDBCS.getConnection();
            //String sql="select ename from emp where ename like '_?%'";//没有问号
            String sql="select ename from emp where ename like ?";
            ps=con.prepareStatement(sql);//编译
            ps.setString(1,"_A%");//第二个字母是A的

            rs=ps.executeQuery();

            while (rs.next()){
                System.out.println(rs.getString("ename"));
            }



        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            //释放资源
            JDBCS.close(con,ps,rs);//如果第三个参数没就传null
        }
    }
}

悲观锁和乐观锁

select 语句在后面加上for update,就被锁上了,在当前事务没有结束的时候这一行数据不能修改,这是行级锁也叫悲观锁

悲观锁:事务必须排队,数据锁住了,不允许并发
乐观锁:支持并发,事务不需要排队,只不过需要一个版本号

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值