JDBC 从入门到精通

本文详细介绍了JDBC的基础知识,包括驱动加载、连接建立和SQL执行。讨论了如何避免资源泄露,提出了一种通用的资源释放方法。接着讲解了SQL注入和批处理,强调了事务的ACID特性和不同隔离级别。最后,探讨了数据库连接池(如DBCP和C3P0)的重要性,展示了如何创建和使用连接池工具类,以及它们在项目中的应用。
摘要由CSDN通过智能技术生成

引入:   

先猜想一下  java程序如何和mysql建立连接:
        思路:可以用socket,需要遵循的是mysql协议。那么mysql又是如何规定发送的数据的格式和mysql返回的响应数据的格式呢?
        java程序通过mysql协议发送请求(内容以sql语句)给服务端,服务端按照mysql协议处理数据结果,
        java程序再解析协议,处理数据(这些过程mysql已经给我们提供了一些API)
         但是又出现了一个问题:不同的数据库的协议不同,那么API也不会不同,那我们的java程序就得重写去适配不同的数据库。
    
        此时sun公司指定了一套标准协议,所有支持java语言的数据库,必须支持java语言的一套协议:jdbc
        

JDBC:java database connectivity

        也就是数据库和java程序交互的一套标准API。
        但是这些API,大多都是接口,我们还必须实现?
        这些具体实现,都通过不同的数据库厂商自己来实现,也就是  数据库的驱动程序。
        所以虽然实现不同,但是都是相同的接口。
         驱动程序:  实现mysql协议的jar包
        
    所以jdbc的流程就清晰了:
        1.建立连接
        2.书写sql语句,mysql服务器发送sql语句
        3.mysql接收并按照sql语句来处理数据
        4.mysql服务器发送响应到客户端,客户端接收数据
        5.java程序按照业务逻辑,处理响应数据。
        6.释放资源。
        

        

测试框架:

    
    对public class 类名,的类名右键,Goto ——> Test ——>JUnit4(开源测试框架)
    里面的所有方法都可以单独运行。
    一旦添加过这个JUnit4框架,以后就直接在普通类中的 要运行的方法 添加注解:@Test


            

编写JDBC程序:

    
    1.向JVM注册驱动:注册的是具体的数据库开发厂商实现的Driver类对象
        DriverManager.registerDriver(new Driver());(这个Driver是mysql的)
        
    2.建立连接(数据库jdbc和java程序):
        String url="jdbc:mysql://localhost:3306/jdbc"
        url:要连接哪个数据库,格式: jdbc:mysql(主协议):[子协议(可有可无)] //localhost:3306(主机端口号)/test(数据库名称)(?参数名=参数值)
        String user="root"
        连接数据库的用户名
        String password="1234"
        密码
        Connection connection = DriverManager.getConnection(url,user,password)
        引用表示java和mysql服务器的连接。
        
    3.写sql语句,将请求发送给服务器。
        String sql ="insert into user(id,name,age) values(1,'zs',18)"
        
        Statement statement = connection.createStatement();
        //增/删/改(DML语句)的时候使用,返回值 int i 代表 本次操作所影响的行数。
        int i = statement.excuteUpdate(sql);
        
        //查(DQL语句)
        ResultSet resultSet = statement.executeQuery(sql);
        while(resultSet.next()){
            //查找数据表的属性值
            1.通过列名获取每个属性

            resultSet.getInt("id");
            resultSet.getString("name");
            2.通过列名的index索引来获取(index 从1 开始编号,表示列数)
            resultSet.getInt(1);
        }

        
    4.根据业务逻辑处理响应数据。
        if(i>0){
            sout("插入成功")
        }

    
    5.释放相关资源
        //如果只有增删改操作的话:
        statement.close();
        connection.close();

            

程序详解:

    1.驱动的加载:
         DriverManager.registerDriver(new Driver());
            
        查看mysql的源码发现,Driver类自己已经有了静态方法:Static { DriverManager.registerDriver(new Driver());}
        所以我们就不需要重复书写这句代码,只要确保这句代码在我们自己的程序执行之前执行就可以了。
        但是如何做呢?注意到 此代码是Driver类的静态代码块中的,又因为静态代码块在类加载的时候执行。
        那么有几种方式类加载:
            1.生成对象:DriverManager.registerDriver(new Driver());//需要导mysql.Driver包。
            2.Class.forName("com.mysql.jdbc.Driver") 全类名(推荐)
            3.放在程序的静态代码块中,statice{Class.forName("com.mysql.jdbc.Driver")}
            4.坑,不会加载静态代码块的方法:driver.class()
            如果我想要跨数据库来加载(不同的驱动都可以运行) : 通过配置文件

            
    
 2.建立连接
      方式一:
             设置好url,user,password
            Connection connection DriverManager.getConnection(url,user,password);     
            
    方式二:
            原url:String url="jdbc:mysql://localhost:3306/jdbc"

             灵活使用url(user/password通过参数给) :  String url="jdbc:mysql://localhost:3306/jdbc?user=root&password=****"
            如果默认IP地址是localhost、端口号是3306,则简写:String url="jdbc:mysql:///jbdc?...."
        
    方式三:
          配置文件:在 src 目录下new 一个配置文件(configure)。
                url="jdbc:mysql://localhost:3306/jdbc"
                user=""
                password=""
         在类中:
                把配置文件当Map<String,String>用
                Properties properties = new Properties();

                
                new FileInputStream("相对路径")
                那么相对路径是什么?sout(System.getProperty("user.dir"))
                相对路径会改动,如果启动服务器的话,所以行不通
                
                获取配置文件:
                法一:URL resouce = 类名.class.getClassLoader().getResource("配置文件名")

                     这个路径 是 相对于 src的路径(虽然其的路径是到了classes目录下,但是是把配置文件复制到classes目录下的)
                
                 法二:
                (通过反射拿到配置文件,放入输入流中)

                InputStream RS = 类名.class.getClassLoader().getResourceAsStream("配置文件名");
                    //加载配置文件

                    properties.load(RS);
                    //获取Driver的全类名:在配置文件中 : URL=com.mysql.jdbc.Driver
                    String url = properties.getProperty("URL");
                    //建立连接
                    Connection connection = DriverManager.getConnection(url,properties);


                    
    3.写sql语句,发送给服务器。
        1.获取statement对象
            Statement statement = connection.createStatement();
        
        2.ResultSet — 结果集(也是一种需要释放的资源)
            ResultSet resultSet = statement.executeQuery(sql);
            
            ResultSet 结果集 中会维护一个游标,用游标来指示表的具体行。
            遍历 ResultSet 结果集:
                先将游标向后移动一个位置,如果游标的当前位置是一个有效的位置(表内)就返回true
                (无效位置就是表的第一行数据之前和最后一行数据之后。)
            
            //开始的时候游标处在第一行数据之前的位置
            while(resultSet.next()){ //.next()结果返回true或false
                //遍历每一行,获取其每一个属性值
                //两种方式获取当前行的各个属性值
            1.通过列名获取(游标所指的行)
                int id = resultSet.getInt("id");
                String name = resultSet.getString("name");
                int age = resultSet.getInt("age");

                
            2.通过列的 index索引值 来获取(不太推荐,可读性差)
                index 从第一列开始编号.
                int id = resultSet.getInt(1);
                String name = resultSet.getString(2);
                int age = resultSet.getInt(3);

            }    
            游标的位置还可以通过API进行修改:
                resultSet.afterLast() ——将游标放在表中最后一行之后
                resultSet.BeforeFrist() ——将游标放在表中第一行之前
                absolute(int row) ——将游标放在指定行(从1开始),要注意遍历的时候,游标会先移动一位
            游标的前后数据判断:(返回的都是boolean类型)
                resultSet.next()/resultSet.previous()

一个注意点(注意区分):

                  
    //查询操作,返回的是一个结果集

    ResultSet resultSet = statement.executeQuery(sql);
    // 增 删 改   操作,返回的是一个修改了多少行的数值

    int i = statement.executeUpdate(sql);


3.根据业务逻辑处理响应
        1.引入 TestCase ,让测试框架根据我们的业务逻辑来判断测试成功与否
            TestCase.assertTrue(i > 0);(这里i是上面的修改数据表的行数)
            执行条件表达式如果为false,会直接抛出异常。
            
        2.测试框架中异常的处理:
            如果测试框架中,自己捕获了异常,那么测试框架就会忽略这个异常,继续执行。


4.释放资源
因为Statement/Connection/ResultSet  都继承了  AutoCloseable,所以他们的释放可以写一个方法来释放,而不用在主代码中写:if(st != null){st.close()}if(ct != null){ct.close()}....
            public static void release(Statement st,Result rs,Connection con){
                closeQuietly.st;
                closeQuietly.rs;
                closeQuietly.con;
            }
            private static void closeQuietly(AutoCloseable closeable){
                //因为Statement/Connection/ResultSet  都继承了  AutoCloseable

                if(closeable != null){
                    closeable.close();
                }
            }

      

发现上面的代码有很多重复的代码,自己创建一个工具类DBUtil:
public class DBUtil{
      1.注册驱动
        static {
             2.建立链接  
            //将全类名放入配置文件 class="com.mysql.jdbc.Driver"
         Properties properties = new Properties();
         InputStream configureStream = 类名.class.getClassLoader().getResourceAsStream("配置文件名.properties");
                
            //加载配置文件
                properties.load(configureStream);
            //从配置文件中拿东西
                Class.forName("com.mysql.jdbc.Driver")}
                
        2.public static Connection getConnection(){ //这里的Connection对象最好导java.sql.Co
  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值