zoukankan      html  css  js  c++  java
  • JDBC的复习

    什么是JDBC

    JDBC(Java DataBase Connectivity)就是Java数据库连接,说白了就是用Java语言来操作数据库。原来我们操作数据库是在控制台使用SQL语句来操作数据库,JDBC是用Java语言向数据库发送SQL语句。

    JDBC原理

    由SUN提供一套访问数据库的规范(就是一组接口),并提供连接数据库的协议标准,然后各个数据库厂商会遵循SUN的规范提供一套访问自己公司的数据库服务器的API出现。SUN提供的规范命名为JDBC,而各个厂商提供的,遵循了JDBC规范的,可以访问自己数据库的API被称之为驱动。

    JDBC是接口,而JDBC驱动才是接口的实现,没有驱动无法完成数据库连接!每个数据库厂商都有自己的驱动,用来连接自己公司的数据库。

    当然还有第三方公司专门为某一数据库提供驱动,这样的驱动往往不是开源免费的!

    JDBC核心类(接口)介绍

    JDBC中的核心类有:DriverManager、Connection、Statement,和ResultSet!

    1.DriverManger(驱动管理器)的作用有两个:

    • 注册驱动:这可以让JDBC知道要使用的是哪个驱动;
    • 获取Connection:如果可以获取到Connection,那么说明已经与数据库连接上了。

    2. Connection对象表示连接,与数据库的通讯都是通过这个对象展开的: 

    Connection最为重要的一个方法就是用来获取Statement对象;

    3. Statement是用来向数据库发送SQL语句的,这样数据库就会执行发送过来的SQL语句:

    • void executeUpdate(String sql):执行更新操作(insert、update、delete等);
    • ResultSet executeQuery(String sql):执行查询操作,数据库在执行查询后会把查询结果,查询结果就是ResultSet;

    4. ResultSet对象表示查询结果集,只有在执行查询操作后才会有结果集的产生。结果集是一个二维的表格,有行有列。操作结果集要学习移动ResultSet内部的“行光标”,以及获取当前行上的每一列上的数据:

    • boolean next():使“行光标”移动到下一行,并返回移动后的行是否存在;
    • XXX getXXX(int col):获取当前行指定列上的值,参数就是列数,列数从1开始,而不是0。

    开始使用

    mysql数据库的驱动jar包:mysql-connector-java-5.1.13-bin.jar;(注意:使用6.x的版本建议使用使用新的驱动名,6版本似乎与连接池不兼容)

    这里先不使用连接池,接下来会专门写一篇连接池的笔记

     初始化连接:

        private Connection conn=null;
        
        public void initConnection()throws Exception{
            Class.forName("com.mysql.jdbc.Driver");
            conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/数据库名","root","root");
        }

    关闭连接(其实ResultSet、Statement,以及Connection都需要关闭,我会在规范化代码的时候再说):

        public void closeConnection()throws Exception{
            conn.close();
        }

    在这里还需要介绍一个最常用的类:PreparedStatement

    它是Statement接口的子接口;

    强大之处:

    • 防SQL攻击;
    • 提高代码的可读性、可维护性;
    • 提高效率!

    如何得到PreparedStatement对象:

    1. 给出SQL语句!
    2. 调用Connection的PreparedStatement prepareStatement(String sql语句);
    3. 调用pstmt的setXxx()系列方法sql语句中的?(记得从1开始哦)赋值!
    4. 调用pstmt的executeUpdate()或executeQuery(),但它的方法都没有参数。

    我们再说说结果集的概念:

    结果集(ResultSet):通过查询语句返回的就是结果集。

    结果集特性:

    • 是否可滚动(是否可以移动游标)
    • 是否敏感(数据库中数据改变,结果集是否改变)
    • 是否可更新(是否允许通过改变结果集反向改变数据库,这一特性不推荐不常用)

    默认结果集不滚动、不敏感、不可更新(但是Mysql数据库返回的结果集默认是可滚动的,要注意)

    ResultSet表示结果集,它是一个二维的表格!ResultSet内部维护一个行光标(游标),ResultSet提供了一系列的方法来移动游标:

        void beforeFirst()://把光标放到第一行的前面,这也是光标默认的位置;
        void afterLast()://把光标放到最后一行的后面;
        boolean first()://把光标放到第一行的位置上,返回值表示调控光标是否成功;
        boolean last()://把光标放到最后一行的位置上;
        
        boolean isBeforeFirst()://当前光标位置是否在第一行前面;
        boolean isAfterLast()://当前光标位置是否在最后一行的后面;
        boolean isFirst()://当前光标位置是否在第一行上;
        boolean isLast()://当前光标位置是否在最后一行上;
        
        boolean previous()://把光标向上挪一行;
        boolean next()://把光标向下挪一行;
        boolean relative(int row)://相对位移,当row为正数时,表示向下移动row行,为负数时表示向上移动row行;
        boolean absolute(int row)://绝对位移,把光标移动到指定的行上;
        int getRow()://返回当前光标所有行。

    其中next()方法最为常用

    批处理

    批处理处理就是一次处理多条sql语句,不必要一句一句去发送sql语句,一次发送多条。

    批处理只针对更新(增、删、改)语句,批处理没有查询什么事儿!

    默认的批处理是关闭的,需要我们在配置连接的url中,配置参数(在上面我们还是将连接数据库的信息放在代码中,这种硬编码不灵活,接下来我们要使用properties文件来配置)

    dbconfig.properties(等使用连接池的时候,这些信息就可以配置到连接池的配置文件中):

    driverClassName=com.mysql.jdbc.Driver
    url=jdbc:mysql://localhost:3306数据库名
    username=root
    password=root

    这才是默认没有开启批处理的配置,接下来我们要加上这个参数

    加上这个参数后,就可以在Dao层开始使用批处理了

    可以多次调用Statement类的addBatch(String sql)方法,把需要执行的所有SQL语句添加到一个“批”中,然后调用Statement类的executeBatch()方法来执行当前“批”中的语句。

    •  void addBatch(String sql):添加一条语句到“批”中;
    •  int[] executeBatch():执行“批”中所有语句。返回值表示每条语句所影响的行数据;
    •  void clearBatch():清空“批”中的所有语句。

    这个JdbcUtil类,是自己编写的,随后给出

            con = JdbcUtils.getConnection();
                String sql = "insert into stu values(?,?,?,?)";
                pstmt = con.prepareStatement(sql);
                for(int i = 0; i < 10; i++) {
                    pstmt.setString(1, "S_10" + i);
                    pstmt.setString(2, "stu" + i);
                    pstmt.setInt(3, 20 + i);
                    pstmt.setString(4, i % 2 == 0 ? "male" : "female");
                    pstmt.addBatch();
                }
                pstmt.executeBatch();

    当执行了“批”之后,“批”中的SQL语句就会被清空!也就是说,连续两次调用executeBatch()相当于调用一次!因为第二次调用时,“批”中已经没有SQL语句了。

    还可以在执行“批”之前,调用Statement的clearBatch()方法来清空“批”!

    再附上一个较常用数据库的properties配置(这些配型也都可以配置到连接池的配置中):

    #mysql
    #url=jdbc:mysql://localhost:3306/mydb?useUnicode=true&characterEncoding=utf8&useServerPrepStmts=true&cachePrepStmts=true&prepStmtCacheSize=50&prepStmtCacheSqlLimit=300
    #driverClassName=com.mysql.jdbc.Driver
    
    #mssql
    #driverClassName=com.microsoft.jdbc.sqlserver.SQLServerDriver
    #url=jdbc:sqlserver://127.0.0.1:1433;DatabaseName=mydb
    
    #mssql jtds
    #driverClassName=net.sourceforge.jtds.jdbc.Driver
    #url=jdbc:jtds:sqlserver://127.0.0.1:1433;DatabaseName=mydb
    
    #orcale
    #driverClassName=oracle.jdbc.driver.OracleDriver
    #url=jdbc:oracle:thin:@localhost:1521:mydb
    
    #access
    #driverClassName=sun.jdbc.odbc.JdbcOdbcDriver
    #url=jdbc:odbc:driver={Microsoft Access Driver (*.mdb)};DBQ=mdb\mydb.mdb

    预处理

    我们每向服务器发送一条sql语句,服务器需要做的的工作:

    •  校验sql语句的语法!

    •  编译:一个与函数相似的东西!

    •  执行:调用函数

    现在连接的数据库几乎没有不支持预处理的

    每个pstmt都与一个sql模板绑定在一起,先把sql模板给数据库,数据库先进行校验,再进行编译。执行时只是把参数传递过去而已!

    若二次执行时,就不用再次校验语法,也不用再次编译!直接执行!

    时间类型

    数据库类型与java中类型的对应关系:

    数据库: java.sql.Date

    Java: java.sql.Time

     注意:

    领域对象(domain/model)中的所有属性不能出现java.sql包下的东西!即不能使用java.sql.Date;

    ResultSet#getDate()返回的是java.sql.Date()

    PreparedStatement#setDate(int, Date),其中第二个参数也是java.sql.Date

    java.sql包下给出三个与数据库相关的日期时间类型,分别是:

      Date:表示日期,只有年月日,没有时分秒。会丢失时间;

      Time:表示时间,只有时分秒,没有年月日。会丢失日期;

      Timestamp:表示时间戳,有年月日时分秒,以及毫秒。

    这三个类都是java.util.Date的子类。

    时间类型相互转换

    把数据库的三种时间类型赋给java.util.Date,基本不用转换,因为这是把子类对象给父类的引用,不需要转换。

    java.sql.Date date = …
    java.util.Date d = date;
    
    java.sql.Time time = …
    java.util.Date d = time;
    
    java.sql.Timestamp timestamp = …
    java.util.Date d = timestamp;

    当需要把java.util.Date转换成数据库的三种时间类型时,这就不能直接赋值了,这需要使用数据库三种时间类型的构造器。java.sql包下的Date、Time、TimeStamp三个类的构造器都需要一个long类型的参数,表示毫秒值。创建这三个类型的对象,只需要有毫秒值即可。我们知道java.util.Date有getTime()方法可以获取毫秒值,那么这个转换也就不是什么问题了。

    java.utl.Date d = new java.util.Date();
    java.sql.Date date = new java.sql.Date(d.getTime());//会丢失时分秒
    Time time = new Time(d.getTime());//会丢失年月日
    Timestamp timestamp = new Timestamp(d.getTime());

    大数据

    所谓大数据,就是大的字节数据,或大的字符数据。标准SQL中提供了如下类型来保存大数据类型 :

    类型

    长度

    tinyblob

    28--1B(256B)

    blob

    216-1B(64K)

    mediumblob

    224-1B(16M)

    longblob

    232-1B(4G)

    tinyclob

    28--1B(256B)

    clob

    216-1B(64K)

    mediumclob

    224-1B(16M)

    longclob

    232-1B(4G)

     

    但是,在mysql中没有提供tinyclob、clob、mediumclob、longclob四种类型,而是使用如下四种类型来处理文本大数据:

    类型

    长度

    tinytext

    28--1B(256B)

    text

    216-1B(64K)

    mediumtext

    224-1B(16M)

    longtext

    232-1B(4G)

    往数据库中添加大数据(二进制上传到数据库中,使用的是commons-iojar包中的IOUtil类,这个包还有一个常用的FileUtils文件操作类)

        public void fun1() throws Exception {
            /*
             * 1. 得到Connection
             * 2. 给出sql模板,创建pstmt
             * 3. 设置sql模板中的参数
             * 4. 调用pstmt的executeUpdate()执行
             */
            Connection con = JdbcUtils.getConnection();
            String sql = "insert into tab_bin values(?,?,?)";
            PreparedStatement pstmt = con.prepareStatement(sql);
            
            pstmt.setInt(1, 1);
            pstmt.setString(2, "a.mp3");
            /**
             * 需要得到Blob
             * 1. 我们有的是文件,目标是Blob
             * 2. 先把文件变成byte[]
             * 3. 再使用byte[]创建Blob
             */
            // 把文件转换成byte[]
            byte[] bytes = IOUtils.toByteArray(new FileInputStream("F:/a.mp3"));
            // 使用byte[]创建Blob
            Blob blob = new SerialBlob(bytes);
            // 设置参数
            pstmt.setBlob(3, blob);
            
            pstmt.executeUpdate();
        }

    IOUtil是commons-iojar包中的类,需要导入这个jar

    从数据库中读BLOB到硬盘:

    /**
         * 从数据库读取mp3
         * @throws SQLException 
         */
        @Test
        public void fun2() throws Exception {
            /*
             * 1. 创建Connection
             */
            Connection con = JdbcUtils.getConnection();
            /*
             * 2. 给出select语句模板,创建pstmt
             */
            String sql = "select * from tab_bin";
            PreparedStatement pstmt = con.prepareStatement(sql);
            
            /*
             * 3. pstmt执行查询,得到ResultSet
             */
            ResultSet rs = pstmt.executeQuery();
            
            /*
             * 4. 获取rs中名为data的列数据
             */
            if(rs.next()) {
                Blob blob = rs.getBlob("data");
                /*
                 * 把Blob变成硬盘上的文件!
                 */
                /*
                 * 1. 通过Blob得到输入流对象
                 * 2. 自己创建输出流对象
                 * 3. 把输入流的数据写入到输出流中
                 */
                InputStream in = blob.getBinaryStream();
                OutputStream out = new FileOutputStream("c:/lgfw.mp3");
                IOUtils.copy(in, out);
            }
        }

     

    还需要注意的是:

    MySQL有默认的数据包大小,需要我们修改它,不然就会报这个异常:

    com.mysql.jdbc.PacketTooBigException: Packet for query is too large (9802817 > 1048576). You can change this value on the server by setting the max_allowed_packet' variable.

    在my.ini中设置,在[mysqld]下添加max_allowed_packet=大小(字节为单位),例如:

  • 相关阅读:
    最大子数组问题(分治策略实现)
    Solving the Detached Many-to-Many Problem with the Entity Framework
    Working With Entity Framework Detached Objects
    Attaching detached POCO to EF DbContext
    如何获取qq空间最近访问人列表
    Health Monitoring in ASP.NET 2.0
    problem with displaying the markers on Google maps
    WebMatrix Database.Open… Close() and Dispose()
    Accessing and Updating Data in ASP.NET: Retrieving XML Data with XmlDataSource Control
    Create web setup project that has crystal reports and sql script run manually on client system
  • 原文地址:https://www.cnblogs.com/lz2017/p/7042859.html
Copyright © 2011-2022 走看看