热门标签 | HotTags
当前位置:  开发笔记 > 后端 > 正文

漫谈jdbc

本文可作为北京尚学堂jdbc课程的学习笔记;简介jdbc是什么东西?jdbc全称(JavaDatabaseConnectivityjava数据库连接)它是干什么的?至于它是干什么的,那就应了那句老话了,说来话长..很久很久之前,作为用户,我们有c,c++,java...各种语言,另一方面数据库领

本文可作为北京尚学堂jdbc课程的学习笔记; 简介 jdbc是什么东西? jdbc全称(Java Database Connectivity java数据库连接) 它是干什么的? 至于它是干什么的,那就应了那句老话了,说来话长.. 很久很久之前,作为用户,我们有c,c++,java...各种语言,另一方面数据库领

本文可作为北京尚学堂jdbc课程的学习笔记;

简介

jdbc是什么东西?
jdbc全称(Java Database Connectivity java数据库连接)
它是干什么的?
至于它是干什么的,那就应了那句老话了,说来话长..
很久很久之前,作为用户,我们有c,c++,java...各种语言,另一方面数据库领域Oracle,Mysql,DB2,SQLServer也是种类繁多。
为了方便我们用户的使用各大数据库厂商就就建立了自己的API,如下图
\
看上去还不错哦。
后来,我们还是觉得麻烦,虽然各个厂商有自己的API,但我Oracle和Myaql毕竟不一样呀!作为客户的我们,并不想学习那么多的API,怎么办?
再加一层呗!
\
至于odbc是微软出的一套东西,干的事情和jdbc一样,就是屏蔽各个数据库的不同!
看上面的图大家就应该明白,各个数据库厂商会开发自己的jdbc jar包。
至此,我们就不需要管各个数据库的差异问题了。(当然,各个数据库的sql语法还有些微的不同,再后来Hibernate出现了,这里我们先不谈)
我们只用了解一个统一的接口,就能方便的使用各个数据库。
\

编程步骤

LoadDriver

    Class.forName("com.mysql.jdbc.Driver");
    Class.forName("com.mysql.jdbc.Driver").newInstance();
    new com.mysql.jdbc.Driver();
三种方式都可以,不过我们经常采用第一种方式,三者有什么区别?
我们看这个例子
package load;

public class LoadTest {
    public static void main(String[] args) {
        try {
            Class.forName("load.Loaded");
            System.out.println("*******");
            Class.forName("load.Loaded").newInstance();
            System.out.println("*****");
            new Loaded();
        } catch (ClassNotFoundException |IllegalAccessException|InstantiationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

package load;

public class Loaded {
    static{
        System.out.println("i am static");
    }
    public Loaded(){
        System.out.println("i am constructed");
    }
}
运行结果:
i am static
*******
i am constructed
*****
i am constructed
大家应该明白了
Class.forName("***"); 会加载一个类,返回的结果是Class类型的,在加载过程中,会执行类中的静态语句块;
Class.forName("***").newInstance(); 它其实和new ***()是一样的,当然类只用加载一次,所以上面调用这行代码的时候没有显示i am static
new ***() 这个和上面那个的区别在于,这个方法可以传递参数,构造不同的类,但是上面的newInstance只能构造无参的对象;
在说的通俗一点,jvm要生成一个类
需要两步,加载与实例化!
第一个方式是加载,后面两个既加载,又实例化(当然,如果前面已经加载了,就不用再加载了)

另外,关于这部分源码基本的分析如com.mysql.jdbc.Driver中到底干了什么,我们后面再说,这里就不多讨论了。

获得Connection

DriverManager.getConnection(url,username,password);

三个参数的意思我就不多说了,这里需要我们注意的其实也就一个url,不过大家也不用死记硬背,知道有这么个东西就ok;

获得Statemment;

Statement st=con.creatStatemnent();

获得结果集;

首先我们得说明,这里的结果集是用ResultSet来组织的。
ResutSet rs=st.executeQuery("select * from admininfo");

遍历结果集:

while (rs.next()) {
System.out.println(rs.getString("Filedname"));
}
这里我得说明一点,即使你想取得数据集中的第一条数据,rs.next()这行也必须有。我们可以理解为,初始情况下resultset内部的"游标"在第一条数据前面,我们得next一下能找到下一条数据!

close

一个原则,后建立的对象先关闭。

最基本的jdbc

下面的代码,写的比较全,只有一个要求,背下来!不要说,先看看,以后再说,这是基础!应该全文默写!!

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class JDBC_Test2 {

    public static void main(String[] args) {
        
        Connection cOnn=null;
        Statement st=null;
        ResultSet rs=null;
        String url="jdbc:mysql://localhost:3306/webexample?useUnicode=true&characterEncoding=UTF-8";
        String userName="root";
        String passWord="";
        try {
            Class.forName("com.mysql.jdbc.Driver");
            cOnn=DriverManager.getConnection(url,userName,passWord);
            st=conn.createStatement();
            rs=st.executeQuery("select * from admininfo");
            while (rs.next()) {
                System.out.println(rs.getString("Aname"));
            }
            
            
        } catch (ClassNotFoundException e) {
            e.printStackTrace();           //log4j 具体记录
        }catch (SQLException e) {
            e.printStackTrace();
        }
        finally{
            try {
                if (rs!=null) {
                    rs.close();
                    rs=null;
                }
                if (st!=null) {
                    st.close();
                    st=null;
                }
                if (conn!=null) {
                    conn.close();
                    cOnn=null;
                }
                
            } catch (SQLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
}

几个知识点

PreparedStatement

其实Statement本身已经够用了,不过有点不方便,哪里不方便?
看下面的例子:
我想将一条数据插入到数据库中如下
            String name="董磊峰";
            int id=16;
            String sql="insert into admininfo (Aname,Aid) values('"+name+"',"+id+") ";
            st.executeUpdate(sql);
大家不觉得生成那个sql语句很麻烦吗?你少写一个'都有可能出错。
所以有了PreparedStatement,它也是一个接口,继承自Statement。
其用法为
            String name="董磊峰2";
            int id=18;
            String sql="insert into admininfo (Aname,Aid) values(?,?)";
            PreparedStatement st=conn.prepareStatement(sql);
            st.setString(1, name);         //给第一个栏位注入String型的数值name  这个不是从0开始
            st.setInt(2, id);
            st.execute();
用若干个?代替要插入的字符,比上面的sql清楚多了,不是吗?

批处理问题

如果我想执行多条sql语句怎么办?
使用Statement
            String name="董磊峰2";
            int id=154;
            int id2=487;
            String sql="insert into admininfo (Aname,Aid) values('"+name+"',"+id+") ";
            String sql2="insert into admininfo (Aname,Aid) values('"+name+"',"+id2+") ";
            System.out.println(sql);
            st=conn.createStatement();
            st.executeUpdate(sql);
            st.executeUpdate(sql2);
使用PretaredStatement
            String name="董磊峰2";
            int id=48;

            String sql="insert into admininfo (Aname,Aid) values(?,?)";
            System.out.println(sql);
            st=conn.prepareStatement(sql);
            st.setString(1, name);
            st.setInt(2, id);
            st.execute();
            
            st=conn.prepareStatement(sql);
            st.setString(1, name);
            st.setInt(2, id+1);
            st.execute();
似乎都不是太方便
看新的方法
使用Statement
            st=conn.createStatement();
            st.addBatch("insert into admininfo (Aname,Aid) values('"+name+"',"+id+") ");
            st.addBatch("insert into admininfo (Aname,Aid) values('"+name2+"',"+id2+") ");
            st.executeBatch();
使用PretaredStatement
            String sql="insert into admininfo (Aname,Aid) values(?,?)";
            System.out.println(sql);
            st=conn.prepareStatement(sql);
            st.setString(1, name);
            st.setInt(2, id);
            st.addBatch();
            
            st.setString(1, name+"ss");
            st.setInt(2, id+15);
            st.addBatch();

            st.executeBatch();
会用即可,这里不必深究。

Transaction

Transaction我们一般翻译成会话,就是一个不可分割的多条(或一条)sql语句,在一个Transaction中,这些sql语句要么全部执行成功,要么一个也不执行。
它有什么用?还用解释么?想想银行。
在jdbc中,默认一个sql语句就是一个transaction。
看看代码
            try{
                        conn.setAutoCommit(false);
            st=conn.createStatement();
            st.addBatch("insert into admininfo (Aname,Aid) values('"+name+"',"+id+") ");
            st.addBatch("insert into admininfo (Aname,Aid) values('"+name2+"',"+id2+") ");
            st.executeBatch();
            conn.commit();
            conn.setAutoCommit(true);    //用完了得改回去
            }catch(Exception e){
                if(conn!=null){
                conn.rollBack();          //sql代码撤销
                conn.setAutoCommit(true);  //还得改回去
                }
            }

可滚动的结果集

            String sql="select * from admininfo order by Aid";

            st=conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY);
            rs=st.executeQuery(sql);
            
        /*    admininfo 表内容
         *  Aid  Aname
            15  dlf
            16  董磊峰
            18  董磊峰2
            48  董磊峰2
            49  董磊峰2
            55  董磊峰2
            154  董磊峰2
            155  董磊峰2
            487  董磊峰2
            1599  董磊峰2ss
            2000  董磊峰2
            2015  董磊峰2ss
            3000  董磊峰2666
            8000  董磊峰2hhhh
            10001  wyf
            10002  zrk
            */
            rs.absolute(4);
            System.out.println("第4   "+ rs.getInt("Aid"));
            System.out.println("第几条   "+ rs.getRow());
            rs.first();
            System.out.println("第一个   "+ rs.getInt("Aid"));
            rs.last();
            System.out.println("最后一个   "+ rs.getInt("Aid"));
            System.out.println("总数   "+ rs.getRow());
            System.out.println("是否最后一个   "+ rs.isLast());
            System.out.println("最后结尾   "+ rs.isAfterLast());
            rs.next();
            System.out.println("最后结尾   "+ rs.isAfterLast());
结果
第4 48
第几条 4
第一个 15
最后一个 10002
总数 16
是否最后一个 true
最后结尾 false
最后结尾 true
看看这些方法的名字还有结果,大家应该能知道方法的作用,不过isAfterLast方法大家估计有点迷惑。
最后一个的后面?
这个方法是判断当前指针是否已经到文件尾,注意:文件尾和最后一条记录是不同的。

比如我们开始读取 ResultSet 时,指针位于文件头,首先需要 rs.next() 执行这个方法,指针移到第一条记录后才可以进行读取。到文件尾也是一样的,读到最后一条记录后,再继续读就到文件尾了,没有记录了,执行 isAfterLast() 方法就返回 true 了。

参考资料

http://blog.163.com/yutao_inx_319/blog/static/207234007201311177482930/ java,ResultSet 类中的isAfterLast()方法

http://www.cnblogs.com/shosky/archive/2011/07/22/2114290.html 三种类加载方式的区别


推荐阅读
  • 本文介绍了在开发Android新闻App时,搭建本地服务器的步骤。通过使用XAMPP软件,可以一键式搭建起开发环境,包括Apache、MySQL、PHP、PERL。在本地服务器上新建数据库和表,并设置相应的属性。最后,给出了创建new表的SQL语句。这个教程适合初学者参考。 ... [详细]
  • Oracle Database 10g许可授予信息及高级功能详解
    本文介绍了Oracle Database 10g许可授予信息及其中的高级功能,包括数据库优化数据包、SQL访问指导、SQL优化指导、SQL优化集和重组对象。同时提供了详细说明,指导用户在Oracle Database 10g中如何使用这些功能。 ... [详细]
  • 在说Hibernate映射前,我们先来了解下对象关系映射ORM。ORM的实现思想就是将关系数据库中表的数据映射成对象,以对象的形式展现。这样开发人员就可以把对数据库的操作转化为对 ... [详细]
  • 本文详细介绍了在ASP.NET中获取插入记录的ID的几种方法,包括使用SCOPE_IDENTITY()和IDENT_CURRENT()函数,以及通过ExecuteReader方法执行SQL语句获取ID的步骤。同时,还提供了使用这些方法的示例代码和注意事项。对于需要获取表中最后一个插入操作所产生的ID或马上使用刚插入的新记录ID的开发者来说,本文提供了一些有用的技巧和建议。 ... [详细]
  • ubuntu用sqoop将数据从hive导入mysql时,命令: ... [详细]
  • 延迟注入工具(python)的SQL脚本
    本文介绍了一个延迟注入工具(python)的SQL脚本,包括使用urllib2、time、socket、threading、requests等模块实现延迟注入的方法。该工具可以通过构造特定的URL来进行注入测试,并通过延迟时间来判断注入是否成功。 ... [详细]
  • 本文介绍了一个免费的asp.net控件,该控件具备数据显示、录入、更新、删除等功能。它比datagrid更易用、更实用,同时具备多种功能,例如属性设置、数据排序、字段类型格式化显示、密码字段支持、图像字段上传和生成缩略图等。此外,它还提供了数据验证、日期选择器、数字选择器等功能,以及防止注入攻击、非本页提交和自动分页技术等安全性和性能优化功能。最后,该控件还支持字段值合计和数据导出功能。总之,该控件功能强大且免费,适用于asp.net开发。 ... [详细]
  • REVERT权限切换的操作步骤和注意事项
    本文介绍了在SQL Server中进行REVERT权限切换的操作步骤和注意事项。首先登录到SQL Server,其中包括一个具有很小权限的普通用户和一个系统管理员角色中的成员。然后通过添加Windows登录到SQL Server,并将其添加到AdventureWorks数据库中的用户列表中。最后通过REVERT命令切换权限。在操作过程中需要注意的是,确保登录名和数据库名的正确性,并遵循安全措施,以防止权限泄露和数据损坏。 ... [详细]
  • 本文详细介绍了使用 SQL Load 和 Excel 的 Concatenate 功能将数据导入 ORACLE 数据库的方法和步骤,同时介绍了使用 PL/SQL tools 将数据导入临时表的方法。此外,还提供了一个转链接,可参考更多相关内容。摘要共计XXX字。 ... [详细]
  • GetWindowLong函数
    今天在看一个代码里头写了GetWindowLong(hwnd,0),我当时就有点费解,靠,上网搜索函数原型说明,死活找不到第 ... [详细]
  • EPICS Archiver Appliance存储waveform记录的尝试及资源需求分析
    本文介绍了EPICS Archiver Appliance存储waveform记录的尝试过程,并分析了其所需的资源容量。通过解决错误提示和调整内存大小,成功存储了波形数据。然后,讨论了储存环逐束团信号的意义,以及通过记录多圈的束团信号进行参数分析的可能性。波形数据的存储需求巨大,每天需要近250G,一年需要90T。然而,储存环逐束团信号具有重要意义,可以揭示出每个束团的纵向振荡频率和模式。 ... [详细]
  • 本文介绍了绕过WAF的XSS检测机制的方法,包括确定payload结构、测试和混淆。同时提出了一种构建XSS payload的方法,该payload与安全机制使用的正则表达式不匹配。通过清理用户输入、转义输出、使用文档对象模型(DOM)接收器和源、实施适当的跨域资源共享(CORS)策略和其他安全策略,可以有效阻止XSS漏洞。但是,WAF或自定义过滤器仍然被广泛使用来增加安全性。本文的方法可以绕过这种安全机制,构建与正则表达式不匹配的XSS payload。 ... [详细]
  • 背景应用安全领域,各类攻击长久以来都危害着互联网上的应用,在web应用安全风险中,各类注入、跨站等攻击仍然占据着较前的位置。WAF(Web应用防火墙)正是为防御和阻断这类攻击而存在 ... [详细]
  • 本文介绍了互联网思维中的三个段子,涵盖了餐饮行业、淘品牌和创业企业的案例。通过这些案例,探讨了互联网思维的九大分类和十九条法则。其中包括雕爷牛腩餐厅的成功经验,三只松鼠淘品牌的包装策略以及一家创业企业的销售额增长情况。这些案例展示了互联网思维在不同领域的应用和成功之道。 ... [详细]
  • 本文详细介绍了Mybatis中#与$的区别及其作用。#{}可以防止sql注入,拼装sql时会自动添加单引号,适用于单个简单类型的形参。${}则将拿到的值直接拼装进sql,可能会产生sql注入问题,需要手动添加单引号,适用于动态传入表名或字段名。#{}可以实现preparedStatement向占位符中设置值,自动进行类型转换,有效防止sql注入,提高系统安全性。 ... [详细]
author-avatar
卖砖头的小男孩
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有