第30次文章:文本大對象+ORM

  • 2019 年 10 月 8 日
  • 筆記

本周主要介紹JDBC中的兩個文本大對象CLOB和BLOB,並根據前面在JDBC中編程的分析,封裝了一個連接數據庫和關閉流操作的工具類JDBCUtil。最後涉及了一點數據庫與程序設計對象之間的對應關係ORM。


一、文本大對象的操作

大字段有些特殊,不同的數據庫處理的方式不一樣,大字段的操作常常是以流的方式來處理的。而非一般的字段,一次即可讀出數據。

1、CLOB(Character Large Object)

(1)基本概念

-用於存儲大量的文本數據

(2)Mysql中相關類型

-TINYTEXT最大長度為255(2^[8]-1)字符的TEXT列

-TEXT[(M)]最大長度為65535(2^[16]-1)字符的TEXT列。

-MEDIUMTEXT最大長度為16777215(2^[24]-1)字符的TEXT列。

-LONGTEXT最大長度為4294967295或4GB(2^[32]-1)字符的TEXT列。

2、BOLB(Binary Large Object)

(1)基本概念

-同於存儲大量的二進制數據

(2)Mysql中相關類型

-TINYBLOB最大長度為255(2^[8]-1)字符的BLOB列

-BLOB[(M)]最大長度為65535(2^[16]-1)字符的BLOB列。

-MEDIUMBLOB最大長度為16777215(2^[24]-1)字符的BLOB列。

-LONGBLOB最大長度為4294967295或4GB(2^[32]-1)字符的BLOB列。

3、兩者的操作流程

CLOB和BLOB兩者的主要區別就在於文本數據的字符流和二進制數據的位元組流之間的區別。所以我們只對其中CLOB進行演示就好啦~BLOB與之類似。

為了我們插入文本大對象,我們在表格設計的過程中,再增加一項myInfo屬性,數據類型為「text」,主要用於接收來自外部的CLOB對象。

具體實現如下:

import com.mysql.jdbc.Connection;  /**   * 測試時CLOB 文本大對象的使用   * 包含:將字符串、文件內容插入數據庫中的CLOB字段、將CLOB字段值取出來的操作。   */  public class Demo09 {      public static void main(String[] args) {      Connection conn = null;      PreparedStatement ps = null;      ResultSet rs = null;      Reader r = null;      try {        //加載驅動類        Class.forName("com.mysql.jdbc.Driver");        conn = (Connection) DriverManager.getConnection("jdbc:mysql://localhost:3306/testjdbc", "root", "123456");          //插入操作  //      ps = conn.prepareStatement("insert into t_user (username,myInfo) values (?,?)");  //      ps.setString(1, "peng1");  //      ps.setClob(2, new FileReader(new File("G:\java學習\test\merge.txt")));//通過傳輸文本文件的方式  //      ps.setClob(2, new BufferedReader(new InputStreamReader(new ByteArrayInputStream("hello world".getBytes()) )));//直接傳入字符串的方式          //取出操作        String sql = "select * from t_user where id=?";        ps = conn.prepareStatement(sql);        ps.setObject(1, 8012);          rs = ps.executeQuery();        while(rs.next()) {          Clob c= rs.getClob("myInfo");          r = c.getCharacterStream();          int temp = 0;          while((temp = r.read()) != -1) {            System.out.print((char)temp);          }        }      } catch (ClassNotFoundException e) {        e.printStackTrace();      } catch (SQLException e) {        e.printStackTrace();      } catch (Exception e) {        e.printStackTrace();      }finally {        try {          if(r != null) {            r.close();          }        } catch (Exception e) {          e.printStackTrace();        }        try {          if(rs != null) {            rs.close();          }        } catch (SQLException e) {          e.printStackTrace();        }        try {          if(ps != null) {            ps.close();          }        } catch (SQLException e) {          e.printStackTrace();        }        try {          if(conn != null) {            conn.close();          }        } catch (SQLException e) {          e.printStackTrace();        }      }    }  }

結果圖:

tips:

1.對比之前簡單的數據插入和取出操作,最大的差別就在於流處理。無論是輸入數據setClob和取出數據之後的輸出,我們都是按照之前學習的IO流的內容進行操作。其他的內容沒有什麼明顯的差別。

2.在插入操作過程中,我們給出了調用文本插入和普通的字符串插入兩種方式,都是基於流處理的操作,進行傳輸數據。

4、簡單封裝JDBCUtil工具包

在之前的所有的數據庫操作中,我們都會涉及到數據庫連接以及關閉流的操作,為了便於後續的操作,我們可以簡單的將其封裝為一個工具包。

package com.peng.jdbc;    import java.io.IOException;  import java.sql.DriverManager;  import java.sql.ResultSet;  import java.sql.SQLException;  import java.sql.Statement;  import java.util.Properties;    import com.mysql.jdbc.Connection;  /**   * 測試JDBC工具類   */  public class JDBCUtil {    static Properties pros ;    /**     * 加載配置文件     */    static {      pros = new Properties();      try {  pros.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("db.properties"));      } catch (IOException e) {        e.printStackTrace();      }    }      /**     * 加載數據庫     * @return     */    public static Connection getConnetion(){      try {        Class.forName(pros.getProperty("mysqlDriver"));        return (Connection) DriverManager.getConnection(pros.getProperty("mysqlURL"),            pros.getProperty("mysqlUser"), pros.getProperty("mysqlPwd"));      } catch (Exception e) {        e.printStackTrace();        return null;      }    }      /**     * 關閉流     * @param rs     * @param ps     * @param conn     */    public static void close(ResultSet rs,Statement ps,Connection conn) {      try {        if(rs != null) {          rs.close();        }      } catch (SQLException e) {        e.printStackTrace();      }      try {        if(ps != null) {          ps.close();        }      } catch (SQLException e) {        e.printStackTrace();      }      try {        if(conn != null) {          conn.close();        }      } catch (SQLException e) {        e.printStackTrace();      }    }  }

tips:在實際的使用過程中,我們一般將自己的數據庫用戶名以及密碼寫入一個配置文件properties中,在實際使用的這些信息的時候,直接從配置文件中調用就會更加方便和安全。

簡單的測試一下我們封裝的工具類:

import com.mysql.jdbc.Connection;  /**   * 測試JDBCUtil工具類   */  public class Demo11 {      public static void main(String[] args) {      Connection conn = null;      PreparedStatement ps = null;      ResultSet rs = null;;      try {        //加載驅動類        conn = JDBCUtil.getConnetion();        System.out.println("建立連接成功!");      } catch (Exception e) {        e.printStackTrace();      }finally {        JDBCUtil.close(rs, ps, conn);      }    }  }

查看一下結果:

二、ORM(Object Relationship Mapping)基本思想

1、ORM的基本思想

(1)表結構和類結構對應:表中字段和類的屬性對應;表中記錄和對象對應;

(2)讓Javabean的屬性名與類型盡量與數據庫保持一致!

(3)一條記錄對應一個對象。將查詢到的對象放到容器中(List,Set,Map)

2、封裝的常見思路

在數據庫與表結構的對應過程中,我們一般有如下幾種封裝思路:

(1)將表中的一條記錄封裝到Object數組中

(2)將表中的一條記錄封裝到map中

(3)將表中的一條記錄封裝到javabean對象中

在封裝每一條記錄之後,我們可以將每一條記錄作為一個整體,然後重新將每條記錄存放在容器中,如此便形成了一個容器與表結構的一一對應關係。下面我們以將每條記錄封裝在Javabean中為例,進行簡單了解。

/**   * 使用JavaBean來封裝一條記錄   * 使用list<JavaBean>存儲多條記錄   */  public class Demo03 {      /**     * 僅封裝一條記錄     */    public static void test01() {      Connection conn = null;      PreparedStatement ps = null;      ResultSet rs = null;      Emp emp = new Emp();      try {        conn = JDBCUtil.getConnetion();        String sql = "select empname,salary,age from emp where id=?";        ps = conn.prepareStatement(sql);        ps.setObject(1, 1);        rs = ps.executeQuery();        while(rs.next()) {          emp = new Emp(rs.getString("empname"),rs.getDouble("salary"),rs.getInt("age"));        }      } catch (SQLException e) {        e.printStackTrace();      } finally {        JDBCUtil.close(rs, ps, conn);      }      //一個emp對應一條記錄      System.out.println(emp.getEmpname()+"-"+emp.getSalary()+"-"+emp.getAge());    }      /**     * 在list中封裝多條記錄,每個Javabean代表一條記錄     */    public static void test02() {      Connection conn = null;      PreparedStatement ps = null;      ResultSet rs = null;      List<Emp> list = new ArrayList<Emp>();      try {        conn = JDBCUtil.getConnetion();        String sql = "select empname,salary,age from emp where id>?";        ps = conn.prepareStatement(sql);        ps.setObject(1, 1);        rs = ps.executeQuery();        while(rs.next()) {          Emp emp = new Emp(rs.getString("empname"),rs.getDouble("salary"),rs.getInt("age"));          list.add(emp);//使用鏈表存放多條記錄        }      } catch (SQLException e) {        e.printStackTrace();      } finally {        JDBCUtil.close(rs, ps, conn);      }        //list對應整張表,一個Javabean對應一條記錄      for(Emp temp:list) {        System.out.println(temp.getEmpname()+"-"+temp.getSalary()+"-"+temp.getAge());      }    }      /**     * 在Map中封裝多條記錄,每個Javabean代表一條記錄     */    public static void test03() {      Connection conn = null;      PreparedStatement ps = null;      ResultSet rs = null;      Map<String,Emp> map = new HashMap<String,Emp>();      try {        conn = JDBCUtil.getConnetion();        String sql = "select empname,salary,age from emp where id>?";        ps = conn.prepareStatement(sql);        ps.setObject(1, 1);        rs = ps.executeQuery();        while(rs.next()) {          Emp emp = new Emp(rs.getString("empname"),rs.getDouble("salary"),rs.getInt("age"));          map.put(rs.getString("empname"),emp);//使用鏈表存放多條記錄        }      } catch (SQLException e) {        e.printStackTrace();      } finally {        JDBCUtil.close(rs, ps, conn);      }      //map對應整張表,一個Javabean對應一條記錄      for(String empName:map.keySet()) {        System.out.println(map.get(empName).getEmpname()+"-"+map.get(empName).getSalary()+"-"+map.get(empName).getAge());      }    }      public static void main(String[] args) {      test01();      System.out.println("##################");      test02();      System.out.println("##################");      test03();    }  }

結果:

tips:

在整個程序開始之前,我們先創建一個Emp類(屬於Javabean類),用於後續每條記錄的存儲。

1.在test01中,我們以id作為索引目標,僅篩選出一條記錄,利用Emp的帶參構造器,直接在創建新的對象的時候,將我們需要存儲的參數傳遞進去。在輸出的時候即可根據Emp內部屬性的set和get方法獲取相關的值,然後進行調用。

2.在test02中,直接利用list的add方法,將多條記錄封裝到了list中;在test03中,使用map,以empname作為鍵,以emp對象作為值,進行存儲。

3、總結

在三種存儲方式中,一般都會選擇以Javabean的方式封裝每一條記錄。可以做到見名知意的效果,提高程序的閱讀性。ORM的基本思想是為了提供一個程序和數據庫表格的對應關係,深入理解每一條記錄在程序內部的存儲與封裝,對於我們的學習很有幫助。